Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: enola от Сентябрь 07, 2006, 14:55



Название: Модальный диалог
Отправлено: enola от Сентябрь 07, 2006, 14:55
Пытаюсь сделать модальный диалог с кнопочками "accept" и "cancel" с соответствующими сигналами;
вот так работает:
Код:
MessageDialog *message = new MessageDialog(this);
message->show();


а вот так кнопки не нажимаются:
Код:
MessageDialog *message = new MessageDialog(this);
if (message->exec() == QDialog::Accepted) {
   // ....
}

в чем проблема?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 07, 2006, 15:41
Цитировать
а вот так кнопки не нажимаются:

ниасилил
Ты от чего наследуешься? От QDialog или от QMessageBox?

...может тебя устроят стандартные статики QMessageBox?


Название: Модальный диалог
Отправлено: enola от Сентябрь 07, 2006, 15:55
Цитата: "bigirbis"

Ты от чего наследуешься? От QDialog или от QMessageBox?

от QDialog.

Цитата: "bigirbis"
...может тебя устроят стандартные статики QMessageBox?

Не, не подойдет у меня там свой интерфейс рисуется.

вот что делаю в конструкторе диалога:
Код:
QPushButton *okButton = new QPushButton(tr("Продолжить"), this);
QPushButton *cancelButton = new QPushButton(tr("Отмена"), this);
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));

при show данные кнопки нажимаются а при exec нет!???
 :(


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 07, 2006, 16:15
Ты слоты accept() и reject() переопределял?
Если да, то для решения проблемы скорее всего в конце слотов не хватает строчки QDialog::accept(); и QDialog::reject();


Название: Модальный диалог
Отправлено: enola от Сентябрь 07, 2006, 16:17
Цитата: "bigirbis"
Ты слоты accept() и reject() переопределял?
Если да, то для решения проблемы скорее всего в конце слотов не хватает строчки QDialog::accept(); и QDialog::reject();

нет, а что нужно?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 07, 2006, 16:31
Цитировать
нет, а что нужно?

...нет, слоты переопределять необязательно, просто и такая проблема могла иметь место...

Побыстрому сваял диалог. Вот код. Все работает.
Код:

setLayout( new QHBoxLayout );
QPushButton * buttonAccept = new QPushButton( "accept" );
QPushButton * buttonReject = new QPushButton( "reject" );
layout()->addWidget( buttonAccept );
layout()->addWidget( buttonReject );

connect( buttonAccept, SIGNAL( clicked() ), SLOT( accept() ) );
connect( buttonReject, SIGNAL( clicked() ), SLOT( reject() ) );

Если не заведется, шли код - посмотрим. Все дело, наверное, в конце рабочего дня :)


Название: Модальный диалог
Отправлено: enola от Сентябрь 07, 2006, 16:43
вот нашел затык:
Код:
setWindowFlags(Qt::FramelessWindowHint);

мне нужно чтобы диалог был без "заголовка".
Так можно сделать или нужно наследовать от QWidget  и писать ручками?

P.S. чуть поправлюсь мне нужно чтобы этот диалог был в размер главного окна и прозрачный без рамки вот с флагом с этим так и получается только кнопки не нажимаются, отключаю флаг все нормально, только диалог отдельно от окна!

вот мой диалог:
Код:
	
MyDialog::setWindowFlags(Qt::FramelessWindowHint);

MyDialog::setGeometry(QRect(0, 0, 1024, 768));

QPalette bgPalette = MyDialog::palette();
QBrush bgBrush = QColor(255, 255, 255, 50); //120

bgPalette.setBrush(MyDialog::backgroundRole(), bgBrush);
MyDialog::setAutoFillBackground(true);
MyDialog::setPalette(bgPalette);

QPixmap bgPixmap("dialog.png");
QLabel *bgLabel = new QLabel(this);
bgLabel->setPixmap(bgPixmap);

QPushButton *okButton = new QPushButton(tr("Продолжить"), this);
QPushButton *cancelButton = new QPushButton(tr("Отмена"), this);

okButton->setGeometry(QRect(600, 440, 200, 50));
cancelButton->setGeometry(QRect(360, 440, 200, 50));

connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 07, 2006, 17:35
Цитировать
Код:
MyDialog::setGeometry(QRect(0, 0, 1024, 768));

По коду похоже, что шириной в десктоп: QApplication::desktop()->size()

И еще вопрос: у тебя слоты не отрабатывают, или сами баттоны на клик не реагируют?


Название: Модальный диалог
Отправлено: enola от Сентябрь 07, 2006, 17:41
нет мне нужно просто такого размера диалог на главной форме.


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 07, 2006, 18:25
Специально созданный тест показал, что если передать флаг Qt::FramelessWindowHint следующим образом, то таких контузий не возникает:
Код:
MessageDialog *message = new MessageDialog( this, Qt::FramelessWindowHint );
либо
Код:
MessageDialog::MessageDialog( QWidget * parent, Qt::WFlags flags )
: QDialog( parent, flags | Qt::FramelessWindowHint )
{
...
}


