2.窗口部件-对话框QDialog

1.模态和非模态

 

 

看代码 widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //指定父类窗口 widget
    QDialog dialog(this);
    dialog.show();
    // 这样运行会一闪而过,因为dialog 是函数中的一个变量,函数运行结束自动将变量回收.
    //为了不让变量释放,开辟一个内存空间
    QDialog *ql = new QDialog(this);
    //可以用setModal()函数默认设置的是Qt::ApplicationModal.
    dialog.setModal(true);
    ql->show();

    //还有方法 就是  调用 exec()函数让程序阻塞.
     dialog.exec();
    //此刻运行会有对话弹出但是widget窗口并有出来,当关闭对话框后 widget 才会弹出来. 这种称为模态对话框
    //只需调用exec() 就可变成模态对话框
    //模态对话框就是在这个窗口关闭前本应用程序不能再与其他窗口进行交互.
    //非模态对话框即使打开对话框本不会影响本应用于其他窗口交互.

}

Widget::~Widget()
{
    delete ui;
}

 

运行程序后可以看到,生成的对话框是模态的。但是,它与用exec()函数时的效果是不一样的,因为现在的MyWidget窗口也显示出来了。这是因为调用完show()函数后会立即将控制权交给调用者,程序可以继续往下执行。而调用exec()函数却不同,只有当对话框被关闭时才会返回。与setModal()函数相似的还有一个setWindow-Modality()函数,它有一个参数来设置模态对话框要阻塞的窗口类型,可以是Qt∶∶NonModal(不阻塞任何窗口,就是非模态)、Qt∶∶∶WindowModal(阻塞它的父窗口、所有祖先窗口以及它们的子窗口)或Qt∶∶ApplicationModal(阻塞整个应用程序的所有窗口)。而 setModal()函数默认设置的是Qt∶∶ApplicationModal。

2.多窗口切换  信号和槽

     Qt中使用信号和槽机制来完成对象之间的协同操作。简单来说,信号和槽都是函数,比如单击窗口上的一个按钮后想要弹出一个对话框,那么可以将这个按钮的单击信号和自定义的槽关联起来,在这个槽中创建一个对话框并且显示它。这样,单击这个按钮时就会发射信号,进而执行槽来显示一个对话框。下面来看一个例子。

双击widget.ui文件,在设计模式中往界面添加一个Label和一个Push Button,在属性栏中将Push Button的objectName 改为showChildButton,然后更改Label的显示文本为“我是主界面!”,更改按钮的显示文本为“显示子窗口”。然后回到编辑模式打开widget.h文件,

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    void showChildDialog();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect(ui->showChildButton,&QPushButton::clicked,[=](){
        showChildDialog();
    });
}


Widget::~Widget()
{
    delete ui;
}

void Widget::showChildDialog()
{
   QDialog *dialog = new QDialog(this);
   dialog->show();
}

以上是手动链接槽   在编写代码的一般会用 手动 connect

还有一种自动链接槽

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
public slots:
    void on_showChildButton_clicked();

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include<QDialog>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::on_showChildButton_clicked()
{
   QDialog *dialog = new QDialog(this);
   dialog->show();
}

运行程序和使用connect 函数一样.

1  on_showChildButton_clicked 这个名字很关键. pushButton 的名字必须是 showChildButton 或者 在pushButton 的ObjectName 加上 on_objectName_clicked 这样就能自动关联上了.

2.可以用 setObjectName() 指定部件对象名字

自定义对话框

第一种方法 

第一步,添加自定义对话类框。依然在前面的项目中更改。首先向该项目中添加Qt 设计师界面类。界面模板选择Dialog without Buttons,类名改为MyDialog。然后在设计模式中向窗口添加两个Push Button,并且分别更改其显示文本为“进入主界面”和“退出程序”。

第二步,设计信号和槽。这里使用设计器来实现“退出程序”按钮的信号和槽的关联.如下图 步骤2左键按住往下拖会弹出步骤三的界面 ,记得勾选最后点击ok 就关联完毕了. 最后点击按钮 7退出编辑.对应快捷键 F4, F3

 

 

 

 

 

 

 

 

 

 第二种方法:

