Qt5 C++14教程--事件和信号

在Qt5 C++编程教程的这一部分,我们谈谈事件和信号。

事件是任何GUI程序中的一个重要部分。所有的GUI应用程序都是事件驱动的。一个应用程序对其生命周期中产生的不同事件类型作出反应。事件主要由应用程序的用户产生。但它们也可以由其他方式产生,例如,互联网连接、窗口管理器或计时器。

在事件模型中,有三个参与者:

事件源

事件对象

事件目标

事件源是状态改变的对象。它产生事件。事件对象(Event)封装了事件源的状态变化。事件目标是希望被通知的对象。事件源对象将处理事件的任务委托给事件目标。

当我们调用应用程序的exec方法时,应用程序进入主循环。主循环获取事件并将其发送给对象。Qt有一个独特的信号和槽机制。这种信号和槽机制是对C++编程语言的一种扩展。

信号和槽被用于对象之间的通信。当一个特定的事件发生时,会发出一个信号。槽是一个普通的C++方法;当与之相连的信号被发出时,它被调用。

Qt5点击示例

第一个示例展示了一个非常简单的事件处理示例。我们有一个按钮,通过点击该按钮来终止应用程序。

click.h
#pragma once

#include <QWidget>

class Click : public QWidget {

  public:
    Click(QWidget *parent = nullptr);
};
This is the header file.

click.cpp
#include <QPushButton>
#include <QApplication>
#include <QHBoxLayout>
#include "click.h"

Click::Click(QWidget *parent)
    : QWidget(parent) {

  auto *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);

  auto *quitBtn = new QPushButton("Quit", this);
  hbox->addWidget(quitBtn, 0, Qt::AlignLeft | Qt::AlignTop);

  connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);
}

我们在窗口上显示一个QPushButton。

connect(quitBtn, &QPushButton::clicked, qApp, &QApplication::quit);

connect方法将一个信号连接到一个槽。当我们单击Quit按钮时,将生成clicked信号。qApp是指向应用程序对象的全局指针。它在<QtGui/QApplication>头文件中定义。当clicked信号被发射时,将调用quit方法。

main.cpp
#include <QApplication>
#include "click.h"

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

  QApplication app(argc, argv);

  Click window;

  window.resize(250, 150);
  window.setWindowTitle("Click");
  window.show();

  return app.exec();
}

按键事件

在以下示例中,我们对按键事件作出反应。

keypress.h
#pragma once

#include <QWidget>

class KeyPress : public QWidget {

  public:
    KeyPress(QWidget *parent = 0);

  protected:
    void keyPressEvent(QKeyEvent * e);
};
This is the keypress.h header file.



keypress.cpp
#include <QApplication>
#include <QKeyEvent>
#include "keypress.h"

KeyPress::KeyPress(QWidget *parent)
    : QWidget(parent)
{ }

void KeyPress::keyPressEvent(QKeyEvent *event) {

   if (event->key() == Qt::Key_Escape) {
       qApp->quit();
   }
}

如果按下Esc键,应用程序将终止。

void KeyPress::keyPressEvent(QKeyEvent *e) {

   if (e->key() == Qt::Key_Escape) {
       qApp->quit();
   }
}

其中一种在Qt5中处理事件的方式是重新实现事件处理程序。 QKeyEvent是一个事件对象,它包含有关发生的事件的信息。 在我们的示例中,我们使用事件对象来确定实际按下了哪个键。

main.cpp
#include <QApplication>
#include "keypress.h"

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

  QApplication app(argc, argv);

  KeyPress window;

  window.resize(250, 150);
  window.setWindowTitle("Key press");
  window.show();

  return app.exec();
}

移动事件

QMoveEvent类包含移动事件的事件参数。移动事件被发送到已移动的小部件。

move.h
#pragma once

#include <QMainWindow>

class Move : public QWidget {

  Q_OBJECT

  public:
    Move(QWidget *parent = 0);

  protected:
    void moveEvent(QMoveEvent *e);
};
This is the move.h header file.

move.cpp

#include <QMoveEvent>
#include "move.h"

Move::Move(QWidget *parent)
    : QWidget(parent)
{ }

void Move::moveEvent(QMoveEvent *e) {

  int x = e->pos().x();
  int y = e->pos().y();

  QString text = QString::number(x) + "," + QString::number(y);

  setWindowTitle(text);
}

在我们的代码示例中,我们对移动事件作出反应。我们确定窗口客户区域左上角的当前x、y坐标,并将这些值设置为窗口的标题。