Название: Модальный диалог
Отправлено: alex0303 от Сентябрь 07, 2006, 21:07
А
setWindowFlags(getWindowFlags() | Qt::FramelessWindowHint);
не катит?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 08, 2006, 08:45
To alex0303
Смотри тему внимательнее.

При установке данного влаге методом setWindowFlags() начинается весьма интересная свистопляска, описанная выше.


Название: Модальный диалог
Отправлено: enola от Сентябрь 08, 2006, 08:57
bigirbis
Контузий не возникает, но и желаемого результата тоже.
Вот что нужно: есть форма, на ней по клику на кнопке должен появиться прозрачный диалог (во весь размер формы), у меня с выше описанным кодом все получается, только кнопки не нажимаются (именно сами баттоны не реагируют). А если сделать как ты написал, то все работает только диалог не прозрачный и не на форме а отдельно!


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 08, 2006, 10:17
To enola.
То, о чем ты говоришь, жесточайший изврат. Рамку нужно убирать как описано выше (передавая флаги в конструктор виджета). В твоем случае QPainter просто взбесился. А прозрачность надо делать другими средствами - смотри в форуме. Что касаетя выхода за границы виджета - так ты же от диалога наследуешься (тогда переописывай resizeEvent() либо наследуйся от виджета и клади его сверху).


Название: Модальный диалог
Отправлено: enola от Сентябрь 08, 2006, 13:52
Ты прав это полный изврат, буду делать от QWidget, спасибо за помошь.


Название: Модальный диалог
Отправлено: enola от Сентябрь 11, 2006, 08:09
Сделал от QWidget, интерфейс что нужно, теперь сама реализация нужна, а именно некоторые весчи от QDialog:
  • Модальность
  • Слоты accept(), reject()
  • Результат (возвращаемое значение)

подскажите как такое можно реализовать?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 11, 2006, 12:35
По поводу модальности:
void setWindowModality ( Qt::WindowModality windowModality );
Qt::WindowModal
Qt::ApplicationModal

По поводу accept()/reject() создай два слота у виджета и зацепи их к кнопарям.
Можно прикрутить enum флаг выполнения.
Если был какой-нибудь контекст диалога, то можно написать метод, который его возвращает или воткнуть в качестве возвращаемого значения из accept()/reject().


Название: Модальный диалог
Отправлено: enola от Сентябрь 11, 2006, 13:07
Млин что-то не получается:
  • Модальность, делаю:
    Код:
    MyForm::setWindowModality(Qt::WindowModal);

    опять кнопки не реагируют (не нажимаются), создан от QWidget?
  • Слоты, так если я создаю слоты accept и reject компилятор ругается?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 11, 2006, 13:38
Цитировать
setWindowModality(Qt::WindowModal)

Это в конструкторе?

Цитировать
Слоты, так если я создаю слоты accept и reject компилятор ругается?

По идее не на что ругаться - вроде у QWidget нет таких имен...


Название: Модальный диалог
Отправлено: enola от Сентябрь 11, 2006, 14:03
Цитата: "bigirbis"
Цитировать
setWindowModality(Qt::WindowModal)

Это в конструкторе?

ну да.

Цитировать
По идее не на что ругаться - вроде у QWidget нет таких имен...

