qt第三章

窗口部件

QT 提供的默认基类有

  • QMainWindow: 带有菜单栏和工具栏的主窗口类
  • QDialog: 各种对话框的基类
  • QWidget: QMainWindow和QDialog都继承自QWidget
    在这里插入图片描述

3.1 基础窗口组件QWidget

QWidget类是所有用户界面对象的基类,被称为基础窗口部件。
图3-1中,

  • QWidget继承自QObject类和QPaintDevice类。
  • QObjct类是所有支持Qt对象模型(QtObjectModel)的对象的基类。
  • QPaintDevice类是所有可以绘制的对象的基类。

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

1 窗口、子部件、窗口类型
  1. 创建一个空的qmake项目(其他项目➡Empty qmake Project)
  2. 往项目中添加C++源文件mian.cpp,代码如下
#include <QtWidgets>
// 头文件QtWidgets中包含QApplication、Qwidget、QLabel类


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // 新建QWidget类对象,默认parent参数是0,所以它是个窗口

    QWidget *widget = new QWidget(0, Qt::Dialog | Qt::FramelessWindowHint);
    //  Qt::FramelessWindowHint: 用于产生一个没有边框的窗口
    //  QWidget *widget = new QWidget();  //窗口固定,右上角有边框,有×号,窗口大小可能容纳不了

    //构造函数QWidget有两个参数:QWidget * parent = 0和Qt:: WindowFlags f = 0,
    //前面的parent指父窗口部件,默认值为0,表明没有父窗口;
    //而后面的f参数是Qt::WindowFlags类型的,是Qt:: WindowType枚举类型值的或组合。Qt:: WindowType枚举类型用来为部件指定各种窗口系统属性,比如f=0表明窗口类型的值为Qt:: Widget,这是QWidget的默认类型,这种类型的部件如果有父窗口,那么它就是子部件,否则就是独立窗口
    //Qt:: WindowType包括了很多类型,下面演示其中的Qt:: Dialog和Qt:: Splash-Screen,更改程序中新建对象的那两行代码:


    //QWidget *widget = new QWidget(0, Qt::Dialog)
    //QLabel *label = new QLabel(0, Qt::SplashScreen


    // 设置窗口标题
    widget->setWindowTitle(QObject::tr("我是widget"));

    // 新建QLabel对象,默认parent参数是0,所以它是个窗口
    QLabel *label = new QLabel(0, Qt::SplashScreen | Qt::WindowStaysOnTopHint);
    // WindowStaysOnTopHint: 使该窗口停留在所有窗口的上面

    //设置窗口标题
    label->setWindowTitle(QObject::tr("我是label"));

    // 设置要显示的信息
    label->setText(QObject::tr("label:我是个窗口"));

    // 改变部件大小,以便能显示出完整的内容
    label->resize(180, 20);
    // label2指定了父窗口为widget,所以不是窗口

    QLabel *label2 = new QLabel(widget);//label2继承了widget
    label2->setText(QObject::tr("label2:我不是独立窗口,只是widget的子部件"));
    label2->resize(250, 20);
    // 在屏幕上显示出来
    label->show();
    widget->show();

    int ret = a.exec();
    delete label;
    delete widget;
    //label2也使用new进行空间分配,但没用delete进行销毁。
    //因为label2的父对象是widget,delete widget时自动销毁widget子对象。
    return ret;
}
  • 窗口部件(Widget)简称部件,是Qt中建立用户界面的主要元素。
  • 像主窗口、对话框、标签、还有以后要介绍到的按钮、文本输人框等都是窗口部件。
  • 这些部件可以接收用户输入、显示数据和状态信息,并且在屏幕上绘制自己。有些也可以作为一个容器来放置其他部件。
  • Qt中把没有嵌人到其他部件中的部件称为窗口,一般窗口都有边框和标题栏,就像程序中的widget和label一样。QMainWindow和大量的QDialog子类是最一般的窗口类型。
  • 窗口就是没有父部件的部件,所以又称为顶级部件(top-levelwid-get)。与其相对的是非窗口部件,又称为子部件(childwidget)。
  • 在Qt中大部分部件被用作子部件,嵌人在别的窗口中,如程序中的label2。这部分内容可以查看关键字 Qt Widgets和Window and Dialog Widgets。

QWidget提供了自我绘制和处理用户输人等基本功能,Qt提供的所有界面元素不是QWidget的子类就是与QWidget的子类相关联。要设计自己的窗口部件,可以继承白QWidoet或者是它的子类。

