对于一个图形界面来说,对话框是必不可少的,因为它是为用户和应用程序之间提供一种可以相互“交谈”的交互方式。下面具体分享编写对话框的过程。
First:确定对话框程序的源码结构
对于一般的程序来说都需要自己定义头文件和源文件,头文件中包括对控件类的声明定义,而对应就应该有一个同名的源文件来定义编写对应类中的函数,最后需要一个入口函数来执行相应程序的源文件,所以定义如下文件:
文件名 |
---|
finddialog.h |
finddialog.cpp |
main_dialog.cpp |
Second:构思及编写 finddialog 类的定义
规划界面,如下:
规划的界面中有如下元素:一个标签( label ),一个文本框( lineedit ),两个复选框( checkbox ),两个按钮( button ) ,具体的数据结构为:
- 父类:Finddialog
新创建对话框类需要继承QDialog,所以QDialog是作为dialog的基类被继承。
- 父类中包含函数:构造函数Finddialog()
Finddialog中有参数 parent ,该参数的类型为QWidget,此 parent 参数的值为0,它指定了它的父窗口部件的数目为0,是一个空指针,这意味着该对话框没有父对象。
- Finddialog还需自定义信号和槽,便于部件之间的交互,最后需要定义相应的所需控件(上文提到过)
补充:对于Qt来说,对于所有定义了信号和槽的类,在类定义开始处的Q_OBJECT 宏都是必须的,文档写道:The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.
Third:Finddialog.h的编写
1.类开头的编写:
#ifndef FINDDIALOG_H
#define FINDDIALOG_H
#include
class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;
注意:该段代码前置声明了在这个对话框实现中的Qt类,前置声明会告诉C++编译程序类的存在,而不用提供类定义中的所有细节。
2.声明构造函数
class FindDialog:public QDialog
{
Q_OBJECT //对于所有定义了信号和槽的类,在类开始处必需
public:
FindDialog(QWidget *parent=0);//典型Qt窗口部件类的定义,parent指定父窗口部件
3.信号(signals)的声明
signals: //声明当前用户单击find按钮对对话框发射的两个信号
void findNext(const QString &str,Qt::CaseSensitivity cs);//CaseSensitivity是枚举类型有两个取值
void findPrevious(const QString &str,Qt::CaseSensitivity cs);
说明:
1.signals部分声明当用户单机Find按钮的时候对话框所发射的两个信号,如果先前查询,对话框就发射findPrevious()信号,否则它就发射findNext()信号。(findNext和findPrevious的函数是Qt中已有的函数,此时仅仅是声明而已。)
2.Qt::CaseSensitivity是一个枚举类型,表示对大小写敏感。
4.槽(slots)和控件的声明
private slots: //声明两个槽
void findClicked();
void enableFindButton(const QString &text);
private: //对于私有变量,使用了类前置声明,因都是指针而且没必要在头文件访问,
//编译程序无需这些类的完整定义,前置声明使编译过程快一些
QLabel *label;
QLineEdit *lineEdit;
QCheckBox *caseCheckBox;
QCheckBox *backwardCheckBox;
QPushButton *findButton;
QPushButton *closeButton;
};
#endif // FINDDIALOG_H
1.为了实现声明的两个槽,几乎需要访问这个对话框的所有子窗口部件,所以也保留了指向它们的指针。关键字slots就像signals一样也是一个宏,C++预编译
2.对于私有变量,使用了它们的类前置声明,这是可行的,因为它们都是指针,而且没有必要在头文件中就去访问他们,因此编译程序就无需类的完整定义。
Fourth:Finddialog.cpp的编写
1.包含头文件的写法
#include //重要模块Qt-Core,Gui,Network,OpenGL,Script,Sql,Svg,Xml
#include"finddialog.h"
此处说明:Qt5对Qt4的模块进行了重构,最明显的是对Qt Gui模块的修改,在Qt 5 中,Qt Gui不再包含有关界面的所有类。所有的图形界面程序需要的QApplication以及最重要的基类QWidget已经不在Qt Gui模块中,而是被重新组合到了一个新的模块Qt Widgets中。Qt 5的一个重大更改就是重新定义了Qt Gui模块,它不再是一个大而全的图形界面库,而是为各种图形用户界面组件提供一般的处理,包括窗口系统集成、事件处理、OpenGL和OpenGL ES的集成、2D绘图、基本图像、字体和文本等内容。Qt 5将以前的Qt Gui模块中的图形部件类移动到了Qt Widgets模块中,将打印相关类移动到了Qt PrintSupport模块中。
此外,Qt 5移除了Qt OpengGL模块,将OpenGL相关类移动到了Qt Gui模块中。
此外,QtCore也做了很大更新:
(1)Qt 5巧妙地利用C++的函数指针,为信号槽连接提供了编译期类型检查,同时还减少了信号槽的限制,在Qt4中,只有类的非静态成员函数才允许作为槽函数,但是在Qt 5中,所有函数,包括全局函数,静态函数,甚至匿名函数,都可以作为槽函数。
(2)Qt 5中包含了一个JSON解析器。随着Web2.0的星期,JSON正在取代XML成为新一代数据交换格式。Qt 4中需哟使用第三方库才能方便解析JSON,而Qt 5则直接内置对JSON的支持。
原文链接:https://blog.csdn.net/hudfang/article/details/76099830
2.定义构造函数
语句解释在注释中
FindDialog::FindDialog(QWidget *parent)
:QDialog(parent) //基类
{ //tr()函数的调用是把它们翻译成其他语言的标记,是个好习惯
label = new QLabel(tr("Find &what"));
lineEdit = new QLineEdit;
label->setBuddy(lineEdit);//设置行编辑器作为标签的伙伴,
//所谓伙伴,就是一个窗口部件,可以在按下标签的快捷键时接受焦点
//&用来表示快捷键,
caseCheckBox=new QCheckBox(tr("Match &case"));
backwardCheckBox = new QCheckBox(tr("Search &backward"));
findButton = new QPushButton(tr("&Find"));
findButton->setDefault(true); //设置默认按钮,用户按下Enter能够按下对应按钮
findButton->setEnabled(false); //禁用Find按钮,不能和用户发生交互行为
closeButton = new QPushButton(tr("Close"));
connect(lineEdit,SIGNAL(textChanged(const QString&)), //QObject是FindDialog的父对象之一,
//省略QObject::前缀
this,SLOT(enableFindButton(const QString&)));
connect(findButton,SIGNAL(clicked()),
this,SLOT(findClicked()));
connect(closeButton,SIGNAL(clicked()),
this,SLOT(close()));
//布局窗口部件
QHBoxLayout *topLeftLayout = new QHBoxLayout;
topLeftLayout->addWidget(label);
topLeftLayout->addWidget(lineEdit);
QVBoxLayout *leftLayout = new QVBoxLayout;
leftLayout->addLayout(topLeftLayout);
leftLayout->addWidget(caseCheckBox);
leftLayout->addWidget(backwardCheckBox);
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addWidget(findButton);
rightLayout->addWidget(closeButton);
rightLayout->addStretch();
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addLayout(leftLayout);
mainLayout->addLayout(rightLayout);
setLayout(mainLayout);
//显示对话框标题栏上的内容,并让窗口具有一个固定的高度
setWindowTitle(tr("Find"));
setFixedHeight(sizeHint().height());//sizeHint返回一个窗口理想的尺寸大小
}
说明:进一步说明Q_OBJECT宏,因而由qmake生成的makefile将会自动包含一些运行moc的规则,moc就是指Qt的元对象编译器,叫meta-object compiler。
为了使moc能够正常运行,必须把类定义从实现文件中分离出来并放到头文件中。由moc生成的代码会包含这个头文件,并且会添加一些特殊的C++代码。
Fifth.深入介绍信号和槽
- 信号和槽机制是Qt编程的基础,槽可以被重载,参数是任意类型的。connect()语句如下:
connect(sender,SIGNAL(sender),receiver,SLOT(slot));
sender和receiver是指向 QObject 的指针,signal和slot是不带参数的函数名。实际上,SIGNAL()和SLOT()宏会把它们的参数转换成相应的字符串。
- 信号与槽的连接方式:
- 一个信号和一个槽连接
- 一个信号可以连接多个槽:
connect(slider,SIGNER(valueChanged(int)),
spinBox,SLOT(setValue(int)));
connect(slider,SIGNER(valueChanged(int)),
this,SLOT(updateStatusBarIndicator(int)));
在发射信号时,会以不确定的顺序一个接一个地调用这些槽。
- 多个信号可以连接同一个槽(类似2)
无论发射哪一个信号,都会调用这个槽
- 一个信号可以和另外一个信号连接
connect(lineEdit,SIGNAL(textChanged(const QString &)),
this,SIGNAL(updateRecord(const QString &)));
当发射第一个信号时,也会发射第二个信号,信号与信号之间地连接和信号与槽之间的连接是难以区分的。
- 连接可以被移除(不常用)
disconnect(),删除对象的时候,Qt会自动移除和这个对象相关的所有链接。
- 要把信号成功连接到槽,它们的参数必须具有相同的顺序和相同的类型;如果信号的参数比它所连接的槽的参数多,那么多余的参数将会被简单地忽略掉;如果参数类型不匹配,或者信号或槽不存在,则Qt会发出警告;如果在信号和槽的名字中包含参数名,Q也会发出警告。
最后总结:
通过读书,大体了解了一个对话框的创建以及实现方式,同时了解可以画出对话框的方法,但不想用,因为从头编写代码会更加清楚整个结构。此外,关于其他有关的控件都会逐步用到。Keep learning!