Название: Новый класс на основе QDialog и память
Отправлено: Orfus от Февраль 10, 2011, 13:17
Доброго времени суток. Собственно встала следующая проблема. Необходимо вывести окошко (блокирующее все остальные виджеты приложения) и получить с него результат. Окно по типу: "вы уверены ...? Да-Нет". За родителя нового класса был выбран QDialog, по причине существования в нём такой вещи как exec(). Такое окно будет появлятся одновременно 1 на всё приложение (с разными текстом в различных случаях), но вызываться может десятки раз и поэтому чтобы не долбаться с потерей памяти я сделал его глобальным для всего приложения и получил следующую проблему. При первом вызове всё происходит гладко и красиво. При втором вызове, непонятно откуда происходит отрисовка окна, а уже после этого смена текста. Всё конечно работает, но косяк с таким мерцанием текста напрягает. header class MesBoxYesNo: public QDialog { Q_OBJECT
public: explicit MesBoxYesNo(); ~MesBoxYesNo();
topBar *tbar;// окно делается с 0. это полоска наверху с заголовком и кнопкой закрыть. QLabel *Label_text;//1 строка текста QLabel *Label_textunder;//2 строка текста QPushButton *But_yes;//кнопка Да QPushButton *But_no;//кнопка нет
QHBoxLayout *ButLayout; QVBoxLayout *MainLayout; int answer;//переменная которую будет возвращать окошко int winWidth,winHeight;//размеры окна protected: void paintEvent(QPaintEvent *event); public slots: void close();
//ниже слот вызова окна. проблема в нём. Его отработка запаздывает, наверно... int Question(QString question,QString question2,QString topbar_label,int width,int height);
void yes(); void no(); };
Вызов из другого cpp. Инициализация происходит в main.cpp. Сама же ссылка на переменную хранится в файле глобальных переменных, хедер которого я использую во многих местах. switch(MesBoxYN->Question(tr("Вы действительно хотите удалить?"), //1ая строка tr(""),//2ая строка tr("Удаление ")+this->tree_model->itemFromIndex(index)->text(),//текст в заголовке 250,//переменные размеров 100)) { case 1: { //some actions break; } case 0: { //some actions break; }
конструктор и слоты cpp MesBoxYesNo::MesBoxYesNo() :QDialog() { tbar =new topBar(this); Label_text =new QLabel(this); Label_textunder =new QLabel(this); But_yes = new QPushButton(tr("Ok"),this); But_no = new QPushButton(tr("Отмена"),this);
MainLayout = new QVBoxLayout(this); ButLayout = new QHBoxLayout(); ButLayout->setMargin(0); MainLayout->setMargin(0);
ButLayout->addWidget(But_yes,0,Qt::AlignLeft); ButLayout->addWidget(But_no,0,Qt::AlignRight);
But_yes->setObjectName("But_Standart"); But_no->setObjectName("But_Standart");
MainLayout->addWidget(tbar,0,Qt::AlignTop); MainLayout->addWidget(Label_text,0,Qt::AlignJustify); MainLayout->addWidget(Label_textunder,0,Qt::AlignJustify); MainLayout->addLayout(ButLayout);
connect(But_yes,SIGNAL(clicked()),this,SLOT(yes())); connect(But_no,SIGNAL(clicked()),this,SLOT(no())); connect(tbar->closeBut,SIGNAL(clicked()),this,SLOT(no())); this->setObjectName("MesBoxYesNo"); answer=0;
winWidth= 150; winHeight= 100;
this->setLayout(MainLayout);
this->setWindowFlags(Qt::FramelessWindowHint); this->setAttribute(Qt::WA_TranslucentBackground); this->setWindowModality (Qt::ApplicationModal); //this->setAttribute(Qt::WA_DeleteOnClose);//тут у меня были попытки уничтожать окно по закрытию. // но тогда правильный int возвращался через раз this->setStyleSheet(styles);//Глобальная переменная со стилями. this->hide(); qWarning()<<"MesBoxYesNo::MesBoxYesNo()"; } void MesBoxYesNo::paintEvent(QPaintEvent *event) { //вызов исходного метода QDialog::paintEvent( event ); //произвольные команды QStyleOption opt; opt.init(this); QPainter p(this); style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); qWarning()<<"MesBoxYesNo::paintEvent()"; } int MesBoxYesNo::Question(QString question,QString question2,QString tbar_label,int width=0,int height=0) {
qWarning()<<"MesBoxYesNo::Question() 01"; answer=0; tbar->TopLabel->setText(tbar_label); Label_text->setText(question); Label_textunder->setText(question2);
qWarning()<<"MesBoxYesNo::Question() 02"; if(width!=0) {winWidth=width;} if(height!=0) {winHeight=height;}
QDesktopWidget *d=QApplication::desktop(); int x=d->width(),y=d->height(); this->setGeometry((x-winWidth)/2,(y-winHeight)/2,winWidth,winHeight); qWarning()<<"MesBoxYesNo::Question() 03";
// qWarning()<<"answer first = "<<answer; // this->show(); setVisible( true ); //exec(); qWarning()<<"answer final = "<<answer; return answer; } //смена переменной на 1 и закрытие окна void MesBoxYesNo::yes() { answer = 1; close(); } //смена переменной на 0 и закрытие окна void MesBoxYesNo::no() { answer=0; close(); } //хоть close тут и стоит и даже отрабатывается, но обнуления не происходит вообще... void MesBoxYesNo::close() { qWarning()<<"MesBoxYesNo::close() 01";
tbar->TopLabel->setText(""); Label_text->setText(""); Label_textunder->setText("");
tbar->TopLabel->clear(); Label_text->clear(); Label_textunder->clear(); qWarning()<<"MesBoxYesNo::close() 02"; QDialog::close(); } MesBoxYesNo::~MesBoxYesNo() { if(tbar){tbar=0;delete tbar;} if(Label_text){Label_text=0;delete Label_text;} if(Label_textunder){Label_textunder=0;delete Label_textunder;} if(But_no){But_no=0;delete But_no;} if(But_yes){But_yes=0;delete But_yes;} if(ButLayout){ButLayout=0;delete ButLayout;} if(MainLayout){MainLayout=0;delete MainLayout;}
}
Вопрос в том как избавится от мерцания и почему оно вообще рисуется до exec()? Без exec() оно либо не рисуется вообще, либо закрывается моментально и я не успеваю его заметить. Альтернативный способ борьбы на мой взгляд: 1) Долбаться с локальными переменными окна и делать delete в конце метода с ним. Я честно говоря мало понимаю в распределении памяти. Насколько мне было известно в конце метода переменные инициализированные в данном методе пропадают, но память выделенная под них остаётся замусоренной. Вопрос ещё в том правильно ли я это понял) 2) Отказаться от QDialog и ковырять в другом направлении (QWidget сигнал-слотовая структура) У меня были изначально попытки разобраться с setEnabled(false) для блокирования остальной части приложения, но я предпочёл перейти к QDialog.
Название: Re: Новый класс на основе QDialog и память
Отправлено: UVV от Февраль 10, 2011, 13:24
Почему бы просто не воспользоваться QMessageBox?
Название: Re: Новый класс на основе QDialog и память
Отправлено: Пантер от Февраль 10, 2011, 13:26
Какой кошмар. :) Советую попробовать начать сначала и все обдумать. ;)
Название: Re: Новый класс на основе QDialog и память
Отправлено: Orfus от Февраль 10, 2011, 13:43
Почему бы просто не воспользоваться QMessageBox?
Стандартная отрисовка выбивается из стиля. Тем более он тоже от диалога наследуется и боюсь проблемы будут те же. :-\ Какой кошмар. :) Советую попробовать начать сначала и все обдумать. ;)
Что большего всего ужаснуло? :D
Название: Re: Новый класс на основе QDialog и память
Отправлено: Пантер от Февраль 10, 2011, 13:44
Orfus, подход к решению задачи, так как код не парсил, "многабукф".
Как уже посоветовали, используй QMessageBox.
Название: Re: Новый класс на основе QDialog и память
Отправлено: Orfus от Февраль 11, 2011, 14:30
Собственно говоря проблема как оказалось даже не в QDialog. Данный косяк проявляется во всём приложении.... :-[ Например в дереве: первой строкой каждого метода я разместил qWarning() с названием метода. Ну примерно так: C++ (Qt) void SelectGroupWindow::show() { qWarning()<<"SelectGroupWindow::show()"; QWidget::show(); } void SelectGroupWindow::Show() { qWarning()<<"SelectGroupWindow::Show()"; tree->tree_model->clear(); currentNode=new QStandardItem(QDir::toNativeSeparators(Dir_Groups)); currentNode->setEditable(false); tree->tree_model->appendRow(currentNode); tree->RefreshNode(currentNode->index()); tree->expand(currentNode->index()); this->show(); }
Получил следующий список: SelectGroupWindow::SelectGroupWindow() //конструктор SelectGroupWindow::Hide() //очистка и затем hide окна
//далее я вызываю окно в первый раз по нажатию на некую кнопку SelectGroupWindow::Show() //Смена некоторых значений и show() в конце SelectGroupWindow::ButtonsEnD() // Disable/enable некоторых кнопок SelectGroupWindow::show() //отображение окна SelectGroupWindow::ButtonsEnD() // Disable/enable некоторых кнопок
//далее окно прячется по нажатию на кнопку SelectGroupWindow::Hide() //очистка и затем hide окна
//вот тут проблема :( SelectGroupWindow::Show() //Смена некоторых значений и show() в конце SelectGroupWindow::ButtonsEnD() // Disable/enable некоторых кнопок SelectGroupWindow::ButtonsEnD() // Disable/enable некоторых кнопок SelectGroupWindow::show() //собственно показ окна
В первый раз после инициализации всё происходит замечательно. Но в каждый следующий сначала окно показывается, а только после этого очищает некоторые старые значения и строит новые и в то же время я вижу в дебаггере что метод Show() производящий очистку вызывается раньше чем show() производящий показ. Ума не приложу чем может быть вызвано. ???
Название: Re: Новый класс на основе QDialog и память
Отправлено: Etud от Февраль 11, 2011, 19:41
Надо начать с НУЛЯ
и все переписать...
А память тут при чем ?
Название: Re: Новый класс на основе QDialog и память
Отправлено: Orfus от Февраль 14, 2011, 11:22
Надо начать с НУЛЯ
и все переписать...
А память тут при чем ?
Не особо радует писать всё с 0.. но видимо придётся. Я слабо понимаю как используется память, но предполагаю что единожды созданное окно в котором меняют некотрые значения, работает быстрее (отрисовывается) и занимает меньше памяти чем постоянно создаваемые с 0. Собственно говоря даже если объёмы памяти останутся теми же и не будет никаких утечек, процесс создания окна с 0 займёт больше времени чем смены значений пары QLabel. Или я не прав? А касательно мерцания, дело то было в parent. Если я создавал новый виджет без parent он сначала показывал себя старого, а потом перерисовывался. Если же ему делать родителем главное окно то он сразу всё верно отображал.
|