Russian Qt Forum
Ноябрь 27, 2024, 08:52 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Привязка скриптов к динамически загруженной форме  (Прочитано 4811 раз)
iRQSX
Гость
« : Август 07, 2010, 20:08 »

Есть такая вот задача... Можно конечно загрузить форму непосредственно из скрипра и пручною связать сигналы со слотами, но хотелось бы реализовать это иначе. Итак мысль такая:
1. загружаем форму
2. определяем какие на ней есть виджеты (QObjectList ui = myWidget->children()Подмигивающий
3. определяем какие сигналы есть у каждого виджета
4. связываем ВСЕ эти сигналы с ОДНИМ слотом
5. в слоте вычисляем какой послан сигнал
6. смотрим кто его послал
7. Запускаем соответствующий скрипт.
не могу понять как(да и можно ли вообще) реализовать пункты 3-5?



 
Записан
asvil
Гость
« Ответ #1 : Август 07, 2010, 20:37 »

ВСЕ с ОДНИМ слотом не получиться из-за несовместимости списков агрументов.

3. определяем какие сигналы есть у каждого виджета
4. связываем ВСЕ эти сигналы с ОДНИМ слотом
Код:
QObjectList children = parent.children();
QMetaMethod *metaMethod;
foreach (QObject *child, children) {
  for (int i = child.staticMetaObject.methodOffset(); i < child.staticMetaObject->methodCount(); ++i) {
    metaMethod = child.staticMetaObject.metaObject->method(i);
    if (metaMethod.methodType() == QMetaMethod::Signal) {
      connect(child, QString("%1%2").arg(QSIGNAL_CODE).arg(metaMethod.signature()).toLatin1().data()
              , this, SLOT(YOUR_SLOT));
    }
  }
}
5. в слоте вычисляем какой послан сигнал
Для сигналов с разными наборами параметров, нужно будет делать слоты с такими же наборами. Тем самым примерно знаем какой сигнал пришел.
« Последнее редактирование: Август 07, 2010, 22:11 от Филоненко Михаил » Записан
iRQSX
Гость
« Ответ #2 : Август 07, 2010, 22:31 »

Начал копать и вот...
Код
C++ (Qt)
foreach (QObject *child, ui) {
       qDebug()<<child->metaObject()->className();
       for (int i= child->metaObject()->methodOffset();i<child->metaObject()->methodCount();i++){
           QMetaMethod metaMethod = child->metaObject()->method(i);
           if (metaMethod.methodType()==QMetaMethod::Signal) {
           c = metaMethod.signature();
           qDebug()<<c;
           }
       }
   }
 
Вывод приложения:
Код:
QFormInternal::TranslationWatcher 
QHBoxLayout
QPushButton
QLabel
linkActivated(QString)
linkHovered(QString)

Заменяем везде metaObject()-> на staticMetaObject. и :
Код:
QObject 
destroyed(QObject*)
destroyed()
QObject
destroyed(QObject*)
destroyed()
QObject
destroyed(QObject*)
destroyed()
QObject
destroyed(QObject*)
destroyed()
Два вопроса : в чем разница metaObject()-> и staticMetaObject.
и где butoon.clicked?
по поводу того  в чем разница metaObject()-> и staticMetaObject.
я так понял при вызове staticMetaObject мы работаем со статическим методом QObject а вот при использовании metaObject как раз обращаемся к данному конкретному экземпляру класса?

Есть такое предположение что в случае кнопки сигнал clicked() не ищется из за того что он реализован в предке Qpushbutton - QAbstractButton...
« Последнее редактирование: Август 08, 2010, 00:41 от iRQSX » Записан
iRQSX
Гость
« Ответ #3 : Август 07, 2010, 23:58 »

Цитировать
Есть такое предположение что в случае кнопки сигнал clicked() не ищется из за того что он реализован в предке Qpushbutton - QAbstractButton...
разобрался... Весь цикл for надо выполнять в рекурсии еще и для qmetaobject->superclass что бы вычислить сигналы предков!
« Последнее редактирование: Август 11, 2010, 20:25 от iRQSX » Записан
iRQSX
Гость
« Ответ #4 : Август 11, 2010, 20:25 »

в итоге вот код:
Код
C++ (Qt)
void windowloader::loadUI(QString uifile){
   QUiLoader loader;
   QFile file(uifile);
   file.open(QFile::ReadOnly);
   QWidget *myWidget = loader.load(&file);
   file.close();
   myWidget->show();
   myWidget->children();
   QObjectList ui = myWidget->children();
   foreach (QObject *child, ui) {
#ifdef QT_DEBUG
       qDebug()<<child->metaObject()->className();
#endif
 
       QList<QMetaMethod>* mthl = mapMethods(child->metaObject());
       for (int i=0;i<mthl->count();i++){
#ifdef QT_DEBUG
           qDebug()<<mthl->value(i).signature();
#endif
 
           qDebug()<< this->connect(child, QString("%1%2").arg(QSIGNAL_CODE).arg(mthl->value(i).signature()).toLatin1().data()
                         ,  SLOT(attachslot()));
 
       }
   }
}
 
QList<QMetaMethod>* windowloader::mapMethods(const QMetaObject* mo,  QList<QMetaMethod>* mthl){
   if (mthl==0){
       mthl = new QList<QMetaMethod>();
   }
 
   QRegExp rx("*()");
   rx.setPatternSyntax(QRegExp::Wildcard);
 
   for (int i= mo->methodOffset();i<mo->methodCount();i++){
       QMetaMethod metaMethod = mo->method(i);
       if ((metaMethod.methodType()==QMetaMethod::Signal)
           && rx.exactMatch(metaMethod.signature())) {
           mthl->append(metaMethod);
       }
   }
   if (mo->superClass()){
       mapMethods(mo->superClass(),mthl);
   }
   return mthl;
 
}
 
void windowloader::attachslot(){
 
   qDebug()<<"work";
}
 
}

