第3章 窗口部件
Qt提供了两种GUI开发方式:Qt Widgets和Qt Quick。Qt Widgets基于QWidget类,是所有窗口部件的基类,支持窗口、子部件、几何布局和边框样式设置等特性。QFrame类及其子类(如QLabel)可实现不同边框效果和文本/图片显示功能。按钮部件包括QPushButton、QCheckBox、QRadioButton等,支持文本、图标和菜单功能。这些基础部件为构建传统桌面应
Qt作为应用程序开发框架,为用户界面的开发和功能实现提供了丰富的部件和控件。对于Qt Widgets程序来说,窗口部件(Widgets)是图形用户界面(GUI)应用程序的基本构建块,而QWidget是所有窗口部件的基类;而对于Qt Quick程序,Qt Quick Controls模块提供了一组丰富的UI控件,基本覆盖了最常见的用例,可用于构建完整的应用界面。
3.1 Qt Widgets窗口部件
3.1.1 基础窗口部件QWidget
QWidget类是所有用户界面类的基类,被称为基础窗口部件,继承自QObject类和QPaintDevice类。其中,QObject类是所有支持Qt对象模型(Qt Object Model)的对象的基类,QPaintDevice类是所有可以绘制的对象的基类。
3.1.1.1 窗口与子部件
- 窗口部件是Qt中建立用户界面的主要元素。像主窗口、对话框、标签、还有按钮、文本输入框等都是窗口部件。这些部件可以接收用户输入,显示数据和状态信息,并且在屏幕上绘制自己。有些也可以作为一个容器来放置其他部件。
- Qt中把没有嵌入到其他部件中的部件称为窗口,一般窗口都有边框和标题栏。QMainWindow和大量的QDialog子类是最一般的窗口类型。窗口是没有父部件的部件,所以又称为顶级部件(top-level widget),与其相对的是非窗口部件,又称为子部件(child widget)。在Qt中大部分部件被用作子部件,嵌入在别的窗口中。
- 以下程序定义了一个QWidget类对象的指针widget和两个QLabel对象指针label与label2,其中label没有父窗口,而label2在widget中,widget是其父窗口。
QWidget *widget = new QWidget(); // 新建QWidget类对象,默认parent参数是nullptr,所以它是个窗口
widget->setWindowTitle(QObject::tr("我是widget")); // 设置窗口标题
QLabel *label = new QLabel(); // 新建QLabel对象,默认parent参数是nullptr,所以它是个窗口
label->setWindowTitle(QObject::tr("我是label"));
label->setText(QObject::tr("label:我是个窗口")); // 设置要显示的信息
label->resize(180, 20); // 改变部件大小,以便能显示出完整的内容
QLabel *label2 = new QLabel(widget); // label2指定了父窗口为widget,所以不是窗口
label2->setText(QObject::tr("label2:我不是独立窗口,只是widget的子部件"));
label2->resize(250, 20);
label->show(); // 在屏幕上显示出来
widget->show();

3.1.1.2 窗口类型
QWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
- QWidget的构造函数有两个参数:前面的parent就是指父窗口部件,默认值为nullptr,表明没有父窗口;
- 后面的f参数是Qt::WindowFlags类型的,它是Qt::WindowType枚举类型值的按位或组合。Qt::WindowType枚举类型用来为部件指定各种窗口系统属性,比如f=0表明窗口类型的值为Qt::Widget,这是QWidget的默认类型,这种类型的部件如果有父窗口,那么它就是子部件,否则就是独立窗口。
- 对于窗口标志Qt::WindowFlags,它主要的作用是更改窗口的标题栏和边框,可以是多个窗口类型枚举值进行按位或操作:
QWidget *widget = new QWidget(nullptr,Qt::Dialog | Qt::FramelessWindowHint); // Qt::FramelessWindowHint用来产生一个没有边框的窗口
QLabel *label = new QLabel(nullptr,Qt::SplashScreen | Qt::WindowStaysOnTopHint); // Qt::WindowStaysOnTopHint用来使该窗口停留在所有其它窗口上面。
- QWidget中还有一个setWindowState()函数用来设置窗口的状态,其参数由Qt::WindowStates指定,是Qt::WindowState枚举类型值的按位或组合。Qt::WindowState包括最大化Qt::WindowMaximized、最小化Qt::WindowMinimized、全屏显示Qt::WindowFullScreen和活动窗口Qt::WindowActive等,默认值为正常状态Qt::WindowNoState。
3.1.2 窗口几何布局
对于窗口的大小和位置,根据是否包含边框和标题栏两种情况,要用不同的函数来获取它们的数值。这里的函数分为两类,一类是包含框架的,一类是不包含框架的:
1)包含框架:x()、y()、frameGeometry()、pos()和move()等函数;
2)不包含框架:geometry()、width()、height()、rect()和size()等函数。
3.1.3 QFrame类族
QFrame类是带有边框的部件的基类。它的子类包括常用的标签部件QLabel,以及QLCDNumber、QSplitter、QStackedWidget、QToolBox和QAbstractScrollArea等类。其中QAbstractScrollArea类是所有带有滚动区域的部件类的抽象基类。QAbstractScrollArea的子类中包含常用的文本编辑器QTextEdit类和各种项目视图类。
- 带边框部件最主要的特点就是可以有一个明显的边界框架。QFrame类的一项主要功能就是用来实现不同的边框效果,这主要是由边框形状(Shape)和边框阴影(Shadow)组合来形成的。
- QFrame类中定义的主要边框形状包括QFrame::Box、QFrame::Panel、QFrame::StyledPanel、QFrame::HLine、QFrame::VLine和QFrame::WinPanel等。
- 边框阴影主要包括QFrame::Plain、QFrame::Raised和QFrame::Sunken等。
- 在设计模式从部件列表里拖入一个Frame到界面上,然后在右下方的属性编辑器中更改其frameShape为Box,frameShadow为Sunken,lineWidth为5,midLineWidth为10。也可以通过代码进行设置:
ui->frame->setFrameShape(QFrame::Box);
ui->frame->setFrameShadow(QFrame::Sunken);
ui->frame->setLineWidth(5);
ui->frame->setMidLineWidth(10);
- 标签QLabel部件用来显示文本或者图片。在设计器中向界面拖入一个Label,并在属性编辑器中设置其宽度为170,高度为30。然后修改font属性对字体进行设置。也可以通过代码进行设置:
QFont font;
font.setFamily("华文行楷");
font.setPointSize(10);
font.setBold(true);
ui->label->setFont(font);
- QLabel部件用来显示图片或gif动态图片:
ui->label->setPixmap(QPixmap("../logo.png"));
QMovie *movie = new QMovie("F:/donghua.gif");
ui->label->setMovie(movie); // 在标签中添加动画
movie->start();
3.1.4 按钮部件
- QAbstractButton类是按钮部件的抽象基类,提供了按钮的通用功能。它的子类包括:
1)复选框QCheckBox
2)标准按钮QPushButton
下面代码为三个按钮改变了显示文本,这里在一个字母前加上“&”符号,那么就可以将这个按钮的加速键设置为Alt加上这个字母。如果要在文本中显示“&”符号本身,那么可以使用“&&”。也可以使用setIcon()函数来给按钮添加图标,这里图片文件使用了相对路径(当然这个也可以在设计模式通过更改icon属性来实现)。对于pushBtn3,我们为其添加了下拉菜单。
ui->pushBtn1->setText(tr("&nihao")); // 这样便指定了Alt+N为加速键
ui->pushBtn2->setText(tr("帮助(&H)"));
ui->pushBtn2->setIcon(QIcon("../image/help.png"));
ui->pushBtn3->setText(tr("z&oom"));
QMenu *menu = new QMenu(this);
menu->addAction(QIcon("../image/zoom-in.png"), tr("放大"));
ui->pushBtn3->setMenu(menu);

