Здравствуйте. Есть проблема, которую пока никак не могу решить. Соединяю сигнал со слотом, высылаю сигнал - вызывается слот. Как узнать имя сигнала вызвавшего данный слот. Единственное что пока пришло в голову как то использовать класс QSignalSpy. Но как пока не знаю.
Такой вариант меня не очень устраивает так как мне необходимо идентифицировать стандартные сигналы qt. Например от кнопок и др элементов.
Посмотри в сторону: http://www.wiki.crossplatform.ru/index.php/Qt:%D0%94%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%B0%D1%86%D0%B8%D1%8F_4.3.2/qmetaobject#connectSlotsByName
Кажется это то, что тебе нужно. Кажется.
Посмотрел на описание connectSlotsByName ( QObject * object ) .
Этот метод выполняет связку всех сигналов объекта передаваемого в параметре и его дочерних объектов со слотами имена которых строятся по следующему принципу void on_<widget name>_<signal name>(<signal parameters>);
Вот только не очень ясно как это тут можно применить. Мне бы нужно просто имя сигнала в виде const char* узнать.
Или может я просто чего то не понимаю?
Объект пославший сигнал можно получить QObject::sender.
Но вот и правда как получить имя сигнала?
Конечная цель не дебажная следилка. Есть заказ на крупное клиент-серверное приложение в котором тысячи всевозможных элементов на формах в том числе нестандартных. На самом деле пытаемся разработать набор библиотек для создания клиент серверной технологии основанной на концепции MVC. Одно из условий наличие тонкового клиента. Так вот хочется максимально упростить написание клиентской части и так как там не предусматривается никакой логики разработку основной части клиента хочется перенести в qt designer. Суть в том что все необходимые для нас виджеты будут переопределены и будут привязаны своими свойствами к свойствам объектов описание которых находится во внешнем xml файле. Эти объекты динамически подгружаются сервером и во време работы происходит автоматическая синхронизация сервера с клиентом, что позволяет избавится от кучи лишней работы связанной с написанием клиента и предоставить ее дизайнеру. Так вот отправка запросов от клиента будет идти по сигналу от любого виджета на форме. Связка сигналов и необходимых групп свойств для запроса на изменении делается в дизайнере. Все эти сигналы планируется связать с одним слотом который будет выполнять парсинг созданных в дизайнере правок и отправки необходимых запросов серверу. Проблема в том чтобы определить от какого объекта и какой сигнал вызвал этот слот.. Причем проблему хоть как то извращенно но надо решить. Может у кого какие идеи есть?
Кстати если реализация будет успешной реализацию данной технологии выложим под GPL.
Ладно щас буду копать в сторону QSignalSpy.
единственное что приходит в гоолову это так как вы собираетесь переопределять виджеты
...
connect(this,SIGNAL(clicked()),this,SLOT(sendClicked()));// перенаправление стандартного сигнала
...
void sendClicked() {
emit sgClicked(параметр);//этот сигнал соединить со слотом обработчиком и оп параметру определять что за /////сигнал вызвал слот.
}
...
fantom, Если я правильно понял конечную цель, то предлагаю посмотреть на готовое решение: http://www.crossplatform.ru/node/522
Суть проста. На клиента ставится спецпрограмма Vedga-client, прога пишется одна для сервера, но не чистая Qt там в часности соединение сигналов идет другими функциями. написаное прложение запускается на сервере. А клиенты пользуются им с помощью Vedga-client.
Подробности по указанной ссылке, и ниже там смотри ссылку "Обсудить..."
Дальнейшее обсуждение связанное с Vedga перенес в существующую тему. http://www.forum.crossplatform.ru/index.php?showtopic=493&view=findpost&p=13564
По всей видимости стандартных путей нет.
Если хаком, то по всей видимости тебе нужно достучаться до класса QObjectPrivate, в нем есть структура Sender:
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
Q_DECLARE_PUBLIC(QObject)
public:
// ...
struct Sender
{
QObject *sender;
int signal;
int ref;
};
// object currently activating the object
Sender *currentSender;
//...
};
signal - это индекс сигнала, благодаря которому ты сможешь получить имя сигнала с помощью QMetaObject.class Q_CORE_EXPORT QObject
{
// ...
protected:
QObjectData *d_ptr;
// ...
};
ViGOur вы исходники какой версии qt смотрели? У меня 4.3.2 и в классе QObjectPrivate да и вообще нигде нет структуры Sender.
Блин, забыл что у вас 4.3.2, я смотрел 4.4.0. Сейчас гляну можно ли нахаляву хакнуть в 4.3.2.
да.
в 4.4 должно как то так работать
int signalId = (reinterpret_cast<QObjectPrivate*>(this->d_ptr))->currentSender->signal;
В вашей версии есть такой аргумент как QObjectPrivate::currentSenderSignalIdStart.
Гляньте в qtdir/src/corelib/kernel/qobject.cpp в методе bool QObject::event(QEvent *e) есть такой код:
case QEvent::MetaCall:
{
Q_D(QObject);
QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(e);
QObject *previousSender = d->currentSender;
int previousFrom = d->currentSenderSignalIdStart;
int previousTo = d->currentSenderSignalIdEnd;
d->currentSender = const_cast<QObject*>(mce->sender());
d->currentSenderSignalIdStart = mce->signalIdStart();
d->currentSenderSignalIdEnd = mce->signalIdEnd();
#if defined(QT_NO_EXCEPTIONS)
mce->placeMetaCall(this);
#else
try {
mce->placeMetaCall(this);
} catch (...) {
QReadLocker locker(QObjectPrivate::readWriteLock());
if (QObjectPrivate::isValidObject(this)) {
d->currentSender = previousSender;
d->currentSenderSignalIdStart = previousFrom;
d->currentSenderSignalIdEnd = previousTo;
}
throw;
}
#endif
QReadLocker locker(QObjectPrivate::readWriteLock());
if (QObjectPrivate::isValidObject(this)) {
d->currentSender = previousSender;
d->currentSenderSignalIdStart = previousFrom;
d->currentSenderSignalIdEnd = previousTo;
}
break;
}
А вот какзацепиться за currentSenderSignalIdStart, нужно думать...
Кстати а как получить имя сигнала по индексу? Вроде хак по крайней мере на 4.4.2 прокатил.
Или как получить список всех сигналов объекта?
Ну судя по metaObject()->indexOfSignal обращение через QObjectPrivate работает верно..
Но все же как получить список сигналов как это делает qt designer?
for( int i = 0; i < this->metaObject()->methodCount(); ++i)
{
QMetaMethod mm = this->metaObject()->method( i);
const char *p = mm.signature();
}
Точно! Спасибо все работает.
for( int i = 0; i < this->metaObject()->methodCount(); ++i)
{
QMetaMethod mm = this->metaObject()->method( i);
const char *p = mm.signature();
if (mm.methodType() == QMetaMethod::Signal)
qDebug() << p;
}
#include "qobject_p.h"
void Test::testSlot()
{
QObjectPrivate* sh = reinterpret_cast<QObjectPrivate*>(this->d_ptr);
int idSignal = sh->currentSender->signal;
for( int i = 0; i < this->metaObject()->methodCount(); ++i)
{
QMetaMethod mm = this->metaObject()->method( i);
const char *p = mm.signature();
if (mm.methodType() == QMetaMethod::Signal)
{
if (idSignal == metaObject()->indexOfSignal(p))
qDebug() << "Name of Signal" << p;
}
}
}
#include "qobject_p.h"
void Test::testSlot()
{
QObjectPrivate* sh = reinterpret_cast<QObjectPrivate*>(this->d_ptr);
int idSignal = sh->currentSender->signal;
QMetaMethod mm = this->metaObject()->method( idSignal);
const char *p = mm.signature();
if (mm.methodType() == QMetaMethod::Signal)
{
qDebug() << "Name of Signal" << p;
}
}
Обсуждение связанное с Vedga перенес в существующую тему. http://www.forum.crossplatform.ru/index.php?showtopic=493&view=findpost&p=13564
#include "private/qobject_p.h" //у меня только так захотел находить заголовок
...
qint32 idSignal = ((QObjectPrivate*)d_ptr)->currentSender->signal;
class Q_Object: public QObject
{
Q_OBJECT
public:
using QObject::d_ptr;
};
class Q_Object: public QObject
{
Q_OBJECT
public:
using QObject::d_ptr;
};
Ну чтобы не вылезло можешь в каждом своем наследнике от QObject писать
public:
using QObject::d_ptr;
public:
using QObject::d_ptr;
emit sig_btn_clicked(sender(), "clicked");
SABROG ты сам запутался и меня запутал. короче никаких using и наследований использывать не надо. Вот так все работает.
void Test::testSlot()
{
QObjectPrivate* sh = reinterpret_cast<QObjectPrivate*>(this->d_ptr);
int idSignal = sh->currentSender->signal;
QMetaMethod mm = (sender())->metaObject()->method( idSignal );
const char *p = mm.signature();
qDebug() << "Name of Signal" << p;
}
ну теперь, по идее, должно все работать.
Что-то помоему как-то всё через чур сложно. Может по другому прощее будет?
Например:
1. В дизайнере создаётся интерфейс (UI форма).
2. Для виджетов, сигналы которых нужно транслировать добавляется динамическое свойство с именами сигналов.
3. "Лёгкий клиент" грузит ui-шку (QUiLoader), пробегается по всем её виджетикам, и для тех у кого есть соответственное динамическое свойство создаёт нужные конекты в которых вся нужная инфа и отфудболивается на сервак.
И не нужно никаких хаков Qt.
Кроме того, покуда не изменились имена можно безболезненно менять интерфейс.
Так же клиент полностью не зависит от UI, т.е. его вообще не нужно перекомпилять при добавлении новой формочки.
QObject - не обязательно виджет. QTimer например.
Мое дело предупредить, а уж кто как захочет ваше дело. Я пытаюсь мыслить глобально.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)