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

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

Страниц: [1]   Вниз
  Печать  
Автор Тема: Qt4.6.2. Проблемы. Конструктор интерфейса с использованием QGraphicsScene.  (Прочитано 9391 раз)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« : Июнь 23, 2010, 16:25 »

Делаю конструктор интерфейса. Хочется комбинировать QWidget'ы с графическими элементами. Например, положить кнопку а на ней произвольно разложить иконки и текст. В дальнейшем планируется строить деревья, таблицы комбинированием простых панелек, и заодно конструктор печатных форм, это накладывает требование по одновременному присутствию на экране большого числа различных панелек. QWidget'ы при большом количестве начинают сильно тормозить. Решил попробовать сделать все это с помощью QGraphicsScene, т.к. она позволяет вкладывать виджеты в сцену. Да и в хелпе однозначно написано: "in some cases you can now use Graphics View for advanced MDI applications." это вроде как раз мой случай.

Накидал пример, и возникли проблемы с отображением  Плачущий. В общих чертах:
  • не работают нормально лайоуты с QGraphicsWidgetProxy
  • эмбеддят всплывающие меню, что не радует и не понятно как отключить
  • виджеты рисуют принудительно подложку, из за этого визуальные глюки с кнопками, едитами и пр.
  • фокус перемещается странно, иногда уходит неизвестно куда
  • не работает подсветка при наведении мышкой у кнопок

Хотелось бы найти соратника по несчастью, кто с этой темой разбирался, как все это можно лечить... 

Или может есть другой подход?  Непонимающий

Скриншот багов с пояснениями:


Схема компонентов следующая:


Код:
Код:
    boost::shared_ptr<QDialog> dlg(new QDialog);
    dlg->setModal(true);

    qgraphics_window* view = new qgraphics_window(dlg.get());

    QVBoxLayout* lay = new QVBoxLayout(dlg.get());
    lay->addWidget(view);
    lay->setContentsMargins(0, 0, 0, 0);
    view->setFrameShape(QFrame::NoFrame);

    QGraphicsScene* scene = view->scene();

    QGraphicsLinearLayout* l2 = new QGraphicsLinearLayout(Qt::Vertical);
    view->proxy_widget()->setLayout(l2);
   
    QGraphicsProxyWidget* pw1 = new QGraphicsProxyWidget(view->proxy_widget());
    pw1->setWidget(new QTextEdit());
    l2->addItem(pw1);

    pw1->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum));

    QGroupBox* gb = new QGroupBox();
    QGraphicsProxyWidget* pw2 = new QGraphicsProxyWidget(view->proxy_widget());
    pw2->setWidget(gb);
    l2->addItem(pw2);

    pw2->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum));
    gb->setTitle("Group Box");

    QGraphicsLinearLayout* l3 = new QGraphicsLinearLayout(Qt::Vertical);
    pw2->setLayout(l3);

    QGraphicsProxyWidget* pw3 = new QGraphicsProxyWidget(pw2);
    pw3->setWidget(new QPushButton());
    l3->addItem(pw3);

    QGraphicsProxyWidget* pw = new QGraphicsProxyWidget(pw2);
    pw->setWidget(new QLineEdit());
    l3->addItem(pw);

    pw = new QGraphicsProxyWidget(pw2);
    pw->setWidget(new QLineEdit());
    l3->addItem(pw);

    dlg->exec();

qgraphics_window - простая обертка над QGraphicsView.
Записан

Гугль в помощь
vipet
Бывалый
*****
Offline Offline

Сообщений: 452


Просмотр профиля
« Ответ #1 : Июнь 23, 2010, 17:49 »

Или может есть другой подход?  Непонимающий

Глянь Qt Quick здесь:
http://labs.trolltech.com/blogs/2010/05/06/qt-creator-and-beyond-quick/
и в других местах
Записан
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #2 : Июнь 23, 2010, 23:07 »

Посмотрел, но что-то легче не стало  В замешательстве Насколько я понял это для свистоперделок на основе QML. А мне нужно смесь из обычных компонентов на базе QWidget с легкими (типа кубик, картинка, текст) которых может быть много.. Чтобы одно на другое можно было ложить...

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

* Ушел качать исходники кед и ковыряться в них
« Последнее редактирование: Июнь 23, 2010, 23:10 от navrocky » Записан

Гугль в помощь
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #3 : Июнь 23, 2010, 23:18 »