3)单选框按钮QRadioButton
4)工具按钮QToolButton
- 按钮最常见的应用就是通过单击或双击来实现一些功能,在Qt中,这种应用是通过信号和槽的机制来实现的。
1)首先在设计模式向主界面上拖入Push Button按钮部件。然后在按钮上右击,在弹出的级联菜单中选择“转到槽”,然后在弹出的转到槽对话框中选择toggled(bool)信号。
2)这时会自动切换到编辑模式并添加该信号对应的槽函数on_pushBtn1_toggled(bool checked),下面在其中添加如下代码:
void MyWidget::on_pushBtn1_toggled(bool checked)
{
qDebug() << tr("按钮是否按下:") << checked;
}
3)当按钮被单击时会发射toggled(bool)信号,继而执行on_pushBtn1_toggled(bool checked)槽函数。如果按钮已经处于按下状态则checked为true,否则为false。使用qDebug()可以在应用程序输出窗口输出其后的信息。
3.1.5 QLineEdit
行编辑器QLineEdit部件是一个单行的文本编辑器,它允许用户输入和编辑单行的纯文本内容,而且提供了一系列有用的功能,包括撤销与恢复、剪切和拖放等操作。其中,剪切复制等功能是行编辑自带的,不用自己编码实现。
- 显示模式。QLineEdit有4种显示模式(echoMode),可以通过echoMode属性更改它们,分别是:
1)Normal正常显示输入的信息;
2)NoEcho不显示任何输入,这样可以保证不泄露输入的字符位数;
3)Password显示为密码样式,就是以小黑点或星号之类的字符代替输入的字符;
4)PasswordEchoOnEdit在编辑时显示正常字符,其他情况下显示为密码样式。 - 输入掩码。QLineEdit提供了输入掩码(setInputMask())来限制输入的内容。可以使用一些特殊的字符来设置输入的格式和内容,这些字符中有的起限制作用且必须要输入一个字符,有的只是起限制作用,但可以不输入字符而是以空格代替。

例如:“>AA-90-bb-!aa\#H;*”,它表示的含义为:
1)“>”号表明后面输入的字母自动转为大写;
2)“AA”表明开始必须输入两个字母,因为有前面的“>”号的作用,所以输入的这两个字母会自动变为大写;
3)“-”号为分隔符,直接显示,该位不可输入;
4)“9”表示必须输入一个数字;
5)“0”表示输入一个数字,或者留空;
6)“bb”表示这两位可以留空,或者输入两个二进制字符,即0或1;
7)“!”表明停止大小写转换,就是在最开始的“>”号不再起作用;
8)“aa”表示可以留空,或者输入两个字母;
9)“\#”表示将“#”号作为分隔符,因为“#”号在这里有特殊含义,所以前面要加上“\”号;
10)“H”表明必须输入一个十六进制的字符;
11)“;*”表示用“*”号来填充空格。
- 输入验证。在QLineEdit中可以使用验证器(validator)来对输入进行约束。还可以使用正则表达式来设置更强大的字符约束。
// 新建验证器,指定范围为100~999
QValidator *validator = new QIntValidator(100, 999, this);
// 在行编辑器中使用验证器
ui->lineEdit3->setValidator(validator);
使用正则表达式:
QRegularExpression rx("-?\\d{1,3}");
QValidator *validator = new QRegularExpressionValidator(rx, this);
ui->lineEdit3->setValidator(validator);
- 自动补全。QLineEdit中也提供了强大的自动补全功能,这是利用QCompleter类实现的。
QStringList wordList;
wordList << "Qt" << "Qt Creator" << tr("你好");
QCompleter *completer = new QCompleter(wordList, this); // 新建自动完成器
completer->setCaseSensitivity(Qt::CaseInsensitive); // 设置大小写不敏感
ui->lineEdit4->setCompleter(completer);

