Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Виджет-контейнер
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt GUI
fantom
Возникла необходимость сделать виджет-контейнер. По сути это обычный виджет в котором могут находится другие виджеты вместе со своими дочерними виджетами. Работа с ним будет происходить примерно следующим образом: в дизайнере мы переносим мышкой необходимый виджет на виджет-контейнер, и он определяет типы объектов которые на нем находятся(все они наследники от QWidget) и по команде add добавляет внутри себя новый набор виджетов который является клоном того что положили в дизайнере.
Вот тут наглядно что я хочу получить(в упрощенном варианте).
Нажмите для просмотра прикрепленного файла
Основная проблема в определении типов всех дочерних виджетов виджета-контейнера. Понятно что надо работать с шаблонами c++ но как? Может кто может что подсказать?
Litkevich Yuriy
Цитата(fantom @ 10.4.2009, 19:45) *
Вот тут наглядно что я хочу получить(в упрощенном варианте).
всё равно не понятно.

Цитата(fantom @ 10.4.2009, 19:45) *
и по команде add добавляет внутри себя новый набор виджетов который является клоном того что положили в дизайнере.
особенно это, команда уже не в дизайнере, а в коде? полность повторить содержимое?

Цитата(fantom @ 10.4.2009, 19:45) *
Основная проблема в определении типов всех дочерних виджетов виджета-контейнера.
вроде нет такой проблемы, Метаобъектная система позволяет определить класс от которого унаследовались и пр.
fantom
Ну фактически слот add который описан 1 раз в коде , он должнен быть универсальным и уметь клонировать тот элемент который мы положили в дизайнере.
Litkevich Yuriy
Цитата(fantom @ 10.4.2009, 19:57) *
он должнен быть универсальным и уметь клонировать тот элемент который мы положили в дизайнере.
вот с этого места ещё подробнее.
Клонировать только тот элемент, который положили в дизайнере?
- - -> Если в дизайнере положили несколько элементов, то клонировать все?
fantom
По определению на этот элемент можно класть только 1 виджет(на нем могут быть дочерние виджеты). В идеале вообще запретить добавление нескольких виджетов - но это некритично пока. Вот этот виджет который мы положили и будет клонироваться, причем расположение клонов будет задаваться через QLayout.
kuler
шаблоны тут врядли причем, достаточно обычного switch
if (child.type == QButton)
{
but = new QButton(child);
}
else if (child.type == QListWidget)

как то так
Litkevich Yuriy
Так. Имеется в дизайнере mainForm (QWidget) для него устанавливается некий компоновщик, например, QVBoxLayout.
В компоновщик помещается один(!) виджет.

Далее в коде ищем у mainForm единственного ребенка и запоминаем его.
При срабатывании слота add клонируем ребенка и помещаем в компоновщик mainForm.

Если я правильно понял, тогда в чём вопрос?
fantom
Проблема в том что внутри того виджета который мы поместили могут быть какие то объекты, причем тип их заранее неизвестен, известно только что они наследуются от QWidget. Как технически клонировать виджет который содержит внутри себя другие объекты. Причем с полным соответствием типов. Вариант со свитчем не очень подходит, хочется как то универсально..
Litkevich Yuriy
Цитата(fantom @ 10.4.2009, 20:21) *
Как технически клонировать виджет который содержит внутри себя другие объекты.
Во, вот это и есть настаящая задачка.

Пока чуть мимо нее, экскурс так сказать:
Чтобы найти ребёнка пользуемся чем-нибудь типа QObject::findChildren(), вернет указатель на QObject, его лучше сразу привести к типу QWidget с помощью qobject_cast.

В слоте add клонируем виджет (вот с этим нужно разобраться)

Далее если тебе понадобится вызывать методв специфичные для данного виджета, то используем invokeMtod
fantom
Да согласен. До этого тоже дошел. А вот как вызвать new с тем классом который нужно получить при поиске дочерних виджетов непонятно.
Litkevich Yuriy
Первое, что приходит в голову по поводу клонирования - пробежатся по всем дочерним виджетам, однако надо будет еще и их свойства скопировать.