现在设置“进入主界面”按钮的信号和槽的关联。在该按钮上右击,在弹出的级联菜单中选择“转到槽”,然后在弹出的对话框中选择 clicked()信号,并单击 OK 按钮。这时便会进入代码编辑模式,并且定位到自动生成的 on_btExit_clicked()槽中。在其中添加代码∶

 

点击 步骤1 右键弹出对话框 选择 转到槽.代码会自动创建出来 如下 可以在里面写想要的逻辑

 

void MyDialog::on_btExit_clicked()
{
    qDebug()<<"on btExit_clicked.........";
    //这个 accept()函数是QDialog类中的一个槽,对于一个使用exec()函数实现的模态对话框,执行了这个槽就会隐藏这个模态对话框,并返回QDialog∶∶Accepted值,这
    //里就是要使用这个值来判断是哪个按钮被按下了。与其对应的还有一个reject()槽,它可以返回一个QDialog∶∶Rejected值,前面的“退出程序”按钮也可以关联这个槽。
    
    
  // accept();
}

 

 

前面讲述了两种关联信号和槽的方法,第一种是直接在设计器中进行,这个更适合在设计器中的部件间进行。第二种方法是在设计器中直接进入相关信号的槽,这个与前面讲到的手写函数是一样的,它用的就是自动关联,这样也会在.h文件中自动添加该槽的声明,我们只须更改其实现代码就可以了。在以后的章节中,如果在设计器中添加的部件要使用信号和槽,那么都会使用第二种方法。

需要说明的是那个close()槽,它不一定使程序退出,只有当只剩下最后一个主界面了(就是没有父窗口的界面),这时调用close()槽,程序才会退出;而其他情况下界面只是隐藏起来了,并没有被销毁。

 3.标准对话框

Qt提供了一些常用的对话框类型,它们全部继承自QDialog类,并增加了自己的特色功能,比如获取颜色、显示特定信息等。下面简单讲解这些对话框,可以在帮助索引中查看Standard Dialogs关键字,也可以直接索引相关类的类名。

1. 颜色对话框

 

 

颜色对话框类QColorDialog提供了一个可以获取指定颜色的对话框部件。下面创建一个颜色对话框。先在mywidget.cpp文件中添加#include<QDebug>和#in-clude<QColorDialog>头文件,然后从设计模式进入"颜色对话框"按钮的clicked()单击信号槽。更改如void Widget::on_colorDialog_btn_clicked({

//颜色对话框中就是使用这种方法。其中,0表示颜色最浅,255表示颜色最深。在0~255与0.0~1.0之间可以通过简单的数学运算来对应,其中0对应0.0,255对应1.0。在颜色对话框中还可以添加对 alpha 的设置,
    //就是在 getColor()函数中再使用最后一个参数∶
   // QColor color = QColorDialog::getColor(Qt::red,this,tr("1颜色对话框1"));
    //这里使用了QColorDialog的静态函数getColor()来获取颜色,它的3个参数的作用分别是∶设置初始颜色、指定父窗口和设置对话框标题。
    //这里的Qt∶red是Qt预定义的颜色对象,可以直接单击该字符串,然后按下Fl查看其快捷帮助,或者在帮助索引中通过Qt∶∶GlobalColor关键字,
    //从而查看到所有的预定义颜色列表。getColor()函数返回一个QColor类型数据。现在运行程序,然后单击“颜色对话框”按钮,如果不选择颜色,
    //直接单击OK,那么输出信息应该是QColor(ARGB1,1,0,0),这里的4个数值分别代表透明度(alpha)、红色(red)、绿色(green)和蓝色(blue)。
    //它们的数值都是从0.0~1.0,有效数字为6位。对于alpha来说,1.0表示完全不透明,这是默认值,而0.0 表示完全透明。对于三基色红、绿、蓝的数值,还可以使用0~255来表示,
    //颜色对话框中就是使用这种方法。其中,0表示颜色最浅,255表示颜色最深。在0~255与0.0~1.0之间可以通过简单的数学运算来对应,其中0对应0.0,255对应1.0。在颜色对话框中还可以添加对 alpha 的设置,
    //就是在 getColor()函数中再使用最后一个参数∶
    //这里的QColorDialog∶∶ShowAlphaChannel用来显示alpha设置。可以运行程序查看效果。
    QColor color = QColorDialog::getColor(Qt::red,this,tr("1颜色对话框1"),QColorDialog::ShowAlphaChannel);
    qDebug()<<"color:"<<color;

}