3.1.6 QAbstractSpinBox
- QAbstractSpinBox类是一个抽象基类,提供了一个数值设定框和一个行编辑器来显示设定值。它有3个子类:QDateTimeEdit、QSpinBox和QDoubleSpinBox,分别用来完成日期时间、整数和浮点数的设定。

- QDateTimeEdit类有两个子类QDateEdit和QTimeEdit;其中QTimeEdit用来设置时间,可以使用setDisplayFormat()来设置显示格式,例如“h:mm:ssA”,这样可以使用12小时制来进行显示。对于QDateEdit,使用setCalendarPopup(true)可以使用弹出的日历部件来设置日期。其中y表示年;M表示月;d表示日,而ddd表示星期;H表示小时,使用24小时制显示,而h也表示小时,如果最后有AM或者PM的,则是12小时制显示,否则使用24小时制;m表示分;s表示秒;还有一个z可以用来表示毫秒。
// 设置时间为现在的系统时间
ui->dateTimeEdit->setDateTime(QDateTime::currentDateTime());
// 设置时间的显示格式
ui->dateTimeEdit->setDisplayFormat(tr("yyyy年MM月dd日ddd HH时mm分ss秒"));
3.1.7 QAbstractSlider
-
QAbstractSlider类用于提供区间内的一个整数值,它有一个滑块,可以定位到一个整数区间的任意值。该类是一个抽象基类,它有3个子类:QScrollBar(更多的是用在QScrollArea类中来实现滚动区域)、QSlider(最常见的音量控制或多媒体播放进度等滑块)和QDial(刻度表盘)。

-
在设计模式关联信号和槽
到设计模式,从部件栏中分别将Dial、Horizontal Scroll Bar、Vertical Scroll Bar、Horizontal Slider以及Vertical Slider等部件拖入到界面上。再往界面上拖入一个Spin Box,然后按下F4或者单击图标进入信号和槽编辑模式,将刻度表盘部件dial的sliderMoved(int)信号分别与其他各个部件的setValue(int)槽相连接。运行程序,然后使用鼠标拖动刻度盘部件的滑块,可以看到其他所有的部件都跟着变化了。
-
QAbstractSlider提供的属性:
1)maximum属性用来设置最大值,minimum为最小值;
2)singleStep属性是每步的步长,默认是1,就是按下方向键后其数值增加或者减少1;
3)pageStep是每页的步长,默认是10,就是按下PageUp或者PageDown按键后,其数值增加或者减少10;
4)value与sliderPosition是当前值;
5)tracking是设置是否跟踪,默认为是,就是在拖动滑块时,每移动一个刻度,都会发射valueChanged()信号,如果选择否,则只有拖动滑块释放时才发射该信号;
6)orientation是设置部件的方向,有水平和垂直两种选择;
7)invertedAppearance属性是设置滑块所在的位置,选中后,滑块默认会在最右端。
8)invertedControls是设置反向控制,比如默认是向上方向键是增大,向下方向键是减小,如果选中这个属性,那么控制就会正好反过来。
-
Slider包含了自己的两个属性tickPosition和tickInterval,前者用来设置显示刻度的位置,默认是不显示刻度;后者是设置刻度的间隔。

-
Dial包含属性wrapping,用来设置是否首尾相连;属性notchTarget用来设置刻度之间的间隔;属性notchesVisible用来设置是否显示刻度。

3.2 对话框QDialog
QDialog类是所有对话框窗口类的基类。对话框窗口是一个经常用来完成短小任务或者和用户进行简单交互的顶层窗口。按照运行对话框时是否还可以和该程序的其他窗口进行交互,对话框常被分为两类:模态的(modal)和非模态的(modeless)。
3.2.1 模态和非模态对话框
- 模态对话框就是在没有关闭它之前,不能再与同一个应用程序的其他窗口进行交互,比如新建项目时弹出的对话框。要想使一个对话框成为模态对话框,只需要调用它的exec()函数:
QDialog dialog(this);
dialog.exec();
- 而对于非模态对话框,既可以与它交互,也可以与同一程序中的其他窗口交互,如一些软件中的查找替换对话框。要使一个对话框成为非模态对话框,可以使用new操作来创建,然后使用show()函数来显示。
QDialog *dialog = new QDialog(this);
dialog->show();
- 使用show()函数也可以建立模态对话框,只需在其前面使用setModal()函数即可。但是,它与用exec()函数时的效果是不一样的。这是因为调用完show()函数后会立即将控制权交给调用者,那么程序可以继续往下执行。而调用exec()函数却不是这样,它只有当对话框被关闭时才会返回。
QDialog *dialog = new QDialog(this);
dialog->setModal(true);
dialog->show();
- 与setModal()函数相似的还有一个setWindowModality()函数,它有一个参数来设置模态对话框要阻塞的窗口类型,可以是:
1)Qt::NonModal(不阻塞任何窗口,就是非模态),
2)Qt::WindowModal(阻塞它的父窗口和所有祖先窗口以及它们的子窗口)
3)Qt::ApplicationModal(阻塞整个应用程序的所有窗口)。
setModal()函数默认设置的是Qt::ApplicationModal。 - 使用自定义对话框登陆主界面
QApplication a(argc, argv);
MyDialog dialog; // 新建MyDialog类对象
if(dialog.exec() == QDialog::Accepted) { // 判断dialog执行结果
MyWidget w;
w.show(); // 如果是按下了“进入主界面”按钮,则显示主界面
return a.exec(); // 程序正常运行
} else return 0;
3.2.2 标准对话框
Qt提供了一些常用的对话框类型,它们全部继承自QDialog类,并增加了自己的特色功能,比如获取颜色、显示特定信息等。
3.2.2.1 标准对话框分类
- 颜色对话框QColorDialog

