Linux下QT實現自定義對話框以及設置模態和非模態對話框

最近使用QT做畢業設計,其中用到了對話框,但系統默認的對話框不能滿足我的需求,於是決定自己來封裝一個,這需要根據QT提供的QDialog基類來建立,以下附上頭文件及實現文件,已測試通過。

#ifndef MYRMDIALOG_H
#define MYRMDIALOG_H

#include <QDialog>
#include <QCheckBox>
#include <QDateTimeEdit>
#include <QDateEdit>
#include <QTimeEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>

class MyRmDialog : public QDialog
{
    Q_OBJECT
public:
    MyRmDialog(QWidget *parent = 0);
private:
    QDateTimeEdit *dateTimeEdit;
    QDateEdit *dateEdit;
    QTimeEdit *timeEdit;
    QCheckBox *everyDay;
    QPushButton *dateBtn;
    QPushButton *timeBtn;
    QPushButton *okBtn;
    QPushButton *cancelBtn;
    QHBoxLayout *editLayout;
    QHBoxLayout *spinLayout;
    QHBoxLayout *btnLayout;
    QVBoxLayout *mainLayout;
private slots:	
   void dateClicked();
   void timeClicked();  
   void okClicked();
   void cancelClicked();
   void timeoutslot();

};

#endif // MYRMDIALOG_H
.cpp

#include "MyRmDialog.h"
#include <QTextCodec>
#include <QTimer>
MyRmDialog::MyRmDialog(QWidget *parent) :

    QDialog(parent)
{

    QTextCodec::setCodecForTr(QTextCodec::codecForName("gbk"));
    setWindowTitle(tr("編輯提醒"));
    dateTimeEdit=new QDateTimeEdit;
    dateTimeEdit->setDate(QDate::currentDate());
    dateTimeEdit->setTime(QTime::currentTime());
    
    dateEdit=new QDateEdit(QDate::currentDate());
    timeEdit=new QTimeEdit(QTime::currentTime());
    dateEdit->setReadOnly(true);
    timeEdit->setReadOnly(true);
    dateBtn = new QPushButton(tr("設置日期"));
    connect(dateBtn,SIGNAL(clicked()),this,SLOT(dateClicked()));

    timeBtn = new QPushButton(tr("設置時間"));
    connect(timeBtn,SIGNAL(clicked()),this,SLOT(timeClicked()));
    
    everyDay=new QCheckBox;
    everyDay->setText(tr("每天提醒"));
    everyDay->setChecked(true); //默認爲每天提醒
    
    okBtn=new QPushButton(tr("確定"));
    connect(okBtn,SIGNAL(clicked()),this,SLOT(okClicked()));
    
    cancelBtn=new QPushButton(tr("取消"));
    connect(cancelBtn,SIGNAL(clicked()),this,SLOT(cancelClicked()));
    
    editLayout = new QHBoxLayout;
    spinLayout = new QHBoxLayout;
    btnLayout=new QHBoxLayout;
    mainLayout=new QVBoxLayout;
    editLayout->setSpacing(60);
    editLayout->addWidget(dateBtn);
    editLayout->addWidget(timeBtn);
    spinLayout->setSpacing(60);
    spinLayout->addWidget(dateEdit);
    spinLayout->addWidget(timeEdit);

    btnLayout->setSpacing(60);
    btnLayout->addWidget(okBtn);
    btnLayout->addWidget(cancelBtn);
    mainLayout->setMargin(40);
    mainLayout->addWidget(dateTimeEdit);
    mainLayout->addLayout(editLayout);
    mainLayout->addLayout(spinLayout);
    mainLayout->addWidget(everyDay);
    mainLayout->addLayout(btnLayout);
    
    QTimer *timer=new QTimer(this);
    connect(timer,SIGNAL(timeout()),this,SLOT(timeoutslot()));
    setLayout(mainLayout);
    timer->start(1000);

}

void MyRmDialog::okClicked()

{
   dateEdit->setReadOnly(true);
   timeEdit->setReadOnly(true);
}

void MyRmDialog::cancelClicked()

{
	//這裏實現自己的事件

}