Хотя нет, в плазме наблюдаются те-же глюки
Записан

Гугль в помощь
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #4 : Июнь 24, 2010, 15:36 »

Цитировать
эмбеддят всплывающие меню, что не радует и не понятно как отключить
Дело в том, что тролли не дают нам контролировать создание контекстного меню Злой
Почему нельзя было сделать метод createStandardContextMenu() virtual мне непонятно.
Вот так можно решить проблему встроенного меню:
Код
C++ (Qt)
#include <QApplication>
#include <QDialog>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsProxyWidget>
#include <QGraphicsLinearLayout>
#include <QGroupBox>
#include <QVBoxLayout>
#include <QTextEdit>
#include <QLineEdit>
#include <QPushButton>
#include <QMenu>
 
static void reloadContextMenu( QMenu* orig_menu, QWidget* parent )
{
QList< QAction* > la = orig_menu->actions();
QMenu* menu = new QMenu( parent );
menu->addActions( la );
menu->setAttribute( Qt::WA_DeleteOnClose );
menu->popup( QCursor::pos() );
orig_menu->close();
}
 
class Dialog : public QDialog
{
public:
Dialog( QWidget* parent = 0 ) : QDialog( parent )
{
qApp->installEventFilter( this );
}
~Dialog() {}
protected:
bool eventFilter( QObject *obj, QEvent *event )
{
if( event->type() == QEvent::ContextMenu )
{
QMenu* menu = 0;
if( QLineEdit* le = qobject_cast< QLineEdit* >( obj ) )
menu = le->createStandardContextMenu();
else if( QTextEdit* te = qobject_cast< QTextEdit* >( obj->parent() ) )
menu = te->createStandardContextMenu();
if( menu )
{
reloadContextMenu( menu, this );
return true;
}
}
return false;
}
};
 
int main( int argc, char** argv )
{
QApplication app( argc, argv );
 
QDialog* dlg = new Dialog();
 
QVBoxLayout* lay = new QVBoxLayout( dlg );
 
QGraphicsView* gv = new QGraphicsView();
gv->setFrameStyle( QFrame::NoFrame );
 
lay->addWidget( gv );
 
QGraphicsScene* scene = new QGraphicsScene( gv );
gv->setScene( scene );
 
QGraphicsProxyWidget* pw = new QGraphicsProxyWidget();
scene->addItem( pw );
 
QGraphicsLinearLayout* l2 = new QGraphicsLinearLayout( Qt::Vertical );
pw->setLayout( l2 );
 
QGraphicsProxyWidget* pw1 = new QGraphicsProxyWidget( pw );
pw1->setWidget( new QTextEdit() );
l2->addItem( pw1 );
 
pw1->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Maximum ) );
 
QGroupBox* gb = new QGroupBox();
QGraphicsProxyWidget* pw2 = new QGraphicsProxyWidget( pw );
pw2->setWidget( gb );
l2->addItem( pw2 );
 
pw2->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Maximum ) );
gb->setTitle("Group Box");
 
lay = new QVBoxLayout( gb );
lay->addWidget( new QPushButton() );
lay->addWidget( new QLineEdit() );
lay->addWidget( new QLineEdit() );
 
dlg->exec();
}
 
Использовать созданное троллями меню мне никак не получилось. Оно всё-равно оставалось embedded чтобы я ни делал Грустный
Пришлось создавать своё использую его actions.

Цитировать
не работают нормально лайоуты с QGraphicsWidgetProxy
Вроде нормально работают.
Я не совсем понял почему вы не повесили на QGroupBox обычный layout и уже на него добавили
QPushButton и QLineEdit?
Записан

Qt 5.11/4.8.7 (X11/Win)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #5 : Июнь 24, 2010, 17:05 »

Дело в том, что тролли не дают нам контролировать создание контекстного меню Злой
Почему нельзя было сделать метод createStandardContextMenu() virtual мне непонятно.
Вот так можно решить проблему встроенного меню:

Использовать созданное троллями меню мне никак не получилось. Оно всё-равно оставалось embedded чтобы я ни делал Грустный
Пришлось создавать своё использую его actions.

