Как использовать 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 вы используете прямо сейчас?