- 错误信息对话框QErrorMessage

- 输入对话框QInputDialog

- 字体对话框QFontDialog

- 文件对话框QFileDialog

- 消息对话框QMessageBox

- 进度对话框QProgressDialog

- 向导对话框QWizard

3.2.2.2 使用示例
- 颜色对话框类QColorDialog提供了一个可以获取指定颜色的对话框部件。需要添加#include 头文件。可以使用QColorDialog的静态函数getColor()来获取颜色,它的3个参数的作用分别是:设置初始颜色、指定父窗口和设置对话框标题。这里的Qt::red,是Qt预定义的颜色对象。
QColor color = QColorDialog::getColor(Qt::red, this, tr("颜色对话框"));
qDebug() << "color: " << color;
- 如果想要更灵活的设置时,则可以先创建对象,然后进行各项设置:
QColorDialog dialog(Qt::red, this); // 创建对象
dialog.setOption(QColorDialog::ShowAlphaChannel); // 显示alpha选项
dialog.exec(); // 以模态方式运行对话框
QColor color = dialog.currentColor(); // 获取当前颜色
qDebug()<<"color:"<<color; // 输出颜色信息
- 进度对话框QProgressDialog对一个耗时较长操作的进度提供了反馈。先添加#include 头文件。
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("复制结束!");
3.3 Qt Quick基础可视项目
Qt Quick模块作为一个编写QML应用程序的标准库,提供了用于创建用户界面的所有基本类型,使用这些类型可以创建动态可视化组件、接收用户输入、创建数据模型和视图。Qt Quick模块既提供了QML 语言接口,可以使用QML类型来创建用户界面,也提供了C++语言接口,可以使用C++代码来扩展 QML 应用。QtQuick模块的子模块包括:Local Storage、Particles、Controls、Layouts、Tests、Effects。
3.3.1 Item
这里要引入一个新的概念,就是“项目”, 因为英文items翻译过来就是项目,而在Qt Quick中所有可视化类型都基于Item,它们都被称为可视化项目(visual items)。虽然单独的Item对象没有可视化外观,但是它定义了可视化项目所有通用的特性,例如关于位置的x和y属性,关于大小的width和height属性,关于布局的anchors相关属性,以及关于按键处理的Keys附加属性等等。
3.3.1.1 作为容器
Item常用于对项目进行分组,在一个根项目下,使用Item项目组织其它的项目。例如下面的代码片段中,Item里面包含了一个图片Image项目和一个矩形Rectangle项目:
Item {
Image {
x: 80
width: 100; height: 100
source: "tile.png"
}
Rectangle {
x: 190
width: 100; height: 100
}
}
3.3.1.2 默认属性
- Item有一个children属性和一个resources属性,前者包含了可见的子项目列表,后者包含了不可见的资源。例如下面的代码片段所示:
Item {
children: [
Text {},
Rectangle {}
]
resources: [
Timer {}
]
}
- Item还有一个data默认属性,允许在一个项目中将可见的子项目和不可见的资源进行自由混合。也就是说,如果向data列表中添加一个可视项目,那么该项目将作为一个孩子进行添加;如果添加任何其它的对象类型,则会作为资源进行添加。因为data是默认属性,所以可以省略data标签,这样前面的代码可以改写为:
Item {
Text {}
Rectangle {}
Timer {}
}
3.3.1.3 不透明度
Item有一个opacity属性,可以用来设置不透明度。该属性可选值为0.0(完全透明)和1.0(完全不透明)之间的任意数字,默认值为1.0。opacity是一个继承属性,也就是说,父项目的透明度也会应用到子项目上。例如两个相互重叠的不透明矩形,通过设置父项目的opacity属性,会使两个矩形都变成透明的:
Item {
Rectangle {
opacity: 0.5
color: "red"
width: 100; height: 100
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
}
}
}

