第三章窗口部件

-3.1基础窗口部件QWidget

Qt creator提供的默认类型只有QMainWindow、QWidget、QDialog三种。 其中QMainWindow是带有菜单栏和工具栏的主窗口类,QDialog是各种对话框的基类,他们全部继承自QWidget,不仅如此,其实所有的窗口部件都继承自QWidget。

-3.1.1窗口、子部件以及窗口类型

1.窗口与子部件 例子1,创建空的qmake项目


    //mywidget1.pro
    greaterThan(QT_MAJOR_VERSION, 4):QT +=widgets

    SOURCES += \
    main.cpp
    //============
    //main.cpp
        #include"QtWidgets"

    int main(int argc, char* argv[])
    {
        QApplication a(argc, argv);
        QWidget *widget = new QWidget(); //新建QWidget类对象,默认parent参数是0,所以他是个窗口
        widget->setWindowTitle(QObject::tr("我是widget"));

        QLabel *label = new QLabel();   //新建QLabel类,默认parent参数为0
        label->setWindowTitle(QObject::tr("我是label"));
        label->setText(QObject::tr("label:我是窗口"));  //设置显示的信息
        label->resize(180, 20);

        QLabel * label2 = new QLabel(widget);
        label2->setText(QObject::tr("label2:我不是独立窗口,只是widget的子窗口"));
        label2->resize(250, 20);

        label->show();
        widget->show();

        int ret = a.exec();
        delete label;
        delete widget;
        return ret;
    }

    /*
    结果:
    显示两个窗口。
    */

2.窗口类型 QWidget的构造函数有两个参数:QWidget *parent = 0Qt::WindowFlags f=0,前面的parent指父窗口部件,默认值为0,表明没有父窗口;而后面的f参数是Qt::WindowFlags类型的,是Qt::WindowFlags枚举类型值得或组合,指明各种窗口系统类型属性;f=0为Qt::widget,其他还有:Qt::DialogQt::SplashScreen 于是将上面的代码中的两行改成这样:


    QWidget *widget = new QWidget(0, Qt::Dialog);   //对话框
    Qlabel *label = new label(0, Qt::SplashScreen`);//欢迎窗口

3.再次更改:


    QWidget *widget = new QWidget(0, Qt::Dialog | Qt::FramelessWindowHint); 
    Qlabel *label = new label(0, Qt::SplashScreen`);
    //Qt::FramelessWindowHint 用来产生一个没有边框的窗口,而Qt::WindowStaysTopHint用来使该窗口停留在其他窗口上面。

4.补充:QWidget中还有一个setWindowState()函数用来设置窗口的状态,其参数由Qt::WindowState枚举类型值得或组合。


    Qt::WindowMaxmized---最大化
    Qt::WindowMinmized---最小化
    Qt::WindowFullScreen---全屏显示
    Qt::WindowActive---活动窗口
    默认是Qt::WindowNostate

-3.1.2窗口几何布局

-3.1.3程序调试

  1. 程序自带,
  2. 使用qDebug()函数qDebug() << xxx,使用之前要在前面添加#include "QDebug"

-3.2 对话框QDialog

-3.2.1 模式和非模式对话框

QDialog类是所有对话框窗口类的基类。对话框窗口是一个经常用来完成短小任务或者和用户进行简单交互的顶层窗口。按照运行对话框时是否还可以和该程序的其他窗口进行交互,对话框经常被分为两类:模态的(model)和非模态的(modeless)。 例子_1讲解 创建基类为QWidget的工程,类名为MyWidget,然后在mywidget.cpp中添加如下代码:


#include "mywidget.h"
#include "ui_mywidget.h"
#include "QDialog"
myWidget::myWidget(QWidget *parent): QWidget(parent), ui(new Ui::myWidget)
{
    ui->setupUi(this);
    QDialog dialog(this);   //定义了一个parent为this的对象
    dialog.show();
}
myWidget::~myWidget()
{
    delete ui;
}

运行结果:有一个窗口一闪而过,显示MyWidget窗口,原因在于,dialog对象只是在这个构造函数中有用,等构造函数执行结束,dialog也会消失。为了不让dialog消失,可以改成如下代码:


QDialog *dialog = new QDialog(this); //定义了一个指向QDialog类对象的指针变量
dialog->show();

窗口一闪而过的现象消失了。原因分析:使用QDialog对象指针,并使用new运算符开辟了内存空间,再运行程序就可以正常显示了。 其实也可以不用指针也可以实现对话框显示:


QDialog dialog(this);
dialog.exec();