前面使用了QColorDialog类的静态函数来直接显示颜色对话框,好处是不用创建对象。但是如果想要更灵活的设置,则可以先创建对象,然后进行各项设置

void Widget::on_colorDialog_btn_clicked()
{
    
    QColorDialog dialog(Qt::red,this);                               //创建对象
    dialog.setOption(QColorDialog::ShowAlphaChannel);                //显示alpha选项
    dialog.exec();                                                  //以模态形式运行对话框
    QColor color = dialog.currentColor();                           //获取当前选择的颜色
    qDebug()<<"color:"<<color;
}

2,文件对话框

 

 

文件对话框QFileDialog类提供了一个允许用户选择文件或文件夹的对话框。继续在mywidget.cpp中添加#include<QFileDialog>头文件,然后从设计模式转到"文件对话框"按钮的单击信号槽,并更改如下∶

void Widget::on_fileDialog_btn_clicked()
{
    QString filepath = QFileDialog::getOpenFileName(this,tr("file"),"D:",tr("图片文件(*png *jpg)"));
    qDebug()<<"fileName:"<<filepath;

    QStringList filepaths = QFileDialog::getOpenFileNames(this,tr("file"),"D:",tr("图片文件(*png *jpg)"));
            for (int i =filepaths.length();i<0;--i)
             {

                qDebug()<<"fileName:"<<filepaths[i];
             }
}

这里使用了QFileDialog类中的getOpenFileName()函数来获取选择的文件名,这个函数会以模态方式运行一个文件对话框。打开后选择一个文件,单击"打开"按钮后,这个函数便可以返回选择的文件的文件名。它的4个参数的作用分别是∶指定父窗口、设置对话框标题、指定默认打开的目录路径和设置文件类型过滤器。如果不指定文件过滤器,则默认选择所有类型的文件。这里指定了只选择png和jpg两种格式的图片文件(注意,代码中*png和*jpg之间需要一个空格),那么在打开的文件对话框中只能显示目录下这两种格式的文件。还可以设置多个不同类别的过滤器,不同类别间使用两个分号";;"隔开,例如,添加文本文件类型∶

运行程序就可以同时选择多个图片文件了,多个文件名存放在QStringList类型变量中。当然也可以不使用这些静态函数,而是建立对话框对象来操作。除了上面的两个函数外,QFileDialog类还提供了getSaveFileName()函数来实现保存文件对话框和文件另存为对话框,还有 getExistingDirectory()函数来获取一个已存在的文件夹路径。因为它们的用法与上面的例子类似,这里就不再举

 

 

3.字体对话框

 

 

字体对话框QFontDialog类提供了一个可以选择字体的对话框部件。先添加#include<QFontDialog>头文件,然后转到"字体对话框"按钮的单击信号槽,更改如下∶

 

void Widget::on_fontDialog_btn_clicked()
{
   //ok 用于标记Ok按钮
    bool ok =false;
    QFont font = QFontDialog::getFont(&ok,this);
    //如果单击ok按钮让字体对话框使用新的字体
    //如果单击cance按钮,那么输出信息
    if(ok)
    {
        ui->fileDialog_btn->setFont(font);

    }else
    {
        qDebug()<<"没有选择字体";
    }
}

这里使用了QFileDialog类的getFont()静态函数来获取选择的字体。这个函数的第一个参数是bool类型变量,用来存放按下的按钮状态,比如在打开的字体对话框中单击了OK按钮,那么这里的 ok 就为 true,这样来告诉程序已经选择了字体。

 

4. 输入对话框

 

 

 

 

 

输入对话框QInputDialog类用来提供一个对话框,可以让用户输入一个单一的数值或字符串。先添加头文件#include<QInputDialog>,然后进入"输入对话框"按钮的单击信号槽,更改如下∶

