![]() |
Здравствуйте, гость ( Вход | Регистрация )
![]() |
mva |
![]()
Сообщение
#1
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Добрый день!
Я хочу создать класс окна, который может работать в рамках QMdiArea как простое окно и как модальное. Делаю я это так (если все представить упрощенно): CODE class Form: public QDialog { Q_OBJECT public: Form(QWidget* pwgt = 0); ... protected: QMdiSubWindow* mdiSubWindow; virtual int exec(); virtual void show(); ... }; Form::Form(QWidget* pwgt): QDialog(pwgt, Qt::WindowTitleHint) { ... mdiSubWindow = app->getMainWindow()->getWorkspace()->addSubWindow(this, Qt::Window); mdiSubWindow->setAttribute(Qt::WA_DeleteOnClose, false); mdiSubWindow->setVisible(false); } int Form::exec() { return QDialog::exec(); // Здесь программа зацикливается - создает локальный обработчик событий, которые не поступают } void Form::show() { QDialog::show(); // Здесь программа нормально работает } Проблема в том, что если я вызываю Form.show(), то все работает нормально, а если вызываю Form.exec(), то программа начинает циклить, и не отвечает ни на клавиатуру, ни на мышь. Что я делаю не так? |
|
|
![]() |
Litkevich Yuriy |
![]()
Сообщение
#2
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Что я делаю не так? а каккой смысл в этих функциях:int Form::exec() { return QDialog::exec(); // Здесь программа зацикливается - создает локальный обработчик событий, которые не поступают } void Form::show() { QDialog::show(); // Здесь программа нормально работает } Лучше сделать наследника от QWidget, тогда ты сможешь его применять, где угодно. В коде главного окна просто вызывай так:
|
|
|
mva |
![]()
Сообщение
#3
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Определенный смысл в этих функциях есть. Класс Form, который является подклассом QDialog, сам в свою очередь является базовым классом для нескольких подклассов (окон различного вида, но со схожими базовыми функциями). Мне хотелось бы сохранить некоторый функционал базового класса QDialog, в том числе функции exec() и show(), но в несколько модифицированном виде. То есть это лучше представить так:
CODE int Form::exec() { ... return QDialog::exec(); } void Form::show() { ... QDialog::show(); } Я добавил многоточия, под которым кроется функционал, отличающий Form::show() или Form::exec() от их прототипов в QDialog. Вообще, здесь я выложил код в сильно упрощенном виде, убрав то, что не относится к сути проблемы, может быть по этому здесь может быть не понятна мотивация именно такого решения. Т.к. архитектура программы (не маленькой) уже сложилась, мне хотелось бы разрешить данную проблему в рамках уже этой сложившейся архитектуры. Добавлю, что раньше, без использования QMdiArea, программа работала, но каждое окно документа работало вне рамок главного окна приложения. Проблема появилась после перехода на использование QMdiArea. Сообщение отредактировал mva - 18.3.2010, 12:05 |
|
|
Litkevich Yuriy |
![]()
Сообщение
#4
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Form::show() или Form::exec() вообще открытые члены в наследниках не принято скрывать.Т.к. это нарушает интуитивность API. Если у класса Base, есть октрытый член foo(), то применительно к наследнику руки потянутся его вызвать, ошибка при компиляции поставит человека в тупик по поводу диалога в МДИ: я на практике убедился, что почти всегда стоит делать окна, заранее не главные, наследниками QWidget, т.к. их мы можем поместить куда угодно, в том числе в наследник QDialog. В МДИ, я думаю, возникают проблемы, связанные с тем, что QDialog - всегда окно верхнего уровня, а parent в нём - всего лишь способ центровки и владения (для последующего удаления объекта). П.С. имеет смысл переписать этот виджет пока совсем плохо не стало. |
|
|
kwisp |
![]()
Сообщение
#5
|
![]() астарожна ынтжинэр ![]() ![]() ![]() ![]() ![]() Группа: Участник Сообщений: 1404 Регистрация: 26.11.2008 Из: ТаганрогРодинаЧехова Пользователь №: 435 Спасибо сказали: 113 раз(а) Репутация: ![]() ![]() ![]() |
вопрос еще почему переопределяется show() && exec() в секции protected если это вообще открытые слоты, да еще и делаются виртуальными???
не понятна цель настолько хитрого заворота. |
|
|
mva |
![]()
Сообщение
#6
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
вопрос еще почему переопределяется show() && exec() в секции protected если это вообще открытые слоты, да еще и делаются виртуальными??? не понятна цель настолько хитрого заворота. Потому что в оригинале эти функции называются doShow() и doExec() и переопределяются в наследуемых классах, а их вызов производится собственно публичными функциями show() и exec(), которые определены в базовом классе Form, но не переопределяются в наследуемых классах. Хотел упростить восприятие, но видимо наоборот усложнил. Будем считать, что я имею такой код: CODE class Form: public QDialog { Q_OBJECT public: Form(QWidget* pwgt = 0); int exec() { return doExec(); } void show() { return doShow(); } ... protected: QMdiSubWindow* mdiSubWindow; virtual int doExec(); virtual void doShow(); ... }; Form::Form(QWidget* pwgt): QDialog(pwgt, Qt::WindowTitleHint) { ... mdiSubWindow = app->getMainWindow()->getWorkspace()->addSubWindow(this, Qt::Window); mdiSubWindow->setAttribute(Qt::WA_DeleteOnClose, false); mdiSubWindow->setVisible(false); } int Form::doExec() { ... return QDialog::exec(); // Здесь программа зацикливается - создает локальный обработчик событий, которые не поступают } void Form::doShow() { ... QDialog::show(); // Здесь программа нормально работает } |
|
|
MoPDoBoPoT |
![]()
Сообщение
#7
|
Участник ![]() ![]() Группа: Участник Сообщений: 172 Регистрация: 7.5.2009 Из: Москва Пользователь №: 738 Спасибо сказали: 44 раз(а) Репутация: ![]() ![]() ![]() |
Класс Form, который является подклассом QDialog, сам в свою очередь является базовым классом для нескольких подклассов (окон различного вида, но со схожими базовыми функциями). Мне хотелось бы сохранить некоторый функционал базового класса QDialog, в том числе функции exec() и show(), но в несколько модифицированном виде. Может тогда лучше отнаследоваться от QMdiSubWindow (чтобы внутри QMdiArea "ездить"), и реализовать весь функционал QDialog'а (благо всего 5 функций, 5 слотов и 3 сигнала). Для exec() надо будет обзавестись своим QEventLoop, а в общем тебе помогут исходники QDialog'а и эта тема. |
|
|
mva |
![]()
Сообщение
#8
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
по поводу диалога в МДИ: я на практике убедился, что почти всегда стоит делать окна, заранее не главные, наследниками QWidget, т.к. их мы можем поместить куда угодно, в том числе в наследник QDialog. В МДИ, я думаю, возникают проблемы, связанные с тем, что QDialog - всегда окно верхнего уровня, а parent в нём - всего лишь способ центровки и владения (для последующего удаления объекта). П.С. имеет смысл переписать этот виджет пока совсем плохо не стало. Наверное стоит попробовать унаследовать Form от QWidget, а не от QDialog. ... Попробовал. Все равно так же циклит. ... Буду пробовать следующий вариант - наследовать Form от QMdiSubWindow. Сообщение отредактировал mva - 18.3.2010, 14:26 |
|
|
Litkevich Yuriy |
![]()
Сообщение
#9
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Буду пробовать следующий вариант - наследовать Form от QMdiSubWindow. опять не унифицированный способ, тепрь ты сможешь использовать Form, только в узкой области - МДИПопробовал. Все равно так же циклит. покажи код как ты создаёшь и вызываешь субокно/диалог
|
|
|
mva |
![]()
Сообщение
#10
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Буду пробовать следующий вариант - наследовать Form от QMdiSubWindow. Пока не прокатило... Требуются сложные переделки. По-простому не получилось. покажи код как ты создаёшь и вызываешь субокно/диалог Код довольно сложный. Готовы ли Вы разбираться в нем? Сегодня постараюсь подготовить. Выложу не весь, а только те куски кода, которые имеют отношение к проблеме. Сообщение отредактировал mva - 18.3.2010, 17:46 |
|
|
Litkevich Yuriy |
![]()
Сообщение
#11
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
|
|
|
mva |
![]()
Сообщение
#12
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
Вот так примерно выглядят классы, которые работают в данном контексте:
CODE class Form: public QDialog { // Класс формы обеспечивает базовый функционал для всех форм приложения (кнопки "Принять", "Отменить"; сохранение конфигурации окна и т.п.) Q_OBJECT public: Form(QWidget* pwgt = 0, Essence* par = 0); ... public slots: int exec() { return doExec(); } void show() { doShow(); } ... protected: QMdiSubWindow* mdiSubWindow; Essence* parent; virtual int doExec(); virtual void doShow(); ... }; Form::Form(QWidget* pwgt, Essence* par):QDialog(pwgt, Qt::WindowTitleHint) { parent = par; ... mdiSubWindow = app->getMainWindow()->getWorkspace()->addSubWindow(this, Qt::Window); mdiSubWindow->setAttribute(Qt::WA_DeleteOnClose, false); mdiSubWindow->setVisible(false); } int Form::doExec() { ... return QDialog::exec(); } void Form::doShow() { ... QDialog::show(); } //---------------------------------------------------------------------------------------- class FormGrid : public Form { // Класс обеспечивает функционал для форм, имеющих Grid (кнопки "Добавить", "Удалить", "Просмотреть", "Обновить", "Печать") плюс базовый функционал класса Form ... }; //---------------------------------------------------------------------------------------- class FormGridSearch : public FormGrid { // Класс обеспечивает функционал для форм, имеющих Grid и параметры для поиска (например для просмотра сущности "Справочник") ... }; //---------------------------------------------------------------------------------------- class FormDocument : public FormGrid { // Класс обеспечивает функционал для просмотра содержимого документа ... }; //---------------------------------------------------------------------------------------- class Essence { // Класс, который описывает базовый функционал сущностей предметной области (справочники, документы, списки документов, отчеты и т.п.) ... virtual int exec(); virtual void show(); ... protected: FormGrid* form; ... virtual void setForm(); // Чисто виртуальная функция. Переопределяется в подклассах ... }; int Essence::exec() { return form->exec(); } void Essence::show() { form->show(); } //---------------------------------------------------------------------------------------- class Dictionary : public Essence { // Класс описывает сущность "Справочник" public: ... protected: ... virtual void setForm(); ... }; void Dictionary::setForm() { form = new FormGridSearch((QWidget*)app->getMainWindow(), this); } //---------------------------------------------------------------------------------------- class Document : public Essence { // Класс сущности "Документ" public: QMap<QString, Dictionary*> dictionaries; // Объекты справочников, которыми оперирует документ ... virtual bool add(); // Функция добавляет новую строку в документ ... protected: virtual void setForm(); // Устанавливает соответствующую сущньсти "Документ" форму private: ... bool showNextDict(); // Производит перебор справочников при добавлении новой строки ... }; bool Document::add() { ... if (showNextDict()) { ... return true; } return false; } void Document::setForm() { form = new FormDocument((QWidget*)parentForm, this); } bool Document::showNextDict() { Dictionary* dict; bool anyShown = true; foreach (QString dictName, dictionaries.keys()) { dict = dictionaries.value(dictName); if (...) { dict->exec(); // Показать справочник в модальном окне. Пользователь должен выбрать объект справочника, прежде чем двигаться дальше ... if (dict->isFormSelected()) { if (...) { anyShown = false; // то считать, что этот справочник не был показан и не давать добавить строчку в документ break; } } else { anyShown = false; // пользователь отказался от работы со справочниками. Прекратим процесс добавления записи break; } } } return anyShown; } После инициализации всех объектов действия начинаются с вызова функции Docement::add() - добавление новой строки в документ. вот избавься от сложного кода и точно всё встанет на свои места. В сообщении №2 я показал как должен выглядеть код, для случая с наследованием от QWidget. Примерно такой же код я и хотел бы увидеть. Если для каждого вида окна писать собственный код, то может быть и можно упростить код для каждого по отдельности окна, но не для приложения в целом, если таких окон в приложении множество. Я пытаюсь классифицировать окна по их назначению и внешнему виду и выделить общие свойства в соответствующих классах. Например так: Form - Пустое окно и кнопки "Принять", "Отменить". Запоминает размеры окна. FormGrid::Form - Окно с кнопками "Принять", "Отменить", плюс кнопки "Добавить", "Удалить", "Просмотреть", "Обновить", "Печать", плюс просмотр таблиц (для сущностей "Отчет", "Список документов" и т.п.) FormGridSearch::FormGrid::Form - Окно со всеми кнопками и Grid, плюс возможность настройки фильтров поиска (для сущностей типа "Справочник") Так что это сложность архитектуры для упрощения развития приложения. Эта архитектура была проработана на таком же проекте, но написанном на Visual FoxPro. Тот проект проработал (и до сих пор работает) во многих местах и показал хорошие возможности для модернизации и развития, но к сожалению был написан на проприетарном инструментарии. Я сейчас портирую его на Qt4. Если присмотреться, мой кусок кода, который работает с QMdiSubWindow, похож на Ваш. Я поторопился. Не совсем похож. |
|
|
Litkevich Yuriy |
![]()
Сообщение
#13
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
|
|
|
mva |
![]()
Сообщение
#14
|
Участник ![]() ![]() Группа: Участник Сообщений: 104 Регистрация: 15.3.2009 Из: Киров Пользователь №: 615 Спасибо сказали: 3 раз(а) Репутация: ![]() ![]() ![]() |
посмотри внимательно на сообщение №2. Там, в главном окне (!) создаётся субокно, а не внутри класса описывающего субокно Сделал класс Form наследуемым от QWidget, а не от QDialog. Конструктор класса Form подправил вот так: CODE Form::Form(QWidget* pwgt, Essence* par):QWidget(pwgt, Qt::WindowTitleHint) { parent = par; ... // mdiSubWindow = app->getMainWindow()->getWorkspace()->addSubWindow(this, Qt::Window); // mdiSubWindow->setAttribute(Qt::WA_DeleteOnClose, false); // mdiSubWindow->setVisible(false); mdiSubWindow = new QMdiSubWindow; mdiSubWindow->setWidget(this); mdiSubWindow->setAttribute(Qt::WA_DeleteOnClose); mdiSubWindow = app->getMainWindow()->getWorkspace()->addSubWindow(mdiSubWindow, Qt::Window); } Думаю, что это то, что вы предлагаете. В результате приложение стало выглядеть так: ![]() А должно выглядеть так: ![]() Кстати, я попробовал сделать окна в примере /qt/examples/mainwindows/mdi, который идет в комплекте с Qt4, модальными. Я добавил лишь одну строку в реализации процедуры MainWindow::newFile(): CODE void MainWindow::newFile() { MdiChild *child = createMdiChild(); child->newFile(); child->setWindowModality(Qt::WindowModal); // эта строка добавлена мной child->show(); } В результате это приложение стало тоже зацикливаться при открытии нового окна. Оно перестает реагировать на любые события и выйти из него можно только путем снятия процесса. Почему в этом примере не удалось сделать окна модальными? |
|
|
Litkevich Yuriy |
![]()
Сообщение
#15
|
![]() разработчик РЭА ![]() ![]() ![]() ![]() ![]() ![]() ![]() Группа: Сомодератор Сообщений: 9669 Регистрация: 9.1.2008 Из: Тюмень Пользователь №: 64 Спасибо сказали: 807 раз(а) Репутация: ![]() ![]() ![]() |
Думаю, что это то, что вы предлагаете. нет, в виджете, нет никаких QMdiSubWindow, WA_DeleteOnClose, ... Он о их существовании вообще ничего не знает, это нужно делать снаружи.Ну и при наследовании от QWidget, не забыть определить методы, которыми пользуются компоновщики (sizeHint, ...) |
|
|
![]() ![]() ![]() |
![]() |
|
Текстовая версия | Сейчас: 3.6.2025, 20:54 |