3.3.1.4 可见与启用
- Item的visible属性用来设置项目是否可见,其默认值为true。设置一个项目的visible属性会直接影响其子项目的可见性,除非单独设置子项目的visible属性。如果将该属性设置为false,那么项目将不再接收鼠标事件,但是可以继续接收键盘事件。如果在设置visible属性之前,项目被设置了键盘焦点,那么焦点依然会保留。
- Item还有一个enabled属性,它可以设置项目是否接收鼠标和键盘事件,其值默认为true。设置一个项目的enabled属性也会直接影响其子项目的enabled值,除非对其子项目的enabled属性进行单独设置。
3.3.1.5 定位子项目和坐标映射
- Item中提供了childAt(real x, real y)函数来返回在点(x, y)处的第一个可视子项目,如果没有这样的项目则返回null。
- Item的mapFromItem(Item item, real x, real y)函数会将item坐标系统中点(x, y)映射到该项目的坐标系统上,该函数会返回一个包含映射后的x和y属性的对象。对应的还有一个mapToItem(Item item, real x, real y)函数,可以从当前项目坐标系统的(x, y)点映射到item的坐标系统。
3.3.1.6 堆叠顺序
Item拥有一个z属性,可以用来设置兄弟项目间的堆叠顺序。默认的堆叠顺序为0。拥有较大z值的项目会出现在z值较小的兄弟项目之上。拥有相同的z属性值的项目会以代码中出现的顺序由下向上进行绘制。如果项目的z属性值为负,那么它会被绘制在其父项目的下面。例如下面的代码中红色矩形绘制在蓝色矩形上面:
Item {
Rectangle {
z: 1
color: "red"; width: 100; height: 100
}
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
}
}

3.3.2 Rectangle
Rectangle项目继承自Item,被用来使用纯色或者渐变填充一个矩形区域,并提供一个边框。Rectangle项目可以使用color属性指定一个纯色来填充,或者使用gradient属性指定一个Gradient类型定义的渐变来填充。除此之外,还可以为Rectangle添加一个可选的边框,并通过border.color和border.width为其指定颜色和宽度。也可以使用radius属性来产生一个圆角矩形。
Rectangle {
width: 100; height: 100
color: "lightgrey"
border.color: "black"; border.width: 5; radius: 20
}

3.3.3 Text
Text项目可以显示纯文本或者富文本,类似于Qt Widgets中的QLabel。Text支持有限的HTML子集。如果在文本中包含HTML的img标签加载远程的图片,文本会被重载。Text是只读文本,如果要使用可编辑文本,可以使用TextEdit项目。
1)wrapMode属性设置换行。
2)elide属性设置自动省略显示。
3)textFormat属性设置文本格式。
4)horizontalAlignment和verticalAlignment分别用来设置文本在Text项目区域中的水平对齐方式和垂直对齐方式。
Column {
Text {
text: "Hello World!"
font.family: "Helvetica"; font.pointSize: 50
color: "red"
}
Text {
text: "<b>Hello</b> <i>World!</i>"
font.pointSize: 30
}
}
Rectangle {
width: 200; height: 200; color: "lightgrey"
Text {
width: 200; height: 200
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: qsTr("中心")
font.pointSize: 20
}
}
3.3.4 TextInput
TextInput项目用来显示单行可编辑的纯文本。TextInput与Qt Widgets中的QLineEdit相似,用于接收单行文本输入。
1)验证器:整数验证器IntValidator、DoubleValidator(非整数验证器)和RegularExpressionValidator(正则表达式验证器)。
2)掩码inputMask,可以参考前面QLineEdit部分的内容。
3)回显方式与QLineEdit一样,也有4种显示模式(echoMode)。
Item {
Rectangle {
id: rect
width: input.contentWidth<100 ? 100 : input.contentWidth + 10
height: input.contentHeight + 5
color: "lightgrey"; border.color: "grey"
TextInput {
id: input
anchors.fill: parent; anchors.margins: 2
font.pointSize: 15; focus: true
inputMask: ">AA_9_a"
onEditingFinished: text2.text = text
}
}
Text { id: text2; anchors.top: rect.bottom}
}
3.3.5 TextEdit
TextEdit与TextInput类似,不同之处在于,TextEdit用来显示多行的可编辑的格式化文本。TextEdit与Qt中的QTextEdit很相似,它既可以显示纯文本也可以显示富文本。
TextEdit {
width: 240; height: 400
wrapMode: Text.WordWrap
text: "<b>Hello</b> <i>World!</i> Note that the TextEdit does not implement scrolling,
following the cursor, or other behaviors specific to a look and feel. For example,
to add flickable scrolling that follows the cursor"
textFormat: Text.RichText
font.family: "Helvetica"
font.pointSize: 20
color: "blue"
focus: true
}