void Widget::on_inputDialog_btn_clicked()
{
     bool ok = false;

     QString str = QInputDialog::getText(this,tr("输入字符串对话框"),tr("请输入用户名:"),QLineEdit::Normal,tr("admin"),&ok);
     if(ok){
         qDebug()<<"string:"<<str;
     }
     //获取整数
     int value1 = QInputDialog::getInt(this,tr("ddddd"),tr("ddd"),0,-199999,1000,1,&ok);
     if(ok) qDebug()<< "valuel:"<< value1;//获取浮点数
     double value2 = QInputDialog::getDouble(this,tr("double"),tr("double"),0.00,-10000,10000,2,&ok);
     if(ok)qDebug()<<"value2:"<< value2;
     QStringList items;
     items << tr("条目1")<< tr("条目2");//获取条目
     QString item = QInputDialog::getItem(this,tr("dddd"),tr("dddhhh"),items,0,true,&ok);
     if(ok)qDebug()<<"item:"<< item;

}

 

这里一共创建了4个不同类型的输入对话框。getText()函数可以提供一个可输入字符串的对话框,各参数的作用分别是∶指定父窗口、设置窗口标题、设置对话框中的标签显示文本、设置输入字符串的显示模式(例如密码可以显示成小黑点,这里选择了显示用户输入的实际内容)、设置输入框中的默认字符串和设置获取按下按钮信息的bool变量;getInt()函数可以提供一个输入整型数值的对话框,其中的参数100表示默认的数值是100,一1000表示可输入的最小值是一1000,1000表示可输入的最大值是1000,10表示使用箭头按钮,数值每次变化10;getDouble()函数可以提供一个输入浮点型数值的对话框,其中的参数2表示小数的位数为2;getItemO函数提供一个可以输入一个条目的对话框,需要先给它提供一些条目,例如这里定义的QStringList类型的items,其中参数0表示默认显示列表中的第0个条目(0就是第一个),参数true 设置条目是否可以被更改,true就是可以被更改。这里使用了静态函数,不过也可以自己定义对象,然后使用相关的函数进行设置。

5. 消息对话框

 

 

 

 

 

 

消息对话框QMessageBox类提供了一个模态的对话框来通知用户一些信息,或者向用户提出一个问题并且获取答案。先添加头文件#include<QMessageBox>,然后转到“消息对话框”按钮的单击信号槽中,添加如下代码∶

 


void Widget::on_messageDialog_btn_clicked()
{
//问题对话框
int queston = QMessageBox::question(this,tr("question??"),tr("Are you see qt?"),QMessageBox::Yes,QMessageBox::No);
if(queston == QMessageBox::Yes){
qDebug()<<"i have a question!";
}else{
qDebug()<<"not a question";
}
//提示信息
int tips = QMessageBox::information(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::Ok);
if(tips == QMessageBox::Ok){
qDebug()<<"ok ok";
}
//警告信息

int warn = QMessageBox::warning(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::Abort);
if(tips == QMessageBox::Abort){
qDebug()<<"abort abort abort";
}
//错误信息
int error = QMessageBox::critical(this,tr("wolaile ??"),tr("niyao laima dddd?"),QMessageBox::YesAll);
if(tips == QMessageBox::YesAll){
qDebug()<<"yes yes yes";
}
//关于对话框
QMessageBox::about(this,tr("wolaile ??"),tr("niyao laima dddd?"));

}

这里创建了4个不同类型的消息对话框,分别拥有不同的图标还有提示音(这个是操作系统设置的),几个参数分别用于设置父窗口、标题栏、显示信息和拥有的按钮。这里使用的按钮都是QMessageBox类提供的标准按钮。这几个静态函数的返回值就是那些标准按钮,由QMessageBox∶StandardButton枚举类型指定,可以使用返回值来判断用户按下了哪个按钮。about()函数没有返回值,因为它默认只有一个按钮,与其相似的还有一个 aboutQt()函数,用来显示现在使用的 Qt 版本等信息。如果想使用自定义的图标和按钮,那么可以创建QMessageBox类对象,然后使用相关函数进行操作。

 

6.进度对话框

 

 

进度对话框QProgressDialog对一个耗时较长操作的进度提供了反馈。先添加#in-clude<QProgressDialog>头文件,然后转到"进度对话框"按钮的单击信号槽,更改如下∶

 