int x = e->pos().x();

int y = e->pos().y();

我们使用QMoveEvent对象来确定x、y值。

QString text = QString::number(x) + "," + QString::number(y);

我们将整数值转换为字符串。

setWindowTitle(text);

setWindowTitle方法将文本设置为窗口的标题。

main.cpp
#include <QApplication>
#include "move.h"

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

  QApplication app(argc, argv);

  Move window;

  window.resize(250, 150);
  window.setWindowTitle("Move");
  window.show();

  return app.exec();
}

断开一个信号

可以将信号从槽中断开连接。下面的示例展示了如何实现这一点。

disconnect.h
#pragma once

#include <QWidget>
#include <QPushButton>

class Disconnect : public QWidget {

  Q_OBJECT

  public:
    Disconnect(QWidget *parent = 0);

  private slots:
    void onClick();
    void onCheck(int);

  private:
    QPushButton *clickBtn;
};

在头文件中,我们声明了两个槽。slots 不是 C++ 的关键字,它是 Qt5 的扩展。这些扩展由预处理器在代码编译之前处理。当我们在我们的类中使用信号和槽时,我们必须在类定义的开头提供一个 Q_OBJECT 宏。否则,预处理器会报错。

disconnect.cpp
#include <QTextStream>
#include <QCheckBox>
#include <QHBoxLayout>
#include "disconnect.h"

Disconnect::Disconnect(QWidget *parent)
    : QWidget(parent) {

  QHBoxLayout *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);

  clickBtn = new QPushButton("Click", this);
  hbox->addWidget(clickBtn, 0, Qt::AlignLeft | Qt::AlignTop);

  QCheckBox *cb = new QCheckBox("Connect", this);
  cb->setCheckState(Qt::Checked);
  hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop);

  connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck);
}

void Disconnect::onClick() {

  QTextStream out(stdout);
  out << "Button clicked" << endl;
}

void Disconnect::onCheck(int state) {

  if (state == Qt::Checked) {
    connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  } else {
    disconnect(clickBtn, &QPushButton::clicked, this,
        &Disconnect::onClick);
  }
}

在我们的示例中,我们有一个按钮和一个复选框。复选框将一个槽连接和断开连接到按钮的 clicked 信号。该示例必须从命令行中执行。

connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);

connect(cb, &QCheckBox::stateChanged, this, &Disconnect::onCheck);

在这里,我们将信号连接到我们的用户定义槽。

void Disconnect::onClick() {

  QTextStream out(stdout);
  out << "Button clicked" << endl;
}

如果我们点击 Click 按钮,我们将把“Button clicked”文本发送到终端窗口。

void Disconnect::onCheck(int state) {

  if (state == Qt::Checked) {
    connect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  } else {
    disconnect(clickBtn, &QPushButton::clicked, this, &Disconnect::onClick);
  }
}

在 onCheck 槽内部,我们根据接收到的状态连接或断开连接到 Click 按钮的 onClick 槽。

main.cpp
#include <QApplication>
#include "disconnect.h"

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

  QApplication app(argc, argv);

  Disconnect window;

  window.resize(250, 150);
  window.setWindowTitle("Disconnect");
  window.show();

  return app.exec();
}

定时器

定时器用于实现单次或重复性任务。一个常见的例子是时钟,每秒钟我们需要更新显示当前时间的标签。

timer.h
#pragma once

#include <QWidget>
#include <QLabel>

class Timer : public QWidget {

  public:
    Timer(QWidget *parent = 0);

  protected:
    void timerEvent(QTimerEvent *e);

  private:
    QLabel *label;
};

timer.cpp

#include "timer.h"
#include <QHBoxLayout>
#include <QTime>

Timer::Timer(QWidget *parent)
    : QWidget(parent) {

  QHBoxLayout *hbox = new QHBoxLayout(this);
  hbox->setSpacing(5);

  label = new QLabel("", this);
  hbox->addWidget(label, 0, Qt::AlignLeft | Qt::AlignTop);

  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);

  startTimer(1000);
}

void Timer::timerEvent(QTimerEvent *e) {

  Q_UNUSED(e);

  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);
}

在这个例子中,我们在窗口上显示当前本地时间。

label = new QLabel("", this);

为了显示时间,我们使用了一个标签部件。

QTime qtime = QTime::currentTime();

QString stime = qtime.toString();

label->setText(stime);