3.4 Qt Quick控件
Qt Quick Controls模块是Qt Quick模块的子模块,包含了一组丰富的UI控件,迎合了最常见的用例,并且提供了定制选项,可用于在Qt Quick中构建完整的应用界面。
3.4.1 控件基类型Control
Control是用户界面控件的基类型,Qt Quick Controls模块中的大部分控件都继承自Control,而Control继承自Item,一般不直接使用该类型,而是使用它的众多子控件类型。Control从窗口系统接收输入事件并在屏幕上绘制自身,一个典型的Control控件布局如图所示。
控件的隐式大小implicitWidth和implicitHeight通常基于背景background和内容项contentItem的隐式大小以及四周的insets和paddings等属性的值,当没有明确指定控件的width和height属性时,会通过这些值来决定控件的大小。背景的insets相关属性可以在不影响控件的视觉外观的情况下扩展其可交互区域,这对于较小的控件非常有用。
3.4.2 按钮类控件
在Qt Quick Controls模块中提供了一组按钮类控件,包括AbstractButton及其子孙类型Button、CheckBox、DelayButton、RadioButton、RoundButton、Switch和ToolButton等,每种类型的按钮都有自己的特定用例。
- Button控件:实现了一个通用的按钮控件,一般用来执行一个动作或者回答一个问题,比如“确定”“取消”等。Button在AbstractButton的基础上添加了flat和highlighted两个属性。
- RoundButton控件:作为Button的子类型,在其基础上添加了一个radius属性,可以设置圆角,将按钮的implicitWidth和implicitHeight设置为同一值,并将radius设置为width / 2,可以创建一个圆形按钮。
RowLayout {
anchors.fill: parent; spacing: 10
Button { text: qsTr("普通按钮"); onClicked: close() }
Button { text: qsTr("flat按钮"); flat: true }
Button { text: qsTr("高亮按钮"); highlighted: true }
RoundButton { text: qsTr("圆角按钮"); radius: 5 }
RoundButton { text: qsTr("圆形按钮"); implicitWidth: 60;
implicitHeight: 60; radius: width / 2 }
}
- CheckBox控件:复选框用来创建一个选项按钮,可以在“选中”和“未选中”两种状态间切换。如果将tristate属性设置为true,则复选框可以拥有第3种状态“部分选中”。
- RadioButton控件:单选按钮通常用于从一组选项中选择一个选项。单选按钮的autoExclusive属性默认为true,在属于同一父项的单选按钮中,任何时候只能选中一个按钮,选中另一个按钮会自动取消选中先前选中的按钮。
- ButtonGroup控件:可以包含一组互斥的按钮,该控件本身是不可见的,一般与RadioButton等控件一起使用。如果需要ButtonGroup中的按钮不再互斥,可以设置exclusive属性为false。
ColumnLayout {
ButtonGroup {
id: childGroup
exclusive: false;
checkState: parentBox.checkState
}
CheckBox {
id: parentBox;
text: qsTr("Parent");
checkState: childGroup.checkState
}
CheckBox {
checked: true; text: qsTr("Child 1")
leftPadding: indicator.width;
ButtonGroup.group: childGroup
}
CheckBox {
text: qsTr("Child 2");
leftPadding: indicator.width
ButtonGroup.group: childGroup
}
}

- DelayButton控件:是一个可被选中的按钮,在被选中并发出activated()信号之前,有一个延迟,用来防止意外按压。progress属性可返回当前进度,介于0.0~1.0之间,延迟时间以毫秒为单位,通过delay属性进行设置。
- Switch控件:开关按钮可以在“打开”和“关闭”之间进行切换,该按钮通常用于在两种状态之间进行选择。
RowLayout {
DelayButton {
text: qsTr("延迟按钮"); delay: 5000
onActivated: text = qsTr("已启动")
}
Switch {
text: qsTr("Wi-Fi")
onToggled: console.log(checked)
}
}