void MyRmDialog::dateClicked()

{
	dateEdit->setReadOnly(false);
	connect(dateEdit,SIGNAL(dateChanged(QDate)),dateTimeEdit,SLOT(setDate(QDate)));
}
void MyRmDialog::timeClicked()

{
	timeEdit->setReadOnly(false);
	connect(timeEdit,SIGNAL(timeChanged(QTime)),dateTimeEdit,SLOT(setTime(QTime)));
}
void MyRmDialog::timeoutslot()

{

	QDate date=dateTimeEdit->date();
	QTime time=dateTimeEdit->time();
	QTime time1(23,59,59);
	if(time == time1)
		date = date.addDays(1);
	time = time.addSecs(1);
	dateTimeEdit->setDate(date);
	dateTimeEdit->setTime(time);

}

          對話框分爲模態對話框和非模態對話框。所謂模態對話框,就是會阻塞同一應用程序中其它窗口的輸入。模態對話框很常見,比如“打開文件”功能。你可以嘗試一下記事本的打開文件,當打開文件對話框出現時,我們是不能對除此對話框之外的窗口部分進行操作的。與此相反的是非模態對話框,例如查找對話框,我們可以在顯示着查找對話框的同時,繼續對記事本的內容進行編輯。

Qt 支持模態對話框和非模態對話框。其中,Qt 有兩種級別的模態對話框:應用程序級別的模態和窗口級別的模態,默認是應用程序級別的模態。應用程序級別的模態是指,當該種模態的對話框出現時,用戶必須首先對對話框進行交互,直到關閉對話框,然後才能訪問程序中其他的窗口。窗口級別的模態是指,該模態僅僅阻塞與對話框關聯的窗口,但是依然允許用戶與程序中其它窗口交互。窗口級別的模態尤其適用於多窗口模式,更詳細的討論可以看以前發表過的文章

 Qt 使用 QDialog::exec() 實現應用程序級別的模態對話框,使用 QDialog::open() 實現窗口級別的模態對話框,使用 QDialog::show() 實現非模態對話框。模態對話框即當對話框出現時,我們不能與主窗口進行任何交互,直到我們關閉了該對話框。

void MainWindow::open()
{
    MyRmDialog dialog(this);
    dialog.setWindowTitle(tr("Hello, dialog!"));  
    dialog->setModal(true);
    dialog.show();
}
是不是事與願違?對話框竟然一閃而過!這是因爲,show() 函數不會阻塞當前線程,對話框會顯示出來,然後函數立即返回,代碼繼續執行。注意,dialog 是建立在棧上的,show() 函數返回,MainWindow::open() 函數結束,dialog 超出作用域被析構,因此對話框消失了。知道了原因就好改了,我們將 dialog 改成堆上建立,當然就沒有這個問題了:

void MainWindow::open()
{
    QDialog *dialog = new QDialog;
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->setModal(true);
     dialog->show();
}
最後兩句也可直接用一句dialog->exec();

如果你足夠細心,應該發現上面的代碼是有問題的:dialog 存在內存泄露!dialog 使用 new 在堆上分配空間,卻一直沒有 delete。解決方案也很簡單:將 MainWindow 的指針賦給 dialog 即可。不過,這樣做有一個問題:如果我們的對話框不是在一個界面類中出現呢?由於 QWidget 的 parent 必須是 QWidget 指針,那就限制了我們不能將一個普通的 C++ 類指針傳給 Qt 對話框。另外,如果對內存佔用有嚴格限制的話,當我們將主窗口作parent 時,主窗口不關閉,對話框就不會被銷燬,所以會一直佔用內存。在這種情景下,我們可以設置 dialog 的 WindowAttribute:

void MainWindow::open()
{
    QDialog *dialog = new QDialog;
    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->setWindowTitle(tr("Hello, dialog!"));
    dialog->show();
}
setAttribute() 函數設置對話框關閉時,自動銷燬對話框。另外,QObject 還有一個 deleteLater() 函數,該函數會在當前事件循環結束時銷燬該對話框(具體到這裏,需要使用 exec() 開始一個新的事件循環)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章