Спасибо за код, попробую.  Улыбающийся
Но еще остаются всплывающие окна другого типа - в комбобоксах например (

Сейчас внимательно изучал сырцы Qt http://qt.gitorious.org/qt/qt/blobs/4.7/src/gui/graphicsview/qgraphicsproxywidget.cpp, так и не усмотрел, каким образом эмбеддятся дочерние окна и как на это можно повлиять извне Грустный

Только что углядел такой флаг в хелпе Qt::BypassGraphicsProxyWidget, может это оно самое?

Цитировать
Вроде нормально работают.
Я не совсем понял почему вы не повесили на QGroupBox обычный layout и уже на него добавили
QPushButton и QLineEdit?

У меня потребность, чтобы все виджеты на сцене имели под собой QGraphicsProxyWidget, поэтому я так сделал. Сейчас попробовал по вашему совету сперва создать QGroupBox, QVBoxLayout, QPushButton и QLineEdit, а потом все компоненты разобрать на QGraphicsProxyWidget и всё получилось! )

Из этого получается вывод, что с QWidget'ами нельзя использовать QGraphicsLayout.

Остается еще одна нерешенная проблема - все контролы рисуются с фоном, если они сидят каждый в своем прокси.... Как бороть?
Записан

Гугль в помощь
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Июнь 24, 2010, 17:31 »

Цитировать
Только что углядел такой флаг в хелпе Qt::BypassGraphicsProxyWidget, может это оно самое?
Я этот флаг пробовал. Ведёт он себя как-то странно.
Если его выставить виджету повешенному на QGraphicsProxyWidget, то этот виджет пропадает. Ежели виджету созданному на одном из потомков QGraphicsProxyWidget, то popup-menu QLineEdit становится не-embedded, но выплёвывется не там где нужно.

Цитировать
Но еще остаются всплывающие окна другого типа - в комбобоксах например (
Сдаётся мне, что тролли сделали такое поведение popup-окон специально Грустный

Кстати, заметил одну странную вещь.
У виджетов созданных без родителя и помещённых в QGraphicsProxyWidget родитель не выставляется.
Ежели задать родителя при создании, то в QGraphicsProxyWidget он уже не помещается.

Вообщем, имхо, всё это еще очень сыро (

Цитировать
Остается еще одна нерешенная проблема - все контролы рисуются с фоном, если они сидят каждый в своем прокси.... Как бороть?
Может через CSS получится?
« Последнее редактирование: Июнь 24, 2010, 17:34 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #7 : Июнь 24, 2010, 18:26 »

Цитировать
Цитировать
Но еще остаются всплывающие окна другого типа - в комбобоксах например (
Сдаётся мне, что тролли сделали такое поведение popup-окон специально Грустный
И судя по документации еще и гордятся этим  Смеющийся

Цитировать
Кстати, заметил одну странную вещь.
У виджетов созданных без родителя и помещённых в QGraphicsProxyWidget родитель не выставляется.
Ежели задать родителя при создании, то в QGraphicsProxyWidget он уже не помещается.

Ну родительские отношения возможны, если корневой QWidget запихнуть в прокси. Тогда можно его как парента использовать.

Цитировать
Вообщем, имхо, всё это еще очень сыро (
Это да. Но будем надеяться допилят, так как в кедах плазма на этом работает...

В последних коммитах я видел правки багов с контекстным меню для qt 4.7..
Записан

Гугль в помощь
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #8 : Июнь 25, 2010, 12:47 »

Кстати, может пригодится.
QGraphicsScene при обработке QEvent::WindowАctivate/QEvent::WindowDeactivate посылает эти события всем элементам сцены.
Т.е. если окно потеряет/получит фокус, то все элементы будут перерисовываться.
Такая тупая политика может дико тормозить, если элементов будет много.
Единственным решением этой проблемы, это перегрузить QGraphicsScene::event().
Записан

Qt 5.11/4.8.7 (X11/Win)
navrocky
Гипер активный житель
*****
Offline Offline

Сообщений: 817


Погроммист


Просмотр профиля
« Ответ #9 : Июнь 25, 2010, 15:12 »

Я уже решил забросить QGraphicsScene для рисования интерфейса  Смеющийся Что-то глюков много..

Буду делать аналог, свою иерархию итемов:
Код:
item
  widget_item
  graphics_item
  layout

widget_item будет путем навешивания фильтра на ассоциированный QWidget будет рисовать дочерние graphics_item'ы.
Плюс к этому придется сделать диспетчеризацию событий и фокуса к graphics_item'ам %)

Во всяком случае, пока не вижу подводных камней, почему у меня это не получится...
Записан

Гугль в помощь
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


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