3.4.3 指示器类控件
在Qt Quick Controls提供了一系列类似指示器的控件,包括BusyIndicator、PageIndicator、ProgressBar、ScrollBar和ScrollIndicator等,它们均直接继承自Control。
- PageIndicator控件:一般与StackLayout这样包含多个页面的容器控件一起使用来指示当前的活动页面。
- ScrollBar和ScrollIndicator控件:一般用于Flickable及其子类型,用于显示滚动条和滚动位置。
- BusyIndicator控件:用来显示一个忙碌指示器控件,用来指示正在加载内容或UI被阻止需等待资源等情况。
- ProgressBar控件:用来显示一个进度条指示器控件,可以指示操作的进度。进度值由value属性指定,需要定期进行更新来显示进度,其范围由from属性(默认值为0.0)和to属性(默认值为1.0)指定。
Pane {
width: 400; height: 300
Image {
id: image; anchors.fill: parent
source: "https://www.qter.org/temp/back.png"
}
BusyIndicator {
id:busy
anchors.horizontalCenter:
parent.horizontalCenter
anchors.verticalCenter:
parent.verticalCenter
running: image.status === Image.Loading
}
ProgressBar {
visible: image.status === Image.Loading
value: image.progress
}
}
3.4.4 输入类控件
Qt Quick Controls模块中为数字和文本输入提供了多种输入控件,包括ComboBox、Dial、RangeSlider、Slider、TextArea、TextField、Tumbler和SpinBox等。
- ComboBox控件:ComboBox继承自Control,是一个组合按钮和弹出列表的组合框控件,提供了一种以占用最小屏幕空间的方式向用户呈现选项列表的方法。填充到ComboBox的数据模型通常是JavaScript数组、ListModel或整数。将editable属性设置为true时,可以对ComboBox进行编辑。
Item {
width: 200; height: 300
ComboBox {
x:10; y:10
editable: true
model: ListModel {
id: model
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
onAccepted: {
if (find(editText) === -1)
model.append({text: editText})
}
}
}

- Dial控件:Dial继承自Control,实现类似于传统的音响上拨号旋钮样式的控件,可以用来指定范围内的值。通过from和to属性来指定开始和结束的值,value属性设置当前值。另外,可以使用stepSize设置步长,将wrap设置为true,可以到终点后直接跳到起始点。
Item {
width: 100; height: 120
Dial {
id: dial
from: 1; to: 10
stepSize: 1; wrap: true
}
Label {
anchors.top: dial.bottom
text: dial.value
}
}

-
RangeSlider控件

-
Slider控件

-
TextArea控件:TextArea继承自TextEdit,提供了一个多行文本编辑器,在TextEdit之上添加了占位符文本功能,并进行了一些装饰。TextArea本身不可以滚动,可以将其放入ScrollView中来实现滚动条。通过placeholderText属性可以设置占位符文本,它是在用户输入之前显示在文本区域中的简短提示。
ScrollView {
id: view
anchors.fill: parent
TextArea {
placeholderText: qsTr("可以在这里输入内容")
wrapMode: Text.WordWrap
}
}

-
TextField控件

-
Tumbler控件

-
SpinBox控件:允许用户通过单击向上或向下指示器按钮,或通过键盘向上或向下键来选择整数值。可以通过editable属性将SpinBox设置为可编辑。默认情况下,SpinBox提供0~99范围内的离散值,步长为1,可以通过from和to设置起始值和结束值,通过value设置当前值。尽管SpinBox默认只可以处理整数值,通过validator、textFromValue和valueFromText等属性也可以自定义让其接受任意输入值。
SpinBox {
id: spinBox
from: 0; to: items.length - 1
value: 1 // "Medium"
property var items: ["Small", "Medium", "Large"]
validator: RegularExpressionValidator {
regularExpression: new RegExp("(Small|Medium|Large)", "i")
}
textFromValue: function(value) {
return items[value];
}
valueFromText: function(text) {
for (var i = 0; i < items.length; ++i) {
if (items[i].toLowerCase().indexOf(text.toLowerCase())
=== 0)
return i
}
return spinBox.value
}
}

3.4.5 日期类控件
日期类控件包括DayOfWeekRow、WeekNumberColumn和MonthGrid,它们都继承自Control。DayOfWeekRow会将星期几的名称显示为一行,日期的名称使用指定的locale区域设置进行排序和格式化。WeekNumberColumn在一列中显示给定year年份、month月份的周数。这两个控件都可以独自使用,但是一般会和MonthGrid一起使用,通过计算给定月份和年份实现在网格中显示日历月。
Item {
width: 400; height: 300
GridLayout {
columns: 2
DayOfWeekRow {
locale: grid.locale
Layout.column: 1
Layout.fillWidth: true
}
WeekNumberColumn {
month: grid.month; year: grid.year
locale: grid.locale
Layout.fillHeight: true
}
MonthGrid {
id: grid
month: Calendar.December; year: 2022
locale: Qt.locale("zh_CN")
Layout.fillWidth: true
Layout.fillHeight: true
onClicked: (date) => console.log(date)
}
}
}

3.5 Qt Quick系统对话框
从Qt 6.2开始引入了Qt Quick Dialogs模块,可以从QML创建系统对话框并与之交互。常用的系统对话框类型包括ColorDialog、FileDialog、FolderDialog、FontDialog和MessageDialog等。
3.5.1 颜色对话框ColorDialog
ColorDialog类型为系统颜色对话框提供了QML API。要显示颜色对话框,可以先创建ColorDialog的实例,设置所需的属性,然后调用open()方法。通过selectedColor属性可用于获取对话框选定的颜色,通过options属性可以启用一些选项,比如显示Alpha通道。注意,使用Qt Quick Dialogs模块,需要添加如下导入语句:import QtQuick.Dialogs。
Window {
width: 800; height: 600; visible: true
RowLayout {
Button {
text: qsTr("颜色对话框")
onClicked: colorDialog.open()
}
Label { id: label; text: qsTr("颜色展示")}
}
ColorDialog {
id: colorDialog
selectedColor: label.color
options: ColorDialog.ShowAlphaChannel
onAccepted: label.color = selectedColor
}
}

3.5.2 文件对话框FileDialog
FileDialog类型为系统文件对话框提供了QML API。
1)通过selectedFile和selectedFiles属性可以获取选择的文件;
2)通过nameFilters属性可以设置类型过滤器,只显示指定类型的文件;
3)通过currentFolder属性可以指定打开的默认目录;
4)通过acceptLabel和rejectLabel可以设置两个按钮的显示文本;
5)通过fileMode属性可以设置对话框模式,默认是FileDialog.OpenFile选择一个文件,另外还有FileDialog.OpenFiles选择多个文件,FileDialog.SaveFile保存文件。
Window {
width: 640; height: 480; visible: true
Image {
id: image; anchors.fill: parent
fillMode: Image.PreserveAspectFit
}
Button {
text: qsTr("Choose Image...")
onClicked: fileDialog.open()
}
FileDialog {
id: fileDialog
nameFilters: ["Image files (*.png *.jpg)"]
currentFolder: StandardPaths.writableLocation
(StandardPaths.PicturesLocation)
acceptLabel: qsTr("选择图片")
onAccepted: image.source = selectedFile
}
}

3.5.3 消息对话框MessageDialog
MessageDialog类型为系统消息对话框提供了QML API。MessageDialog用于通知用户或向用户提问。
1)text属性,作为主要文本用来提醒用户注意的情况;
2)informativeText属性,作为信息性文本以进一步解释警报或向用户提问;
3)detailedText属性,作为可选的详细文本用于用户请求时提供更多数据;
4)buttons属性用来设置按钮,例如MessageDialog.Ok、MessageDialog.Cancel等。
Window {
width: 640; height: 480; visible: true
Button {
text: qsTr("消息对话框")
onClicked: dlg.open()
}
MessageDialog {
id: dlg
title: qsTr("消息对话框")
text: qsTr("这里是text的内容")
informativeText: qsTr("这里是informativeText的内容")
detailedText: qsTr("这里是detailedText的内容")
buttons: MessageDialog.Ok | MessageDialog.Cancel
onAccepted: console.log("ok")
}
}