2 窗口几何布局

在这里插入图片描述

3 程序调试
  1. 断点调试
#include<QWidget>
#include<QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget widget;
    widget.show();//此处的窗口不会直接显示,
    //因为只有主程序进入主事件循环后才能接收事件,
    //show只是触发显示事件,只有在a.exec()调用进入消息循环后才显示。
    int x = widget.x(); //返回部件在父部件中的位置
    //定义变量却没有使用,所以int x有误
    int y = widget.y();
    QRect geometry = widget.geometry();//返回没有边框的窗口框架矩形
    QRect frame = widget.frameGeometry();//返回包含边框的窗口框架矩形
    return a.exec();
}
  1. 使用qDebug函数:将调试信息输出到控制台
#include<QWidget>
#include<QApplication>
#include<QDebug> //头文件

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget widget;
    widget.resize(400,300);  //设置窗口大小
    widget.move(200,100);  //设置窗口位置
    int x = widget.x();
    qDebug("x:%d",x);  //第一种方法
    //此处调用了x,int x无误。
    int y = widget.y();
    qDebug("y:%d",y);
    QRect geometry = widget.geometry();
    QRect frame = widget.frameGeometry();
    qDebug()<<"geo:"<<geometry<<"frame"<<frame;//第二种方法
    return a.exec();

}

3.2 对话框QDialog

  • QDialog类是所有对话框窗口类的基类。
  • 对话框窗口是一个经常用来完成短小任务或者和用户进行简单交互的顶层窗口。

3.2.1 模态的(modal)和非模态对话框

  • 按照运行对话框时是否还可以和该程序的其他窗口进行交互,对话框常被分为两类:模态的(modal)和非模态的(modeless)。

新建Qt Widgets应用,项目名称为mydialogl,基类选择QWidget,类名为MyWidget,然后在mywidget.cpp 文件中添加以下代码:

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDialog>

//在 MyWidget类的构造函数中定义了一个QDialog类对象,
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    QDialog dialog(this);
    dialog.show();
    //指定dialog父窗口为MyWidget类对象(即this参数的作用)
}

运行程序时就发现,一个窗口一闪而过,然后就只显示 MyWidget窗口了,为什么会这样呢?
因为对于一个函数中定义的变量,等这个函数执行结束后,它就会自动释放。也就是说,这里的dialog对象只在这个构造函数中有用,等这个构造函数执行完了, dialog 也就消失了。为了不让 dialog消失,可以将QDialog对象的创建代码更改如下:

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDialog>

//在 MyWidget类的构造函数中定义了一个QDialog类对象,
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    QDialog *dialog = new QDialog(this);
    //使用了QDialog对象的指针,并使用new运算符开辟了内存空间,再运行程序就可以正常显示了。
    dialog->setModal(true);
    dialog->show();
}
  • 定义一个对象是指QDialog dialog; 这样的方式,而像QDialog * dialog;这样不能被称为定义了一个对象,而是定义了一个指向QDialog类对象的指针变量。
  • 后面也会把“QDialog * dialog;”说成是定义了一个QDialog对象。
  • 这里为dialog对象指明了父窗口,所以就没有必要使用delete来释放该对象了,
    不用指针也可以显示对话框
QDialog dialog(this);
dialog.exec();
//运行程序时对话框弹出,但MyWidget窗口没出现,关闭对话框后才弹出。
//此处的对话框称为模态对话框。
  • 模态对话框就是在没有关闭它之前,不能再与同一个应用程序的其他窗口进行交互,比如新建项目时弹出的对话框。
  • 而对于非模态对话框,既可以与它交互,也可以与同一程序中的其他窗口交互,如 Microsoft Word中的查找替换对话框。
  • 要想使一个对话框成为模态对话框,则只需要调用它的exec()函数;而要使其成为非模态对话框,则可以使用new操作来创建,然后使用show()函数来显示。
  • 使用show()函数也可以建立模态对话框,只须在其前面使用setModal()函数即可。例如:
QDialog * dialog = new QDialog(this);
dialog->setModal(true);
dialog ->show();
//此时生成的对话框是模态的。

