^(* ̄(oo) ̄)^

  • 首页
  • 博客
  • 文档
  • 网盘
  • 仓库
  • 简介
Keep Learning
  1. 首页
  2. 博客
  3. 正文

Qt - 创建对话框(信号和槽)

2024年8月26日 1436点热度

Qt由数个模块模块构成,最为重要的模块有QtCore、QtGui、QtNetwork、QtOpenGL、QtScript、QtSql、QtSvg和QtXml。 <QtGui>头文件中为构成QtCore和QtGui组成部分的所有类进行了定义。无需包含所有类。

 

finddialog.h 对话框头文件:

#ifndef FINDDIALOG_H  // 防止多重包含
#define FINDDIALOG_H
​
#include <QDialog> // QT 对话框基类
​
// 前置声明,不提供类细节使编译过程更快一些。
class QCheckBox; 
class QLabel;
class QLineEdit;
class QPushButtom;
​
class FindDialog : public QDialog 
{
    Q_OBJECT  // 对于所有定义了 信号和槽的类,在类定义开始处的 Q_OBJECT 宏 都是必需的。
​
public:
    // parent 默认为空指针即没有父对象
    FindDialog(QWidget *parent = 0);
​
// signals关键字是一个宏, 信号
signals: 
    // CaseSensitivity 是一个枚举类型,包含Qt::CaseSensitive与Qt::CaseInsensitive
    void findNext(const QString &str, Qt::CaseSensitivity cs); 
    void findPrevious(const QString &str, Qt::CaseSensitivity cs);
​
// slots也是一个宏, 槽
    private slots:
    void findClicked();
    void enableFindButton(const QString &text);
​
// 私有变量,类前置说明。QCheckBox、QLabel 未包含头文件,属于前置声明
private:
    QLabel *label;
    QLineEdit *lineEdit;
    QCheckBox *caseCheckBox; 
    QCheckBox *backwardCheckBox;
    QPushButton *findButton;
    QPushButton *closeButton;
};
​
#endif

finddialog.cpp

#include <QtGui>
#include <QLabel>
#include <QCheckBox>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
​
#include "finddialog.h"
​
FindDialog::FindDialog(QWidget *parent) : QDialog(parent)
{
    // tr()函数调用是把他们翻译成其他语言的标记,在用户可见的字符串周围使用tr()函数是好习惯
    label = new QLabel(tr("Find &what:")); // & 快捷键
    lineEdit = new QLineEdit;
    // 设置行编辑器作为标签的伙伴。伙伴(buddy)为一个窗口部件,可在按下【标签】快捷键时接收焦点
    label->setBuddy(lineEdit);
​
    caseCheckBox = new QCheckBox(tr("Match &case"));
    backwardCheckBox = new QCheckBox(tr("Search &backward"));
    
    findButton = new QPushButton(tr("&Find"));
    // 使Find按钮成为对话框默认按钮,当按下 Enter 会按下默认按钮
    findButton->setDefault(true);
    findButton->setEnabled(false);
    
    closeButton = new QPushButton(tr("Close"));
    
    // QObject::connect,因QObject是FindDialog父对象之一,故可省略前缀QObject::
    connect(lineEdit, SIGNAL(textChanged(const QString &)),
        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() 计算窗口部件“理想”的尺寸大小
    setFixedHeight(sizeHint().height());
    //setMinimumHeight(sizeHint().height());
}
​
void FindDialog::findClicked()
{
    QString text = lineEdit->text();
    Qt::CaseSensitivity cs =
        caseCheckBox->isChecked() ? Qt::CaseSensitive
        : Qt::CaseInsensitive;
    if (backwardCheckBox->isChecked()) 
    {
        //emit Qt关键字
        emit findPrevious(text, cs);
    }
    else 
    {
        emit findNext(text, cs);
    }
}
​
void FindDialog::enableFindButton(const QString &text)
{
    findButton->setEnabled(!text.isEmpty()); // 不为空可以使用
}

 

布局管理类不是窗口部件,它们派生自 QLayout,故也是派生自QObject。在一个运行的应用程序中,布局是不可见的。

不使用“弹簧”分隔符时:

 

对话框中窗口部件和布局时使用了new , 故需要一个调用delete的析构函数,以便删除所创建的每一个窗口部件与布局。

Qt自身会在删除父对象时,自动删除其所属的子对象(子窗体子布局)。

由于类中包含 Q_OBJECT 宏,故qmake生成的makefile会自动包含一些运行moc的规则。moc指Qt的元对象编辑器,即meta-object compiler。

信号和槽

Qt编程的基础。槽和普通c++成员函数几乎是一样的,可以是虚函数;可以被重载;可以是共有的;保护的或者私有的,也可以直接被其他成员函数调用;参数可以是任意类型的。不同点在于:槽可以和信号连接在一起,即当发射信号时。会自动调用这个槽。

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

sender和receiver是指向QObject的指针,signal和slot是不带参数的函数名,SIGNAL()宏和SLOT()宏会把它们的参数转换成相应的字符串。

 

一个信号连接多个槽,触发信号时会以不确定的顺序调用这些槽。

connect(slider, SIGNAL(valueChange(int)), spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChange(int)), this, SLOT(update(int)));

多个信号连接同一个槽

connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()), this, SLOT(handleMathError()));

一个信号连接另一个信号,发射第一个信号时会发射第二个信号。

connect(lineEdit, SIGNAL(textChanged(const QString &)), 
    this, SIGNAL(updateRecord(const QString &)));

连接可以被移除。较少使用。删除对象时,Qt会自动移除和这个对象相关的所有连接

disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));

信号连接到槽或者另一个信号时,需保证它们的参数具有相同的顺序和相同的类型。

connect(ftp, SIGNAL(raw(int, const QString &)), 
    this, SIGNAL(proc(int, const QString &)));

例外情况:当信号参数比槽参数多时,多余的参数会被简单的忽略

connect(ftp, SIGNAL(raw(int, const QString &)), 
    this, SIGNAL(proc(int)));

若信号和槽的名字中包含了参数名,若参数类型不匹配或信号(槽)不存在。Qt会警告。

信号和槽是在QObject中实现的,不局限于图形用户界面编程。可以用于QObject的子类中。

Qt元对象系统

对c++进行了扩展,并创建了独立的软件组件。组件可以绑定在一起,但任何一个组件对于它所要连接的组件的情况事先都一无所知。

元系统两项关键技术:信号-槽 以及 内省(introspection)。内省对于实现信号和槽是必须的,同时允许开发人员在运行时获取关于QObject子类的元信息(meta-information),包含一个含有对象的类名以及它所支持的信号和槽的列表。

C++标准没有对Qt元对象系统所需要的动态元信息提供支持。Qt通过独立的moc工具解决了此问题。moc解析Q_OBJECT类的定义并通过c++来提供可使用的信息。 由于moc使用纯c++实现所有功能,故qt元对象系统可在任意c++编译器上工作。

机制工作:

Q_OBJECT宏声明了在每一个QObject子类中必须实现的一些内省函数:metaObject()、tr()、qt_metacall(),以及其他函数

qt的moc工具生成了由Q_OBJECT声明的所有函数和所有信号的实现

像connect()和disconnect()这样的QObject的成员函数使用这些内省函数来完成它们的工作。

others

 

快捷键:

标签: c++ qt
最后更新:2024年8月26日

九州安所如

程序员

点赞
< 上一篇
下一篇 >

文章评论

razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
取消回复

COPYRIGHT © 2023 zhu

鲁ICP备2026022547号