Connect происходит(возвращает true), но при клике на кнопку не попадает в attachslot()... Что то не так сделал?
Сам спросил - сам отвечаю. Оказалось, что после загрузки формы и привязки сигналов к слоту сам класс удалялся...
« Последнее редактирование: Август 14, 2010, 05:18 от iRQSX » Записан
iRQSX
Гость
« Ответ #5 : Август 14, 2010, 13:23 »

И все таки остается еще одна загвоздка... Так все таки можно ли как то узнать какой именно сигнал вызвал слот? обо без этого вся идея пропадает. По параметрам не вариант т.к. таким образом никак не отличить, например к кнопки, pressed() released() clicked() что само собой нехорошо...
Записан
asvil
Гость
« Ответ #6 : Август 15, 2010, 00:24 »

*Удалено*
« Последнее редактирование: Август 15, 2010, 00:26 от Филоненко Михаил » Записан
iRQSX
Гость
« Ответ #7 : Сентябрь 29, 2010, 01:14 »

В таком случае единственный рациональный вариант реализовывать свой слот для каждого сигнала, по это по моему слишком. Вообще вся заварушка для того что бы сам скрипт был максимально прост для написания, хотелось избежать команд типа connect и т.п.   Посмотрел пример QtScript Calculator и Бланшета, вобщем то в том же калькуляторе все сделано красиво, но в скрипте приходится заводить класс и реализовывать у него слоты, причем в виде
Код
C++ (Qt)
Calculator.prototype.clearAll = function()
вместо привычного
Код
C++ (Qt)
function clearAll ()
Что может быть непонятно для неподготовленного пользователя(а скрипт по хорошему должен смочь написать даже он). Может можно как то еще упростить синтаксис скрипта, а заодно избавиться от connect()?
Записан
Denjs
Гость
« Ответ #8 : Сентябрь 29, 2010, 12:53 »

ВСЕ с ОДНИМ слотом не получиться из-за несовместимости списков агрументов.
Можно подключать сигналы с "более длинной сигнатурой" к слотам с "менее длинной сигнатурой"
 - важно что бы начальные параметры, описанные в сигнатуре слота совпадали.
Если же слот с пустым списком параметров - то к нему можно подключить любой сигнал. вопрос только в том конечно нужны ли вам некоторые сигналы без параметров? кроме того и смешение событий в таком варианте - не самое хорошее что можно придумать.. имхо...

И все таки остается еще одна загвоздка... Так все таки можно ли как то узнать какой именно сигнал вызвал слот? обо без этого вся идея пропадает. По параметрам не вариант т.к. таким образом никак не отличить, например к кнопки, pressed() released() clicked() что само собой нехорошо...
>>Так все таки можно ли как то узнать какой именно сигнал вызвал слот?
Можно. Есть во первых класс QSignalMapper. Используйте его для "переиспускания" сигналов с дополнительной строковой "меткой".
Во вторых, не совсем конечно то что надо, но есть функция QObject* QObject::sender() доступная в слоте, но только если сигнал испущен не через квотед-коннектион.
« Последнее редактирование: Сентябрь 29, 2010, 12:58 от Denjs » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.188 секунд. Запросов: 21.