ошибка при компиляции LNK 2019.

 :(


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 11, 2006, 14:44
По поводу setWindowModality(Qt::WindowModal)
Цитировать
Changing this property while the window is visible has no effect; you must hide() the wiget first, then show() it again.


Вышли код с accept()/reject()


Название: Модальный диалог
Отправлено: enola от Сентябрь 11, 2006, 15:04
Слоты сделал вот как (работает, что-то я тормознул сначала):
Код:
void MyForm::accept()
{
setResult(1);
close();
}

void MyForm::reject()
{
setResult(0);
close();
}

void MyForm::setResult(const int &newResult)
{
iResult = newResult;
}


и хидер:
Код:
class MyForm: public QWidget
{
    Q_OBJECT
Q_PROPERTY(int Result READ Result WRITE setResult)

public:
    MyForm::MyForm(QWidget * parent);
int Result() const {return iResult;}

public slots:
void accept();
void reject();

private:
int iResult;

void setResult(const int &newResult);
};


потом создаю форму:
Код:
	MyForm *MyDialog = new MyForm(this);
MyDialog ->show();
if (MyDialog ->Result() == 1)
//.....

вот тут с результатом плохо, я так понимаю нужно, чтобы форма была модальная, иначе получается как у меня, а именно после show сразу далее идет обработка, а должно ждать результат. Что делать?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 11, 2006, 15:21
Ну дык и опиши метод:

bool MyForm::exec()
{
}

посмотри как у QDialog сделано (там через QEventLoop).
И еще, не стоит стрелять диалог в accept()/reject() если не выставлен флаг Qt::WA_DeleteOnClose. Тем паче, что в этом случае контекст диалога тоже стреляется.


Название: Модальный диалог
Отправлено: enola от Сентябрь 11, 2006, 15:33
с exec это идея, завтра попробую, а вот с закрытием диалога что делать, когда его убивать?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 11, 2006, 15:37
Можно создавать его объект в каком-нибудь слоте, и он разрушится, выйдя из области видимости.
Или создать указатель, а потом вызвать delete.
Как правило, так и делается.
А еще можно написать статику, которая просто возвращает или код, или контекст.


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 06:05
Цитата: "bigirbis"
Или создать указатель, а потом вызвать delete.
Как правило, так и делается.

А с этого момента пожалуйста поподробней, если не сложно с примером? :D

P.S. Сделал exec проверка проходит и результат возвращает, только когда повторно диалог создается вылетает ошибка, наверное как раз с удалением не реализовал, смотрел в стандартном диалоге, что-то запутанно не разобрался.


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 08:36
Цитировать
А с этого момента пожалуйста поподробней, если не сложно с примером?

Код:

void slotSmth()
{
 ...
 MyDialog * dialog = new MyDialog( this );
 if( dialog->exec() )
 {
  ...
 }
 else
 {
  ...
 }
 ...
 if( dialog )
  delete dialog;
}


Qt все-таки на плюсах писано, надо Страуструпа читать.


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 09:45
Цитата: "bigirbis"
Qt все-таки на плюсах писано, надо Страуструпа читать.

Читал и почитываю. До этого я додумался, думал может что иное посоветуешь.


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 11:10
Думаю, что-то иное тяжело придумать.

Можно, конечно, установить флаг Qt::WA_DeleteOnClose, а затем, в конце слота, вызвать close().


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 11:17
вот точно вот, что делается в стандартном :)


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 11:26
В стандартном проверяется, установлен ли флаг Qt::WA_DeleteOnClose. И если да - вызывается delete this, если нет - ничего не происходит. Конечно лучше из стандартного выдрать - думаю никто в обиде не будет.


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 13:51
что-то плоховато работает, раз 20 кликнешь и вылетает с ошибкой непонятной:

Код:

#include "private/qdialog_p.h"

MDialog::MDialog(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags | QFlag(Qt::WA_ShowModal) |   // Модальное
 QFlag(Qt::FramelessWindowHint))  // Без заголовка, без кнопки на таскбаре
{
// Фон
QPixmap bgPixmap("message.png");
QLabel *bgLabel = new QLabel(this);
bgLabel->setPixmap(bgPixmap);

// Кнопки
QPushButton *okButton = new QPushButton(tr("Продолжить"), this);
QPushButton *cancelButton = new QPushButton(tr("Отмена"), this);
int iWidthButton = 200;
int iHeightButton = 50;
okButton->setGeometry(QRect(600, 440, iWidthButton, iHeightButton));
cancelButton->setGeometry(QRect(360, 440, iWidthButton, iHeightButton));
okButton->setDefault(true);

// Сигналы
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));

// Сообщение
messageLabel = new QLabel(this);
messageLabel->setPalette(whitePalette);
messageLabel->setGeometry(QRect(340, 260, 480, 160));
messageLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
messageLabel->setWordWrap(true);
messageLabel->setFont(tahomaFont);
messageLabel->setText(tr("Текст сообщения"));
}

MDialog::~MDialog()
{
hide();
}

int MDialog::result() const
{
Q_D(const QDialog);
return d->rescode;
}

void MDialog::setResult(int r)
{
Q_D(QDialog);
d->rescode = r;
}

int MDialog::exec()
{
Q_D(QDialog);
if (d->eventLoop)
return -1;

bool deleteOnClose = testAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_DeleteOnClose, false);

setResult(0);

show();

QEventLoop eventLoop;
d->eventLoop = &eventLoop;
(void) eventLoop.exec();
d->eventLoop = 0;

int res = result();
if (deleteOnClose)
delete this;
return res;
}

void MDialog::done(int r)
{
Q_D(QDialog);
hide();
setResult(r);
d->close_helper(QWidgetPrivate::CloseNoEvent);
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();

if (d->eventLoop)
d->eventLoop->exit();
}

void MDialog::accept()
{
done(Accepted);
}

void MDialog::reject()
{
done(Rejected);
}


и хидер:

Код:
#include <QtGui>
#include <QWidget>
#include <QPixmap>

QT_BEGIN_HEADER

QT_MODULE(Gui)

class QDialogPrivate;

class MDialog : public QWidget
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QDialog)

public:
enum DialogCode { Rejected, Accepted };