这里我们确定当前本地时间并将其设置为标签部件。

startTimer(1000);

我们启动计时器。每隔1000毫秒就会生成一个计时器事件。

void Timer::timerEvent(QTimerEvent *e) {

  Q_UNUSED(e);

  QTime qtime = QTime::currentTime();
  QString stime = qtime.toString();
  label->setText(stime);
}

为了处理计时器事件,我们必须重新实现timerEvent方法。

main.cpp
#include <QApplication>
#include "timer.h"

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

  QApplication app(argc, argv);

  Timer window;

  window.resize(250, 150);
  window.setWindowTitle("Timer");
  window.show();

  return app.exec();
}

这是主文件。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 第一章 开发环境 1.1 Qt 简介5 1.2 下载安装 Qt Creator 6 1.3 第一个程序 Hello World 7 第二章 窗体应用 1.1 窗体基类说明 12 1.2 控制窗体大小 13 1.3 窗体初始位置及背景色 13 1.4 修改标题栏图标 14 1.5 移动无边框窗体 16 1.6 去掉标题栏中最大化、最小化按钮 17 1.7 多窗体调用 18 1.8 字体形状窗体 20 第三章 控件应用 1.1 QPushButton按钮 23 1.2 QLabel标签 23 1.3 QLineEdit单行文本 24 1.4 QTextEdit多行文本 25 1.5 QPlainTextEdit多行文本 26 1.6 QComboBox下拉列表框 26 1.7 QFontComboBox字体下拉列表框 27 1.8 QSpinBox控件 28 1.9 QTimeEdit时间控件 29 1.10 QDateEdit日期控件 30 1.11 QScrollBar控件 30 1.12 QRadioButton单选按钮 31 1.13 QCheckBox复选框 32 1.14 QListView 列表控件 34 1.15 QTreeView树控件 34 1.16 QTableView表格控件 35 1.17 QHBoxLayout横向布局 36 1.18 QGridLayout网格布局 37 1.19 QGroupBox控件 38 1.20 QTabWidget控件 39 1.21 QMenu、QToolBar控件 41 1.22 任务栏托盘菜单 43 第四章 组件应用 1.1日历组件 47 1.2登录窗口 48 1.3文件浏览对话框 50 1.4颜色选择对话框 51 1.5进度条实例53 1.6Timer实时更新时间 54 第五章 文件操作 1.1创建文件夹 57 1.2写入文件 58 1.3修改文件内容 60 1.4删除文件 62 1.5修改文件名 63 1.6 INI文件写入操作 65 1.7 INI文件读取操作 68 1.8创建XML文件 71 1.9读取XML文件 72 第六章 图形图像操作 1.1绘制文字 75 1.2绘制线条 75 1.3绘制椭圆 77 1.4显示静态图像 78 1.5显示动态图像 78 1.6图片水平移动 79 1.7图片翻转 80 1.8图片缩放 82 1.9图片中加文字 84 1.10图像扭曲 85 1.11模糊效果 85 1.12着色效果 86 1.13阴影效果 87 1.14透明效果 87 第七章 多媒体应用 1.1音频、视频播放器 90 1.2播放Flash动画 94 1.3播放图片动画 95 第八章 系统操作 1.1获取屏幕分辨率 98 1.2获取本机名、IP地址 98 1.3根据网址获取IP地址 99 1.4判断键盘按下键值 100 1.5获取系统环境变量 101 1.6执行系统命令 102 第九章 注册表 1.0简要说明注册表 105 1.1写入注册表 105 1.2查找注册表 106 1.3修改IE浏览器的默认主页 107 第十章 数据库基础 1.1查询数据库驱动 109 1.2Qodbc连接Access数据库 109 1.3插入数据 111 1.4数据列表 112 1.5操作SQLite数据库 113 1.6SQLite数据库视图管理器 115 第十一章 网络开发 1.1点对点聊天服务端 119 1.2点对点聊天客户端 123 1.3局域网广播聊天 128 1.4SMTP协议发送邮件 148 1.5调用系统DLL判断网络连接状态 152 第十二章 进程与线程 1.1进程管理器 155 1.2线程QThread应用 158 1.3线程QRunnable应用 159 第十三章 数据安全 1.1 QByteArray加密数据 163 1.2 AES加密数据 164 1.3 MD5 加密数据 165 1.4 生成随机数 166 第十四章 打包部署 1.1 FilePacker 打包 169 1.2 Inno Setup 打包 174

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值