3.6 程序调试
编写程序时难免遇见非预期的结果,或者有时想要测试程序中某段代码的结果,这时进行程序调试就非常有必要了。
3.6.1 调试模式
- Qt Creator中提供的调试模式可以对Qt Widgets和Qt Quick程序进行调试,其中的调试器可以查看应用程序在运行或崩溃时内部发生的情况,它可以通过如下方式来查找应用中的问题:
1)使用指定的参数启动应用程序;
2)在满足条件时停止应用程序;
3)检查应用程序停止时会发生什么;
4)修复错误后对应用程序进行更改,然后继续查找下一个错误。 - 开始调试前一般在需要调试的代码标号前面单击来设置断点。如下在int x = widget.x(); 设置断点。所谓断点,就是程序运行到该行代码时会暂停下来,从而可以查看一些信息。要取消断点,只要在那个断点上再单击一下就可以了。设置好断点后便可以按下F5或者左下角的调试按钮开始调试。这时程序会先进行构建再进入调试模式,这个过程可能需要一些时间。

- 下面对调试模式的几个按钮和窗口进行简单介绍:
①继续按钮。程序在断点处停了下来,按下继续按钮后,程序便会像正常运行一样,执行后面的代码,直到遇到下一个断点,或者程序结束。
②停止调试按钮。按下该按钮后结束调试。
③单步跳过按钮。直接执行本行代码,然后指向下一行代码。
④单步进入按钮。进入调用的函数内部。
⑤单步跳出按钮。当进入函数内部时,跳出该函数,一般与单步进入配合使用。
⑥重新启动调试会话。
⑦显示源码对应的汇编指令,并可以单步调试。
⑧堆栈视图。这里显示了从程序开始到断点处,所有嵌套调用的函数所在的源文件名和行号。
⑨其它视图。这里可以选择多种视图,主要有局部变量(Locals)和表达式(Expressions)视图、断点(Breakpoints)视图、线程视图(Threads)等。
3.6.2 单步调试
一直单击“单步跳过”按钮,单步执行程序并查看右上角局部变量视图中相应变量值的变化情况。等执行到最后一行代码“return a.exec();”时,单击“停止调试”按钮结束调试。从变量监视器中可以看到x、y、geometry和frame这4个变量初始值都是一个随机未知数。等到调试完成后,x、y的值均为0,这是它们的默认值。而geometry和frame的值均为640x480+0+0。为什么x、y的值会是0呢?可能会想到,应该是窗口没有显示的原因,那么下面更改代码,让窗口先显示出来,再看这些值。在“QWidget widget;”一行代码后添加一行代码:widget.show();
QWidget widget;
widget.show();
int x = widget.x();
int y = widget.y();
//x()、y()分别返回部件的位置坐标的x、y值,它们的默认值为0。
//geometry()和frameGeometry()函数分别返回没有边框和包含边框的窗口框架矩形的值,其返回值是QRect类型的,就是一个矩形,它的形式是(位置坐标,大小信息),也就是(x,y,宽,高)。
QRect geometry = widget.geometry();
QRect frame = widget.frameGeometry();
return a.exec();
再次调试程序,这时会发现窗口只显示了一下,先不管它,继续在Qt Creator中单击“单步跳过”按钮。将程序运行到最后一行代码“return a.exec();”时再次单击“单步跳过”按钮后,程序窗口终于正常显示出来了。这是因为只有程序进入主事件循环后才能接收事件,而show()函数会触发显示事件,所以只有在完成a.exec()函数调用进入消息循环后才能正常显示。
3.6.3 在Qt Widgets程序中使用qDebug()函数
- 程序调试过程中常用的是qDebug()、qInfo()、qCritical()、qWarning()和qFatal()等函数,它们由Qt Core模块提供,可以将调试信息直接输出到控制台,当然,Qt Creator中是输出到下方应用程序输出栏。在Qt Widgets程序中,调试信息一般常用qDebug()。
int x = widget.x();
qDebug("x: %d", x);
int y = widget.y();
qDebug("y: %d", y);
QRect geometry = widget.geometry();
QRect frame = widget.frameGeometry();
qDebug() << "geometry: " << geometry
<< "frame: " << frame;
- 这里使用了两种输出方法,一种是直接将字符串当做参数传给qDebug()函数,例如上面使用这种方法输出x和y的值。另一种方法是使用输出流的方式一次输出多个值,它们的类型可以不同,如程序中输出geometry和frame的值。实际编程中经常使用第二种方法。

- 使用qDebug()函数的第二种方法时还可以让输出自动换行:
qDebug() << "pos:" << widget.pos() << Qt::endl
<< "rect:" << widget.rect()<< Qt::endl
<< "size:" << widget.size() << Qt::endl
<< "width:"<< widget.width() << Qt::endl
<< "height:" << widget.height();
1)这里的“Qt::endl”就是起换行作用的。
2)根据程序的输出结果,可以很明了的看到这些函数的作用。
3)其中pos()函数返回窗口的位置,是一个坐标值,上面的x()、y()函数返回的就是它的x、y坐标值;
4)rect()函数返回不包含边框的窗口内部矩形,在窗口内部,左上角是(0,0)点;
5)size()函数返回不包含边框的窗口大小信息;
6)width()和height()函数分别返回窗口内部的宽和高。
3.6.4 在Qt Quick程序中使用console.log()函数
Qt Quick程序也可以使用调试模式,而且QML中也提供了console.log()、 console.debug()、console.info()、 console.warn()和console.error()等调试输出函数,比较常用的是console.log()。
Rectangle {
width: 200
height: 200
color: "blue"
MouseArea {
anchors.fill:parent
onClicked: console.log("矩形的颜色:", parent.color)
}
}
更多推荐
所有评论(0)