MDialog::MDialog(QWidget *parent = 0, Qt::WFlags flags = 0);
MDialog::~MDialog();
int result() const;
void setResult(int r);

signals:
void finished(int result);
void accepted();
void rejected();

public slots:
int exec();
void done(int r);
void accept();
void reject();

private:
Q_DISABLE_COPY(MDialog)
};

QT_END_HEADER


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 14:10
А что за ошибка-то?


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 14:16
Цитировать
test.exe - обнаружена ошибка. Приложение будет закрыто. Приносим извинения за неудобства.
Если работа была не закончена, рабочие данные могут быть утеряны.
Отправить отчет. Не отправлять отчет.

 :(
Вот такая ошибка.

подпись ошибки:
Цитировать
AppName: test.exe    AppVer: 0.0.0.0    ModName: qtcored4.dll
ModVer: 4.1.4.0    Offset: 0010d69a


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 14:20
Попробуй отдебажить.


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 14:34
:) хм
как-то ошибка не постоянно выскакивает, раз 30-50 щелкнешь на кнопке, и вылетает, причем все приложение.


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 14:38
Есть предположение, что у тебя память где-то течет...

Можешь вывесить метод, в котором у тебя создается/вызывается этот диалог?


Название: Модальный диалог
Отправлено: enola от Сентябрь 12, 2006, 15:11
без проблем:
Код:

MDialog *message = new MDialog(this);

        int i = 0;
if(message->exec())
i = 1;
else
i = 2;

if (message)
delete message;


добавлено спустя 24 минуты:

 похоже нашел где ошибка, у меня неправильно работает eventLoop, вот здесь отваливается:
Код:

int MDialog::exec()
{
Q_D(QDialog);
if (d->eventLoop)
{
return -1;
}
.....


возвращает -1 и все после этого диалог не показывается вообще, сколько не тыкай по кнопке. Все дело в том что я сократить решил код QDialog и вот здесь добавил свой код:
Код:

void MDialog::done(int r)
{
Q_D(QDialog);
hide();
setResult(r);
d->close_helper(QWidgetPrivate::CloseNoEvent);
emit finished(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();

if (d->eventLoop) // Вот это добавил я
d->eventLoop->exit(); // это тоже
}


Как мне этот eventLoop самому "сотворить"?


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 12, 2006, 16:32
Во-первых, не смог осилить, зачем в деструкторе hide()?
Во-вторых, для создания своего объекта QEventLoop надо отказаться от макросов Q_DECLARE_PRIVATE и Q_D.


Название: Модальный диалог
Отправлено: enola от Сентябрь 13, 2006, 06:31
Цитировать
Во-первых, не смог осилить...

Непонял интонацию данного высказывания, это я не осилил или ты. Если ты имел ввиду меня, то у меня уже получилось :)
А вообще большое спасибо за помощь.  :lol:
Вот как у меня работает:
Код:

MDialog::MDialog(QWidget *parent, Qt::WFlags flags)
: QWidget(parent, flags | QFlag(Qt::WA_ShowModal) |   // Модальное
 QFlag(Qt::FramelessWindowHint))  // Без заголовка, без кнопки на таскбаре
{
// Размер
MDialog::setGeometry(QRect(0, 0, 1024, 768));

// Фон
QPixmap bgPixmap("message.png");
QLabel *bgLabel = new QLabel(this);
bgLabel->setPixmap(bgPixmap);

// Кнопки
QPushButton *okButton = new QPushButton(tr("Продолжить"), this);
QPushButton *cancelButton = new QPushButton(tr("Отмена"), this);
// Настройка
int iWidthButton = 200;
int iHeightButton = 50;
okButton->setGeometry(QRect(600, 440, iWidthButton, iHeightButton));
cancelButton->setGeometry(QRect(360, 440, iWidthButton, iHeightButton));
okButton->setDefault(true);

// Сигналы
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
}

MDialog::~MDialog()
{

}

int MDialog::result() const
{
return iResult;
}

void MDialog::setResult(int r)
{
iResult = r;
}

int MDialog::exec()
{
// Установка результата по умолчанию
setResult(0);

// Показать
show();

// Ожидание
(void) eventLoop.exec();

// Возврат результата
return result();
}

void MDialog::done(int r)
{
// Скрыть
hide();

// Установка результата
setResult(r);
if (r == Accepted)
emit accepted();
else if (r == Rejected)
emit rejected();

// Выход из ожидания
eventLoop.exit();
}

void MDialog::accept()
{
done(Accepted);
}

void MDialog::reject()
{
done(Rejected);
}


Название: Модальный диалог
Отправлено: bigirbis от Сентябрь 13, 2006, 08:51
Цитировать
Непонял интонацию данного высказывания

Это я не смог осилить. :)
А в общем, вроде ничего так код получился в итоге. :)