它与用exec()函数时的效果是不一样的,因为现在的MyWidget窗口也显示出来了。

  • 因为调用完show()函数后会立即将控制权交给调用者,程序可以继续往下执行。而调用exec()函数却不同,只有当对话框被关闭时才会返回。
  • 与setModal()函数相似的还有一个setWindow-Modality()函数,它有一个参数来设置模态对话框要阻塞的窗口类型,可以是Qt:NonModal(不阻塞任何窗口,就是非模态),Qt :: WindowModal(阻塞它的父窗口,所有祖先窗口以及它们的子窗口)或Qt::ApplicationModal(阻塞整个应用程序的所有窗口)。而setModal()函数默认设置的是ApplicationModal。
MyWidget::~MyWidget()
{
    delete ui;
}

3.2.2 多窗口切换

  • Qt中使用信号和槽机制来完成对象之间的协同操作。
  • 简单来说,信号和槽都是函数,比如单击窗口上的一个按钮后想要弹出一个对话框,那么可以将这个按钮的单击信号和自定义的槽关联起来,在这个槽中创建一个对话框并且显示它。这样,单击这个按钮时就会发射信号,进而执行槽来显示一个对话框。
    举例
    在设计模式中往界面添加一个Label和一个Push Button,在属性栏中将Push Button的objectName改为showChildButton,然后更改Label的显示文本为“我是主界面!”,更改按钮的显示文本为“显示子窗口”。然后回到编辑模式打开mywidget.h文件,在MyWidget类声明的最后添加槽的声明:
//槽用关键字slots修饰
public slots://表明槽可以在类外被调用
    void showChildDialog();

Qt Creator 设计了一个快速添加定义的方法:单击showChildDialog()槽,同时按下Alt+Enter键(也可以在函数上右击,在弹出的级联菜单中选择Refactor菜单项),会弹出在mywidget.cpp添加定选项,再次按下回车键Enter,编辑器便会转到mywidget.cpp文件中,并且自动创建showChildDialog()槽的定义,只需要在其中添加代码即可。这种方法也适用于先在源文件中添加定义,然后自动在头文件中添加声明的情况。
mywidget.cpp中代码为:

#include "mywidget.h"
#include "ui_mywidget.h"
#include <QDialog>

MyWidget::MyWidget(QWidget *parent) ://更改MyWidget的构造函数
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    connect(ui->showChildButton, &QPushButton::clicked,
            this, &MyWidget::showChildDialog);
    //四个参数:发射信号的对象、发射的信号、接收信号的对象、要执行的槽。
    //connect将按钮的单击信号clicked与新建的槽关联起来
    //connect是QObject类的函数,MyWidget继承自QObject,可以直接使用。
}

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

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

上述方法为手动关联,对于信号和槽的关联还有一种方法,叫自动关联。
自动关联就是将关联函数整合到槽命名中,比如前面的槽可以重命名为on_show-ChildButton_clicked(),就是由字符on、发射信号的部件对象名和信号名组成。这样就可以去掉connect()关联函数了,具体做法在下面介绍。
以下采用的项目源码路径;src103\3-5\mydialogl。打开 mywidget.cpp文件,在MyWidget类的构造函数中删除connect()函数,然后更改showChildDialog()槽的名字,Qt Creator中提供了一个快捷方式来更改所有该函数出现的地方,从而不再需要逐一更改函数名。先在showChildDialog上右击,在弹出的级联菜单中选择Refactor-→Rename Symbol Under Cursor,或者直接使用Ctrl+ Shift+R快捷键,在出现的替换栏中输入 on_showChildButton_clicked,再单击Replace就可以了。这时源文件和头文件中相应的函数名都进行了更改。现在运行程序,和前面的效果是一样的。
ldDialog()槽的名字,Qt Creator中提供了一个快捷方式来更改所有该函数出现的地方,从而不再需要逐一更改函数名。先在showChildDialog上右击,在弹出的级联菜单中选择Refactor-→Rename Symbol Under Cursor,或者直接使用Ctrl+ Shift+R快捷键,在出现的替换栏中输入 on_showChildButton_clicked,再单击Replace就可以了。这时源文件和头文件中相应的函数名都进行了更改。现在运行程序,和前面的效果是一样的。
对于这两种关联方式,后一种形式很简便,用Qt设计器直接生成的槽就是使用这种方式。不过,对于不是在Qt设计器中往界面上添加的部件,就要在调用setupUi)函数前定义该部件,而且还要使用setObjectName()函数指定部件的对象名,这样才可以使用自动关联。在编写程序时一般都使用第一种connect方式。信号和槽在第7章还会深入讲解。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值