Как использовать QMetaMethod с QObject::connect

У меня есть два экземпляра подклассов QObject и два экземпляра сигнала QMetaMethod в одном из объектов и слот в другом объекте. Я хочу соединить этот сигнал и слот друг с другом.

Я просмотрел файл qobject.h и обнаружил, что макросы SIGNAL() и SLOT() просто добавляют символ "1" или "2" в начало сигнатуры метода, поэтому похоже, что можно добавить то же самое символ начала строки, возвращаемый QMetaMethod::signature(), но этот подход зависит от некоторых недокументированных внутренних компонентов инструментария и может быть в любой момент нарушен новой версией Qt.

Кто-нибудь знает надежный способ подключения сигналов и слотов через их представление отражения QMetaMethod?

Отредактировано: я создал предложение в трекере вопросов Qt: https://bugreports.qt.io/browse/QTBUG-10637 Если кто-то также заинтересован в этой функции, вы можете проголосовать за этот билет там.

3 ответа

Решение

Похоже, нет способа заставить его работать, не полагаясь на внутреннюю реализацию. На вашем месте я бы отправил запрос на функцию отслеживания ошибок Qt, напишу код, имитирующий текущие макросы SIGNAL/SLOT, и добавлю модульный тест, который не пройдёт при изменении поведения SIGNAL/SLOT.

Там может быть более простое решение проблемы, которую вы пытаетесь решить: опишите, что именно вы пытаетесь сделать без каких-либо подробностей реализации.

Это было исправлено с Qt 4.8.0:

https://bugreports.qt.io/browse/QTBUG-10637

Предположим, у нас есть QObject * m_subject, и мы хотим подключить сигнал уведомления об изменении свойства к слоту propertyChanged():

const QMetaObject* meta = m_subject->metaObject();
QMetaProperty prop = meta->property(meta->indexOfProperty("myProperty"));
if (prop.hasNotifySignal()) {
    QMetaMethod signal = prop.notifySignal();
    QMetaMethod updateSlot = metaObject()->method(
        metaObject()->indexOfSlot("propertyChanged()"));
    connect(m_subject, signal, this, updateSlot);
}

Я успешно использовал это для создания подкласса QWidget, который находит все свойства любого QObject и создает QLineEdit для каждого из них с подключением для обновления QLineEdit при каждом изменении соответствующего свойства. (Поскольку я не нашел способа передать значение propertyID в propertyChanged(), однако, было необходимо создать подкласс QLineEdit и реализовать там свойство propertyChanged(). QSignalMapper не помогло, потому что все свойства находятся в одном и том же объект.)

Благодаря MBack я теперь использую метаметоды для динамического подключения моего представления к свойствам модели для шаблона MVVM или MVC. Чтобы соблюдать DRY, требуется шаблон с примерно таким:

 void myObject::myconnect(QObject* sender, std::string signalName, QObject* receiver, std::string slotName)
 {
    int sigIdx = sender->metaObject()->indexOfSignal(signalName.c_str());
    auto signal = sender->metaObject()->method(sigIdx);
    int slotIdx = receiver->metaObject()->indexOfSlot(slotName.c_str());
    auto slot = receiver->metaObject()->method(slotIdx);
    connect(sender,signal,receiver,slot);
 }

void Form_IVConfiguration::connectProperty(QObject* sender, std::string propName, QObject* receiver, std::string slotName)
{
   int sigIdx = sender->metaObject()->indexOfProperty(propName.c_str());
   auto signal = sender->metaObject()->property(sigIdx ).notifySignal();
   int slotIdx = receiver->metaObject()->indexOfSlot(slotName.c_str());
   auto slot = receiver->metaObject()->method(slotIdx);
   return connect(sender, signal, receiver, slot);
}

Если метод подписи общедоступен в QMetaMethod, то тролли не должны ломать результат, и его безопасно использовать (документация ничего не говорит о "опасностях" при использовании метода QMetaMethod::signature). Я думаю, что вы можете безопасно использовать его. Просто чтобы быть уверенным, какую версию Qt вы используете прямо сейчас?

Другие вопросы по тегам