执行结果便是:对话框弹出来,而MyWidget窗口并没有,当关闭对话框窗口时,MyWidget窗口才出现。我们把这种对话框称为模态对话框,前面的称为非模态对话框。 完整定义: 模态对话框就是在关闭它之前,不能再与同一个应用程序的其他窗口进行交互。例如:新建项目的弹出对话框。 非模态对话框,既可以进行交互,也可以与同一程序中的其他窗口进行交互。


    QDialog *dialog = new QDialog(this);
    dialog->setModal(true);
    dialog->show();

执行结果分析:生成的对话框是模式的,但是,他与exec()函数时的效果是不一样的,因为现在MyWidget窗口也显示出来了。这是因为调用完show()函数后立即将控制权交给调用者,程序可以继续执行。而使用exec()函数不同,只有当对话框被关闭时才会返回。 与setModel()函数相似的还有:setWindowModality()函数,它有一个参数来设置模态对话框要阻塞的窗口类型,它可以是Qt::NonModel(不阻塞任何窗口,就是非模态)、Qt::WindowModel(阻塞他的父窗口,所有祖先窗口以及他们的子窗口)或者Qt::ApplicationModel(阻塞整个应用程序的所有窗口),默认为Qt::ApplicationModel

-3.2.2 多窗口切换

-1.认识信号和槽

认识:Qt中使用信号和槽机制来完成对象之间的协同操作。信号和槽都是函数,例如点击窗口上的一个按钮后想要弹出一个对话框,那么可以将这个按钮的点击信号和自定义的槽关联起来。 1.自己手写: 第一步:在窗口头文件中,这里是myWidget.h里面,类为mywidget,加入


public slots:
    void showChildDialog();

还有就是更改.ui文件,加入pushButton和Label 第二步:在窗口文件(非ui文件)中,这里是myWidget.cpp中加入,将槽函数进行外部定义


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

更改MyWidget类的构造函数,可以改成这样:


myWidget::myWidget(QWidget *parent) : QWidget(parent), ui(new Ui::myWidget)
{
    ui->setupUi(this);
    connect(ui->showChildButton, &QPushButton::clicked, this, &myWidget::showChildDialog);
}

关于connect()函数的说明解释: 第一个参数是:发射信号的对象 第二个参数是:发射的信号 第三个参数是:接收信号的 第四个参数是:要执行的槽 2.自定义对话框 文件结构为


mydialog.h
mywidget.h
main.cpp
mydialog.cpp
mywidget.cpp
mydialog.ui
mywidget.ui

这里先编辑dialog窗口,后编辑widget窗口 加入退出按钮 1. 在对应ui文件中进行修改,选中Edit Signal/Slots F4,左键选中,拖动到窗口界面上,这时松开鼠标左键,在弹出的配置连接对话框中选择“显示QWidget继承的信号和槽”选项,然后再左边的QpushButton栏中选择信号clicked(),在右边的QDialog栏中选择对应的槽close(),完成之后点击OK。 2. 进入主界面按钮的信号和槽的关联。左键选中,选择转到槽,进入代码编辑界面。一般是窗口.cpp文件。


void MyDialog::on_pushButton_clicked()
{
    accept();
}

这个accept()函数是QDialog类中的一个槽,对于exec()函数实现的模态对话框,执行了这个槽就会隐藏这个模态对话框,并返回QDialog::Accept值,这里就是要使用这个值来判断是哪个按钮被按下了。

  1. 主界面中使用自定义的对话框,更改main.cpp

#include "mywidget.h"
#include "mydialog.h"
#include "QDebug"

#include 

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    myWidget w;
    myDialog dia;
    if(dia.exec() == QDialog::Accepted){
        w.show();
        qDebug() << "正确_1";
        return a.exec();
    }
    else
        return 0;
}

双击mywidget.ui文件,在设计模式中加入两个Push Button,命名 重新登陆, 退出 重新登陆中加入:


void myWidget::on_pushButton_clicked()
{
    close();
    myDialog dlg;
    if(dlg.exec() == QDialog::Accepted){
        qDebug() << "正确_2";
        show();
    }
}

-3.2.3标准对话框

Qt提供了一些常见的对话框类型,他们全部继承自QDialog类,并增加了自己的特色功能,比如获取颜色、显示特定信息等。

-1.颜色对话框

第一步建立QWidgets,点击ui文件编辑,拖拽一个PushButton。 第二步,转到槽,进行如下编辑:


//先在文件头加入#include,#include
void myWidget::on_pushButton_clicked()
{
    QColor color = QColorDialog::getColor(Qt::red, this, tr("颜色对话框"));
    qDebug()<<"color: "<<color;
}

getColor()函数解释:第一个参数是设置默认值;第二个参数是设置parent值这里填this;第三个参数填标题,还有第四个参数,其他设置。例如加入:QColorDialog::ShowAlphaChannel,改变颜色值显示办法。

-2.文件对话框

第一步,如法炮制。 第二步,转到槽,改写槽函数


//在.cpp中添加#include "QFileDialog"
void myWidget::on_pushButton_2_clicked()
{
    QString fileName = QFileDialog::getOpenFileName(this,tr("文件对话框"),"D:",tr("图片文件(*png *jpg)"));
    qDebug() << "fileName: "<< fileName;
}

getOpenFileName()函数的解释:第一个参数是parent值;第二个参数是弹出框的标题,具体是点击按钮之后弹出窗口的标题;第三个标题是选择路径;第四个参数是选择文件类型,文件类型方面可以是多样性的,例如改其为:tr("图片文件(*png *jpg);;文本文件(*txt)");,中间用;;隔开。

选择多个文件 :将函数改成getOpenFileNames即可。还有获取文件路径:getExistingDirectory函数。

-3.字体对话框

第一步,如法炮制。 第二步,转到槽,改写槽函数。


//在.cpp文件中添加#include "QFontDialog"
void myWidget::on_pushButton_3_clicked(bool checked)
{
    QFont font = QFontDialog::getFont(&checked, this);
    if(checked)
        ui->pushButton_3->setFont(font);
    else
        qDebug() << tr("没有选择字体");
}

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

-4.输入对话框