Цитата(fantom @ 10.4.2009, 20:21) *
Причем с полным соответствием типов
похоже, что роботёнки будет навалом.

Цитата(fantom @ 10.4.2009, 20:28) *
А вот как вызвать new с тем классом который нужно получить
можно поглядеть в сторону QMetaObject::newInstance
Но я тоже с такой задачкой не сталкивался, посему могу гененрить идеи и только ;)

Цитата
This function was introduced in Qt 4.5.
fantom
QMetaObject::newInstance? Это в какой версии qt? У меня в доках по 4,4,2 нет.

Ясно.. А мне кровь из носа не выше 4,4,2 можно использовать
Litkevich Yuriy
Цитата(fantom @ 10.4.2009, 20:41) *
Ясно.. А мне кровь из носа не выше 4,4,2 можно использовать
тогда у меня никаких других идей нет, кроме как смотреть устройство QUiLoader'а
Ведь он как-то конструирует целую пачку объектов.
SABROG
Сейчас речь идет о стандартных виджетах Qt или о самопальных тоже из каких-нибудь плагинов? Например интересует вопрос, возможно ли скопировать окно типа QMainWindow? Насколько я знаю, в программе должен существовать только один экземпляр этого класса (singleton?).
Litkevich Yuriy
Цитата(SABROG @ 10.4.2009, 20:48) *
Сейчас речь идет о стандартных виджетах Qt
пока о них.
fantom
Вообще у меня задача стоит клонировать и мои собственные виджеты, которые сделаны как плагины дизайнера.

Впринципе т,к, виджетов не очень много можно сделать case. Но этого бы очень не хотелось бы.

Появилась одна идея,, Но для этого нужно будет переопределять все элементы которые необходимо клонировать. Как то так..
class MyClass: public QWidget
{
MyClass(QWidget* parent)
    QWidget* clone(QWidget* parent)
    {
        return MyClass( parent );
    }
}
igor_bogomolov
Цитата(fantom @ 10.4.2009, 17:21) *
Как технически клонировать виджет который содержит внутри себя другие объекты.
Цитата(fantom @ 10.4.2009, 16:45) *
Работа с ним будет происходить примерно следующим образом: в дизайнере мы переносим мышкой необходимый виджет на виджет-контейнер


Отклонусь немного от темы (а мож и не отклонюсь :) ).
По двум недавным обсуждения по поводу динамического создания форм (раз два) родилась следущая мысль. Не знаю на сколько хорошая, но право на жизнь имеющая. (Меня покрайней мере было интересно это реализовать).
Итак, вопросс
Цитата(fantom @ 10.4.2009, 17:21) *
Как технически клонировать виджет который содержит внутри себя другие объекты.

Сразу хочу оговориться, с XML опыта работы очень мало, так что если есть способ сократить код или сделать более изящно, сделайте это. Мне прошу не пинать :)
И еще, метод domxmlToString был позаимствован у xintrea здесь (ссылка)

Итак, изначально форма, виджет-контейнер и все что в нем, создается в дисигнере. Т.е. мы имее ui файл.
шаг №1
 // читаем содержимое ui файла
QDomDocument doc("mydocument");
QFile file("../form/oscilloscope.ui");
if (!file.open(QIODevice::ReadOnly))
     return 0;
if (!doc.setContent(&file)) {
     file.close();
     return 0;
}
file.close();

// отыскиваем в нем наш виджет контейнер по имени (в моем случае это voltdivgroupBox)
QDomNodeList nodelist = doc.elementsByTagName( "widget" );
QDomElement elem; // здесь будет сохранен нужный нам узел
qDebug() << nodelist.count();
for (int i =0; i != nodelist.count(); i++) {
     elem = nodelist.item(i).toElement();
     if(elem.attribute("name") == "voltdivgroupBox")
         break;
}