void Widget::on_progressDialog_btn_clicked()
{
     progress = new QProgressDialog(tr("myProgress"),tr("cancel "),0,100,this); //创建
    progress->setWindowTitle(tr("progess"));	//设置窗口标题
    progress->setWindowModality(Qt::WindowModal);//对话框设置为模态
    progress->show();//显示
    presss = 0;
    QTimer* timer = new QTimer();

    timer->start(500);
    timer->callOnTimeout([=](){
        qDebug()<<presss;
         this->progress->setValue(presss++);//设置进度条当前值
        QCoreApplication::processEvents(); //避免界面冻结
        if(progress->wasCanceled() || presss == 100){ //结束或者取消
            timer->stop();
            progress->cancel();
            }
    });

}

这里首先创建了一个QProgressDialog类对象dialog,构造函数的参数分别用于设置对话框的标签内容、取消按钮的显示文本、最小值、最大值和父窗口。然后将对话框设置为模态并进行显示。for()循环语句模拟了文件复制过程,setValue()函数使进度条向前推进为了避免长时间操作而使用户界面冻结,必须不断地调用QCoreApplica-tion类的静态函数 processEvents(),可以将它放在for()循环语句中。使用QPro-gressDialog的 wasCanceled()函数来判断用户是否按下了“取消”按钮,如果是,则中断复制过程。这里使用了模态对话框,QProgressDialog还可以实现非模态对话框,不过它需要定时器等的帮助。

 

7. 错误信息对话框

 

 

 

错误信息对话框QErrorMessage类提供了一个显示错误信息的对话框。首先打开mywidget.h文件添加类前置声明∶

    QErrorMessage *errMessage;

 


 errMessage = new QErrorMessage(this);

void
Widget::on_progressDialog_btn_2_clicked() { errMessage->setWindowTitle(tr("error message!")); errMessage->showMessage(tr("you are error.....")); }

这里首先新建了一个QErrorMessage对话框,并且调用它的showMessage()函数来显示错误信息,调用这个函数时对话框会以非模态的形式显示出来。错误信息对话框中默认有一个Show this message again复选框,可以选择以后是否还要显示相同错误信息;为了这个复选框的功能有效,不能像前面几个例子一样在槽中直接创建对话框。

8.向导对话框

 

 

向导对话框QWizard类提供了一个设计向导界面的框架。对于向导对话框,读者应该已经很熟悉了,比如安装软件时的向导和创建项目时的向导。QWizard之所以被称为框架,是因为它具有设计一个向导全部的功能函数,可以使用它来实现想要的效果。Qt中包含了Trivial Wizard、License Wizard和Class Wizard 这3个示例程序,可以参考一下。

打开mywidget.h文件,然后添加头文件#include<QWizard>,在MyWidget类的声明中添加private类型函数声明∶

    QWizardPage *createPage1();
    QWizardPage *createPage2();
    QWizardPage *createPage3();

.cpp 文件

 


QWizardPage *Widget::createPage1()//向导1

{

   QWizardPage * page = new QWizardPage(this);

   page->setTitle("介绍");

   return page;

}

QWizardPage *Widget::createPage2()//向导2

{



   QWizardPage * page = new QWizardPage(this);

   page->setTitle("用户选择信息");

   return page;

}

QWizardPage *Widget::createPage3()//向导3

{



   QWizardPage * page = new QWizardPage(this);

   page->setTitle("结束");

   return page;

}


void
Widget::on_progressDialog_btn_3_clicked() { QWizard wizard(this); wizard.setWindowTitle(tr("xiang dao dui hua kuang")); wizard.addPage(createPage1()); wizard.addPage(createPage2()); wizard.addPage(createPage3()); wizard.exec(); }

 

这里新建了QWizard类对象,然后使用addPage()函数为其添加了3个页面。这里的参数是QWizardPage类型的指针,可以直接调用生成向导页面函数。运行程序可以看到,向导页面出现的顺序和添加向导页面的顺序是一致的。

上面程序中的向导页面是线性的,而且什么内容也没有添加。如果想设计自己的向导页面,或添加图片、自定义按钮,或设置向导页面顺序等,那么就需要再多了解一下QWizard类和QWizardPage类。

 

posted @ 2022-08-30 16:57  摇摆的时钟  阅读(492)  评论(0编辑  收藏  举报