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

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

Страниц: [1] 2 3 ... 6   Вниз
  Печать  
Автор Тема: Как преобразовать указатель на QObject в указатель на объект нужного класса?  (Прочитано 57269 раз)
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« : Октябрь 08, 2008, 23:36 »

Здравствуйте!


Сделал себе искалку объектов по имени. С надеждой, что имея её, я всегда смогу достучаться до нужного объекта, и вызвать у этого объекта нужный метод.

Искалка реализована так. Имеется глобальная переменная (знаю что не хорошо, но пока так), которая хранит указатель на виджет основного окна. Это стартовая точка поиска. Далее рекурсивно просматриваются children для поиска нужного объекта по имени.

Код:
QObject *mainwindowpointer;

QObject *find_object_recurse(QObject *pobj,QString n)
{
 QObjectList olist;

 olist=pobj->children();

 for(int i=0;i<olist.size();++i)
  {
   QObject *currobj;
   currobj=olist.at(i);

   qDebug() << "Object " << currobj->objectName();

   if(n==currobj->objectName()) return currobj;
   else return find_object_recurse(currobj,n);
  }

 return NULL;
}

QObject *find_object(QString n)
{
 qDebug() << "Find object " << n << "...";

 QObject *findobj;

 findobj=find_object_recurse(mainwindowpointer,n); // Вызывается рекурсивный поиск

 if(findobj==NULL)
  {
   qDebug() << "Try find unavaiable object " << n;
   exit(1);
  }
 else
  return findobj;
}


Инициализация начальной точки просходит очень просто:

Код:
int main(int argc, char ** argv)
{
 QApplication app( argc, argv );

 mainwindow win; // класс mainwindow - это виджет основного окна
 mainwindowpointer=&win; // инициализация стартовой точки поиска объектов

 win.show();

 return app.exec();
}


Чтобы узнать указатель на объект, теперь можно из любой части программы вызвать функцию

Код:
find_object("objectname")

и эта функция вернет указатель на найденый объект (если ему, конечно, было задано имя через setObjectName() ). Дело осложняется тем, что указатель этот будет типа (QObject *). А для того, чтобы вызвать метод объекта, надо иметь указатель того типа, которым объект объявлен.

И вот тут я дальше не знаю что делать. Пробовал делать по-всякому явное преобразование типов, ну например

Код:
(editor)find_object("editorinstance")

но тогда не идет компиляция, пишет что "некорректное преобразование из 'QObject*' в 'QWidget*'". По-всякому пробовал - результата не получил.


Вопрос. Есть ли воможность в Qt преобразовывать указатели на QObject в тип того объекта, на который этот же указатель и показывает? Как это сделать? Если никак, то каким методом можно решить задачу поиска объекта и получения на него указателя, с последующим использованием этого указателя для доступа к методам объекта?
« Последнее редактирование: Октябрь 09, 2008, 20:25 от xintrea » Записан

Собираю информацию по крупицам
http://webhamster.ru
Rcus
Гость
« Ответ #1 : Октябрь 09, 2008, 00:28 »