шаг №2
// Преабразуем наш узел в QByteArray
QByteArray xmlstr = domxmlToString(elem).toUtf8();
// А теперь эмитируем XML файл (а если точнее .ui)
xmlstr.prepend("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
           "<ui version=\"4.0\">");
xmlstr.append("</ui>");

шаг №3 (заключительный)
// Загружае наш виджет-контейне(или если хотите клонируем) посредством QUiLoader 
    QUiLoader loader;
    QBuffer buffer(&xmlstr);
    buffer.open(QIODevice::ReadOnly|QIODevice::Text);
    QWidget *myWidget = loader.load(&buffer); // это клон нашего виджета-контейнера со всеми расположенными в нем элементами и с сохраннеными свойствами
    buffer.close();
    myWidget->show();

приложение. Описание метода domxmlToString
QString domxmlToString(QDomNode xmldata)
{
     if(xmldata.isDocument()) {
         return xmldata.toDocument().toString();
     }
     else {
         QString xmlcode;
         QTextStream stream(&xmlcode, QIODevice::WriteOnly);
         xmldata.save(stream, 1);
         return xmlcode;
     }
}

Вот что получилось у меня(см. прикрепленные рисунки). Как видете я создал два клона части своего приложения, Все свойства при этом сохранены, в том числе и ресурсы.

Ух. Я в тему надеюсь :rolleyes:?
Даже если не совсем, хвалим меня, я старался :rolleyes:
Litkevich Yuriy
igor_bogomolov, вся эта процедура нужна для того, чтобы извлечь только нужный виджет из ui-файла, я правильно понял?
igor_bogomolov
Цитата(Litkevich Yuriy @ 11.4.2009, 0:01) *
igor_bogomolov, вся эта процедура нужна для того, чтобы извлечь только нужный виджет из ui-файла, я правильно понял?
Нужный виджет, со всем его содержимым(т.е. расположенными на нем другими виджетами) и с сохранением его свойств, и свойств элементов на нем расположенных.
И сделать столько копий подобного объекта, сколько потребуеься. В общем на прилогаемом выше рисунке все видно. :rolleyes:
igor_bogomolov
Цитата(SABROG @ 10.4.2009, 17:48) *
возможно ли скопировать окно типа QMainWindow? Насколько я знаю, в программе должен существовать только один экземпляр этого класса (singleton?).
Откуда такая информация? У меня в проекте используется два QMainWindow, и никаких проблем не испытываю :rolleyes:
SABROG
Цитата(igor_bogomolov @ 11.4.2009, 1:52) *
Цитата(SABROG @ 10.4.2009, 17:48) *
возможно ли скопировать окно типа QMainWindow? Насколько я знаю, в программе должен существовать только один экземпляр этого класса (singleton?).
Откуда такая информация? У меня в проекте используется два QMainWindow, и никаких проблем не испытываю :rolleyes:

Понятно. Я думал, что нельзя. Типа главное окно, системные события, завязка на QApplication.
fantom
igor_bogomolov спасибо за решение проблемы. Как я понимаю это то что мне надо. В ближайшее время опробую этот вариант.
fantom
Еще вопрос. Каким образом при такой схеме обращаться к дочерним элементам клона?
igor_bogomolov
Я лишь предложил способ как клонировать часть Gui.
Дальнейшая ваша задача мне несколько непонятна.

Цитата(fantom @ 10.4.2009, 17:21) *
Проблема в том что внутри того виджета который мы поместили могут быть какие то объекты, причем тип их заранее неизвестен

Какие действия предпологаются с виджетами расположенными на виджет-контейнере?

Так, с ходу, могу предложить только
T findChild ( const QString & name = QString() ) const
const QObjectList & children () const

Кстати из xmlstr можем также составить список виджетов расположенных на виджете-контейнере.
fantom
Все разобрался. Используя findChildren<QWidget*>( ) находим все элементы на форме, которые наследованы от QWidget. Дальше элементы идентифицируются по имени и их свойства меняются через setProperty.

Простой смены свойств этих элементов мне пока достаточно. Еще можно слоты вызывать при помощи InvokeMethod. Но мне пока это не нужно.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.