Как создать динамические сигналы и слоты в Qt?

Механизм сигнал / слот в Qt - статический механизм. Классы должны быть предварительно обработаны компилятором moc.
Теперь я хочу динамически создавать сигналы и слоты во время выполнения.
У меня уже есть рабочее решение, но оно мне кажется хакерским, хотя я с использованием общедоступных методов.
Это код для динамических слотов:

bool DynamicQObject::connectDynamicSlot(const QString &objectName, QObject *pSourceObject, QMetaMethod signalMethod)
{
    QByteArray slotName = signalMethod.name().prepend("on").append("(");
    QStringList parameters;
    for (int i = 0, j = signalMethod.parameterCount(); i < j; ++i)
    {
        parameters << QMetaType::typeName(signalMethod.parameterType(i));
    }
    slotName.append(parameters.join(",")).append(")");
    QByteArray theSignal = QMetaObject::normalizedSignature(signalMethod.methodSignature().constData());
    QByteArray theSlot = QMetaObject::normalizedSignature(slotName);
    if (!QMetaObject::checkConnectArgs(theSignal, theSlot))
    {
        return false;
    }

    int signalId = pSourceObject->metaObject()->indexOfSignal(theSignal);
    if (signalId < 0)
    {
        return false;
    }

    int slotId = slotIndices.value(theSlot, -1);
    if (slotId < 0)
    {
        slotId = slotList.size();
        slotIndices[theSlot] = slotId;
        slotList.append(createSlot(theSlot, objectName, signalMethod));
    }

    return QMetaObject::connect(pSourceObject, signalId, this, slotId + metaObject()->methodCount());
}

Как видите, я интенсивно использую QMetaObject и, в частности, индекс слотов (количество методов).
Код для динамических сигналов сопоставим.

Теперь мой вопрос: насколько перспективным является это решение, особенно потому, что я предполагаю, что индекс должен быть как минимум на единицу больше, чем methodCount ()?


person Kurt Pattyn    schedule 25.08.2013    source источник
comment
Я думаю, если вы объясните конкретный сценарий, в котором это полезно для вас, люди могут предложить вам лучшие альтернативы для его реализации.   -  person Mat    schedule 25.08.2013
comment
@Mat Вы правы, но я только хочу знать, пригодна ли эта реализация для будущего. Что касается сценария: я работаю над платформой pubsub, где события могут быть динамически интегрированы. Приведенный выше код: a.o. используется в клиенте socket.io C ++. В этой реализации можно выполнить следующее: socketIoObject.connect("customEvent", &socketIoObject, [=](Event e){ process event }   -  person Kurt Pattyn    schedule 25.08.2013
comment
Вы должны разделять архитектуру. Некоторое описание было бы лучше кода. Пока все, что я вижу, это то, что вы подключаетесь к несуществующему слоту, который существует только в вашем собственном списке в DynamicQObject. Что важно, так это то, как вы интегрируете это с оборудованием Metacall. Связывание событий с лямбдами или эмиссией событий может быть выполнено без необходимости в динамических сигналах / слотах. Вы ничего не получите, перепрофилировав QObject::connect. Для этого нужно просто создать свой метод, ИМХО.   -  person Kuba hasn't forgotten Monica    schedule 10.09.2013
comment
Вы можете прочитать эту статью Qt Quarterly 16. Он решает именно вашу проблему. Он все еще работает в Qt 5.   -  person Kuba hasn't forgotten Monica    schedule 10.01.2014


Ответы (2)


Теперь мой вопрос: насколько перспективным является это решение, особенно потому, что я предполагаю, что индекс должен быть как минимум на единицу больше, чем methodCount ()?

Он должен работать сейчас.

Что касается будущих доказательств ... может быть. Фрагмент использует неподдерживаемые функции, что означает, что они могут сломаться в любой момент в будущем. Вполне вероятно, что он продолжит работать.

person lpapp    schedule 07.09.2013

В качестве отдельного варианта, если все ваши объекты очень похожи по своей природе (например, вектор или что-то в этом роде), рассмотрите возможность подключения к лямбда-функции. например:

QObject::connect(iter->checkbox, &QCheckBox::stateChanged,
                [&, iter->startup_status](int new_val) {
                    if (new_val == Qt::CheckState::Checked) {
                        startup_status = true;
                    } else {
                        startup_status = false;
                    }
                });

где iter - структура / класс с общедоступными полями

QCheckBox *checkbox;
bool startup_status;

с помощью этого метода можно иметь переменное количество очень похожих слотов (которые на самом деле не слоты, но действуют как слоты)

person Catcow    schedule 21.05.2021