第一步,如法炮制。 第二步,转到槽,改写槽函数。(在编写槽函数之前,先引入头文件#include "QInputDialog"


void myWidget::on_pushButton_4_clicked(bool checked)
{
    //------------------------------------------
    QString string = QInputDialog::getText(this, tr("输入字符串对话框"),                                      tr("请输入用户名"), QLineEdit::Normal, tr("admin"), &checked                                   );
    if (checked)
            qDebug() << "String: "<<string;
    //------------------------------------------
    int value1 = QInputDialog::getInt(this, tr("输入整数对话框"), tr("请输入-1000到1000之间的数值"),100, -1000, 1000, 1, &checked );
    if(checked)
        qDebug() << "value 1: "<<value1;
    //-------------------------------------------
    int value2 = QInputDialog::getDouble(this, tr("输入浮点数对话框"),tr("请输入-1000到1000之间的数"), 0.00, -1000, 1000, 1, &checked);
    if(checked)
        qDebug() << "value 2: "<< value2;
    //-------------------------------------------
    QStringList items;
    items << tr("条目1")<< tr("条目2");
    QString item = QInputDialog::getItem(this, tr("输入条目对话框"),tr("请选择或输入一个条目"),items, 0, true, &checked);
    if (checked)
        qDebug() << "items: "<< item;
}

这里getText()、getInt()、getDouble()、getItem()函数相似: 第一个参数是指定父窗口,第二个参数是设置窗口标题,第三个参数是设置对话框中的标签QLabel显示文本,第四个参数是设置输入的模式...。

-5.消息对话框

第一步,如法炮制。 第二步,转到槽,改写槽函数。(在编写槽函数之前,先引入头文件#include "QMessageBox"


void myWidget::on_pushButton_5_clicked()
{
    //问题对话框
    int ret_1 = QMessageBox::question(this, tr("问题对话框"),tr("你了解Qt吗?")
                                      ,QMessageBox::Yes, QMessageBox::No);
    if(ret_1 == QMessageBox::Yes)
        qDebug() << tr("问题!");
    else
        qDebug() << tr("没事!");

    //提示对话框
    int ret_2 = QMessageBox::information(this, tr("提示对话框"),tr("这是关于Qt的资料!"), QMessageBox::Yes, QMessageBox::No);
    if(ret_2 == QMessageBox::Yes)
        qDebug()<< tr("提示!");
    else
        qDebug()<<tr("没事2!");

    //警告对话框
    int ret_3 = QMessageBox::warning(this, tr("警告对话框"), tr("不能提前结束!"), QMessageBox::Abort);
    if(ret_3 == QMessageBox::Abort)
        qDebug() << tr("警告!");
    else
        qDebug() << tr("没事3!");

    //错误对话框
    int ret_4 = QMessageBox::critical(this, tr("严重错误对话框"), tr("发现一个严重错误!现在关闭所有文件!"), QMessageBox::YesAll);
    if(ret_4 == QMessageBox::YesAll)
        qDebug() << tr("错误!");

    //关于对话框
    QMessageBox::about(this, tr("关于对话框"),tr("这是我写的第一个对话框程序!"));
}

解释:这里建立了4个不同类型的消息对话框,分别拥有不同的图标和提示音(系统设置),几个参数分别用于设置父窗口,标题栏,显示信息,拥有的按钮。这几个静态函数的返回值就是那些标准按钮,由QMessageBox::StandardButton枚举指定。 about()函数没有返回值,默认只有一个按钮。

-6.进度对话框

第一步,如法炮制。 第二步,转到槽,改写槽函数。(在编写槽函数之前,先引入头文件#include "QProcessDialog"


void myWidget::on_pushButton_6_clicked()
{
    QProgressDialog dialog(tr("文件复制进度"), tr("取消"), 0, 50000, this);
    dialog.setWindowTitle(tr("进度对话框")); //设置窗口标题
    dialog.setWindowModality(Qt::WindowModal);  //将对话框设置为模态
    dialog.show();
    for(int i=0; i<50000; ++i)  //演示复制进度
    {
        dialog.setValue(i);     //设置进度条的当前值
        QCoreApplication::processEvents();      //避免界面冻结
        if( dialog.wasCanceled())               //按下取消按钮则中断
            break;
    }
    dialog.setValue(50000);         //这样才显示100%,因为for循环中少加一个数
    qDebug() << tr("复制结束!");
}

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

-7.错误信息对话框

错误信息对话框QErrorMessage类提供了一个显示错误信息的对话框。 1.首先打开myWidget.h文件添加类前置声明:class QErrorMessage; 然后添加私有对象:QErrorMessage * errordlg; 下面到mywidget.cpp中添加头文件#include "QErrorMessage",并在构造函数中添加errordlg = new QErrorMessage(this); 2.转到槽,设计模式下:


void myWidget::on_pushButton_7_clicked()
{
    errordlg->setWindowTitle(tr("错误信息对话框"));
    errordlg->showMessage(tr("这里是出错信息!"));
}

解释:这里首先建立一个QErrorMessage对话框,并且调用它的showMessage()函数来显示错误,调用函数时会以非模态的形式显示出来。错误信息对话框中默认有一个Show this message again复选框,可以选择是否显示。

-8.向导对话框

向导对话框QWizard类提供了一个设计向导界面的框架。对于向导对话框,例如在安装软件的时候,会有一个安装向导。QWizard之所以被称为框架,是 想要的效果。Qt中包含了Trival WizardLicense Wizardclass Wizard这3个实例程序。

打开myWidget.h文件,然后添加头文件#include "QWizard",在mywidget类的声明中添加private类型函数声明:


private:
    Ui::myWidget *ui;
    //
    QWizardPage *createPage1();
    QWizardPage *createPage2();
    QWizardPage *createPage3();

这里声明了3个返回值为QWizardPage类对象的指针函数,用来生成3个向导页面,然后在mywidget.cpp文件中添加对这3个函数进行定义:


QWizardPage * myWidget::createPage1()
{
    QWizardPage *page = new QWizardPage;
    page->setTitle(tr("介绍"));
    return page;
}
QWizardPage * myWidget::createPage2()
{
    QWizardPage *page = new QWizardPage;
    page->setTitle(tr("用户选择信息"));
    return page;
}
QWizardPage * myWidget::createPage3()
{
    QWizardPage *page = new QWizardPage;
    page->setTitle(tr("结束"));
    return page;
}

在各个函数中分别建立了向导页面,并且设置了他们的标题。下面转向“向导对话框”按钮的单击信号槽中,更改如下:


void myWidget::on_pushButton_8_clicked()
{
    QWizard wizard(this);
    wizard.setWindowTitle(tr("向导对话框"));
    wizard.addPage(createPage1());  //添加向导页面
    wizard.addPage(createPage2());
    wizard.addPage(createPage3());
    wizard.exec();
}

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

-3.3其他窗口部件

-3.3.1QFrame类族

QFrame类是带有边框的部件的基类。他的子类包括最常见的标签部件QLabel,另外还有QLCDNumber、QSplitter、QStackedWidget、QToolBox和QAbstractScrollArea类。 带边框部件最主要的特点就是可以有一个明显的边界框架。QFrame类的主要功能就是用来实现不同的边框效果,这主要是由边框形状(Shape)和边框阴影(Shadow)组合来形成。