Все это уже есть в QT, даже глобальный указатель (правда не на главное окно, а на QCoreApplication(QApplication для программ с гуем), таким образом если немного изменить main
Код:
int main(int argc, char ** argv)
{
 QApplication app( argc, argv );

 mainwindow* win = new mainwindow(app);
 win->show();

 return app.exec();
}
то можно будет искать нужные объекты используя метод T QObject::findChild ( const QString & name = QString() ) const,
например так:
Код:
qApp->findChild<QAction*>("actionExit")->trigger();
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #2 : Октябрь 09, 2008, 01:00 »

findChild() ищет рекурсивно, или только объекты, являющиеся children для обрабатываемого объекта ( в вашем случае qApp) ?

Другими словами, можете ли вы, ну, скажем, поменять текст кнопки, которая лежит на виджете, который входит в состав другого виджета, который лежит на главном окне? Причем сделать это не зная пути от главного окна до кнопки?
Записан

Собираю информацию по крупицам
http://webhamster.ru
Rcus
Гость
« Ответ #3 : Октябрь 09, 2008, 01:13 »

Цитировать
T QObject::findChild ( const QString & name = QString() ) const
Returns the child of this object that can be cast into type T and that is called name, or 0 if there is no such object. Omitting the name argument causes all object names to be matched. The search is performed recursively.
assistant пишет что поиск выполняется рекурсивно в ширину.
Записан
ритт
Гость
« Ответ #4 : Октябрь 09, 2008, 01:25 »

используй findChild() и qobject_cast с шаблоном. имя класса можно получить из метаобъекта
Записан
pastor
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 2901



Просмотр профиля WWW
« Ответ #5 : Октябрь 09, 2008, 11:55 »

2 xintrea: Вы путаете понятия "ссылка" и "указатель". Было бы неплохо, если бы вы подредактировали свой пост и название темы
Записан

Integrated Computer Solutions, Inc. (ICS)
http://www.ics.com/
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #6 : Октябрь 09, 2008, 22:21 »

Все это уже есть в QT, даже глобальный указатель (правда не на главное окно, а на QCoreApplication(QApplication для программ с гуем)

можно искать нужные объекты используя метод T QObject::findChild ( const QString & name = QString() ) const,
например так:
Код:
qApp->findChild<QAction*>("actionExit")->trigger();

Это хорошо, но дело в том, что эта функция, согласно документации, не работает в VC6. Я сейчас пишу под линухом, но делаю мультиплатформенное приложение, и под виндой собирался компилировать именно в VC6.

Вместо этой функции рекомендуют пользовать

Цитировать
T qFindChild ( const QObject * obj, const QString & name )

которая вроде как предназначена для компиляторов, которые не поддерживают шаблоны для методов а только для функций (ну я так понял). Таким образом, функция qFindChild() должна работать как и в gcc, так и в vc6. Но я попытался использовать её, но в линухе скомпилировать с ней не могу. Делаю, например, так

Код:
qFindChild(qApp,"editor")->set_text_to_textarea("Main text");

и выдается ошибка

Код:
ошибка: нет соответствующей функции для вызова 'qFindChild(QApplication*, const char [7])

Пока еще винду не поставил, не могу посмотреть, будет ли в ней компилиться. Поэтому не могу понять - то ли это я неправильно вызов делаю, толи функция qFindChild() компилироваться будет _только_ в vc6?

Кто-нибудь может прояснить данный вопрос?


Кстати, функция qFindChild() гораздо удобнее findChild(). Она вроде как возвращает указатель на объект, требуя только стартовую точку поиска и имя, причем тип возвращаемого указателя выставит сама. А findChild(), помимо стартовой точки и имени, требует от программиста указывать тип возвращаемого указателя. Как бы мелочь конечно, но работы добавляет.
Записан

Собираю информацию по крупицам
http://webhamster.ru
Rcus
Гость
« Ответ #7 : Октябрь 09, 2008, 22:39 »

на самом деле и qFindChild, и QObject::findChild используют одну и ту же реализацию, а точнее
Код:
    template<typename T>
    inline T findChild(const QString &aName = QString()) const
    { return qFindChild<T>(this, aName); }
Код:
template<typename T>
inline T qFindChild(const QObject *o, const QString &name)
{ return static_cast<T>(qt_qFindChild_helper(o, name, reinterpret_cast<T>(0)->staticMetaObject)); }
И в любом случае нужно будет указывать тип T прямо.
Записан
ритт
Гость
« Ответ #8 : Октябрь 09, 2008, 23:10 »

Код:
return static_cast<T>(qt_qFindChild_helper(o, name, reinterpret_cast<T>(0)->staticMetaObject));

Цитировать
используй findChild() и qobject_cast с шаблоном. имя класса можно получить из метаобъекта

Улыбающийся
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #9 : Октябрь 10, 2008, 00:04 »

на самом деле и qFindChild, и QObject::findChild используют одну и ту же реализацию
И в любом случае нужно будет указывать тип T прямо.

Люди, ну скажите толком, как писать вызов qFindChild() правильно?

В документации прототип написан так

Цитировать
T qFindChild ( const QObject * obj, const QString & name )
This function is equivalent to obj->findChild<T>(name). It is provided as a work-around for MSVC 6, which doesn't support member template functions.

Нигде не вижу что тип нужно указывать. Пробовал скомпилить просто вызов функции. Вот так

Код:
qFindChild(qApp,"editor");

получаю ошибку

Цитировать
ошибка: нет соответствующей функции для вызова 'qFindChild(QApplication*, const char [7])'

и вот так пробую

Код:
qFindChild<editor>(qApp,"editor");

получаю ошибку

Цитировать
/usr/local/Trolltech/Qt-4.4.1/include/QtCore/qobject.h: In function 'T qFindChild(const QObject*, const QString&) [with T = editor]':
src/main.cpp:68:   instantiated from here
/usr/local/Trolltech/Qt-4.4.1/include/QtCore/qobject.h:408: ошибка: invalid cast from type 'int' to type 'editor'

Подключение заголовка класса editor, само собой, прописано в компилируемый cpp файл. В файл pro все используемые файлы h и cpp тоже включены.
Записан

Собираю информацию по крупицам
http://webhamster.ru
ритт
Гость
« Ответ #10 : Октябрь 10, 2008, 00:38 »

а кто такой editor? имя класса?
если да, попробуй
Код:
qFindChild<editor*>(qApp,"editor");[code]
[/code]
Записан
xintrea
Супер активный житель
*****
Offline Offline

Сообщений: 754



Просмотр профиля WWW
« Ответ #11 : Октябрь 20, 2008, 21:05 »

Здравствуйте!


Вот тут http://www.prog.org.ru/topic_7830_0.html мы начали обсуждать как делать поиск объекта по имени. Выяснили, что надо пользоваться функциями qFindChild() или FindChild, что они должны работать рекурсивно.

Однако, практика показывает, что почему-то находятся не все объекты. Я уже скоро дыру в штанах протру, выясняя почему так.

Вот пример. В программе имеются такие объекты (вывод дерева сделан через самодельную функцию, т.к. dumpObjectInfo() dumpObjectTree() не работают http://www.prog.org.ru/topic_7824_0.html). Пояснение - там где строка не начинается со слова NAME, для объекта имя не установлено.

Код:
Object tree
.NAME _layout, QMainWindowLayout
..QTimer
..QWidgetAnimator
...QTimer
.QRubberBand
.NAME editor, editor
..NAME editbold, QToolButton
..NAME editnumericlist, QToolButton
..NAME vboxLayout, QVBoxLayout
...NAME hboxLayout1, QHBoxLayout

В этом делеве нормально находится объект с именем editor, и вызывается его метод. Делается это таким кодом

Код:
 // Поиск объекта editor от корня, проходит нормально
 editor *edt;
 edt=qFindChild<editor *>(qApp,"editor");
 edt->set_text_to_textarea("Main text"); // Вызов метода найденного объекта, проходит нормально

А вот внутри этого объекта объекты уже не видятся. Пробовал так

Код:
 // Поиск кнопки на объекте editor от корня, не работает
 QToolButton *btn1;
 btn1=qFindChild<QToolButton *>(qApp,"editnumericlist");
 if(btn1!=0)
  btn1->setText("From main code for btn1");
 else
  qDebug() << "Not found editnumericlist from qApp";

и так пробовал (указатель edt найден ранее)

Код:
 // Поиск кнопки на объекте editor от объекта editor, не работает
 QToolButton *btn2;
 btn2=qFindChild<QToolButton *>(edt,"editnumericlist");
 if(btn2!=0)
  btn2->setText("From main code for btn2");
 else
  qDebug() << "Not found editnumericlist from edt";

В обоих случаях объект editnumericlist не находится в дереве через qFindChild(), хотя он там есть.

Архив простого рабочего примера прикреплен к сообщению.


Вопрос. Что делаю не так? Почему не находятся поименованные объекты? Если это имеет значение, версия Qt 4.4.1, Linux, скомпилена из исходников с дефолтными настройками.


Записан

Собираю информацию по крупицам
http://webhamster.ru
spirit
Гость
« Ответ #12 : Октябрь 20, 2008, 21:27 »

непонятно почему qApp передается в функции поиска. если сделать так, то все ок
Код:
editor *edt;
 edt=qFindChild<editor *>(mainwindowpointer,"editor");
 edt->set_text_to_textarea("Main text"); // чЩЪПЧ НЕФПДБ ОБКДЕООПЗП ПВЯЕЛФБ, РТПИПДЙФ ОПТНБМШОП

 // рПЙУЛ ЛОПРЛЙ ОБ ПВЯЕЛФЕ editor ПФ ЛПТОС, ОЕ ТБВПФБЕФ
 QToolButton *btn1;
 btn1=qFindChild<QToolButton *>(mainwindowpointer,"editnumericlist");
 if(btn1!=0)
  btn1->setText("From main code for btn1");
 else
  qDebug() << "Not found editnumericlist from qApp";

 // рПЙУЛ ЛОПРЛЙ ОБ ПВЯЕЛФЕ editor ПФ ПВЯЕЛФБ editor, ОЕ ТБВПФБЕФ
 QToolButton *btn2;
 btn2=qFindChild<QToolButton *>(mainwindowpointer,"editnumericlist");
 if(btn2!=0)
  btn2->setText("From main code for btn2");
 else
  qDebug() << "Not found editnumericlist from edt";

« Последнее редактирование: Октябрь 20, 2008, 21:50 от spirit » Записан
spirit
Гость
« Ответ #13 : Октябрь 20, 2008, 21:29 »

сделай так и глянь, что будет в консоли
Цитировать
mainwindowpointer=&app;

 // рЕЮБФБАФУС ЧУЕ УПЪДБООЩЕ ПВЯЕЛФЩ РТЙМПЦЕОЙС
 print_object_tree();
Записан
spirit
Гость
« Ответ #14 : Октябрь 20, 2008, 21:48 »

еще одно, не по теме, что это за мегафункция
Цитировать
char* fromQStringToChar( const QString& str )

можно ж вот эту заюзать и велосипед не изобретать
Код:
const char * qPrintable ( const QString & str ) 

или же через оператор << выводить в дебаг, т.е. так
Код:
qDebug() << "bla-bla-bla: " << 1 << 1.2;
Подмигивающий

ЗЫ. я предпочитаю последний способ, ибо при помощи его очень удобно выводить и контейнеры и прочее. но это уже на любителя.
« Последнее редактирование: Октябрь 20, 2008, 21:52 от spirit » Записан
Страниц: [1] 2 3 ... 6   Вверх
  Печать  
 
Перейти в:  


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