Qt学习之路(二):创建对话框(QDialog)及深入信号和槽

对于一个图形界面来说,对话框是必不可少的,因为它是为用户和应用程序之间提供一种可以相互“交谈”的交互方式。下面具体分享编写对话框的过程。

First:确定对话框程序的源码结构

 对于一般的程序来说都需要自己定义头文件和源文件,头文件中包括对控件类的声明定义,而对应就应该有一个同名的源文件来定义编写对应类中的函数,最后需要一个入口函数来执行相应程序的源文件,所以定义如下文件:

文件名
finddialog.h
finddialog.cpp
main_dialog.cpp

Second:构思及编写 finddialog 类的定义

规划界面,如下:

Find对话框

规划的界面中有如下元素:一个标签( 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.深入介绍信号和槽

  1. 信号和槽机制是Qt编程的基础,槽可以被重载,参数是任意类型的。connect()语句如下:
connect(sender,SIGNAL(sender),receiver,SLOT(slot));

senderreceiver是指向 QObject 的指针,signalslot是不带参数的函数名。实际上,SIGNAL()和SLOT()宏会把它们的参数转换成相应的字符串。

  1. 信号与槽的连接方式:
  • 一个信号和一个槽连接
  • 一个信号可以连接多个槽:
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会自动移除和这个对象相关的所有链接。

  1. 要把信号成功连接到槽,它们的参数必须具有相同的顺序和相同的类型;如果信号的参数比它所连接的槽的参数多,那么多余的参数将会被简单地忽略掉;如果参数类型不匹配,或者信号或槽不存在,则Qt会发出警告;如果在信号和槽的名字中包含参数名,Q也会发出警告。

最后总结:

 通过读书,大体了解了一个对话框的创建以及实现方式,同时了解可以画出对话框的方法,但不想用,因为从头编写代码会更加清楚整个结构。此外,关于其他有关的控件都会逐步用到。Keep learning!

你可能感兴趣的:(Qt学习之路(二):创建对话框(QDialog)及深入信号和槽)