简介

这个例子显示了如何使用信号和槽来创建自定义窗口部件,和如何使用更加复杂的方式把它们连接起来。基本上一个内容相同,变成了三个文件,并增加了后面滑块控制前面滑块的功能。

lcdrange.h包含LCDRange类定义
lcdrange.cpp包含LCDRange类实现
main.cpp包含MyWidget和main

lcdrange.h

#ifndef LCDRANGE_H
#define LCDRANGE_H
#include <QVBoxLayout>
#include <QWidget>class QSlider;class LCDRange:public QWidget
{Q_OBJECT;
public:LCDRange(QWidget *parent = 0);int value() const;//查询滑块的值
public slots:void setValue(int);//设置滑块的值
signals:void valueChanged(int);
private:QSlider *slider;};#endif // LCDRANGE_H

#ifndef LCDRANGE_H
#define LCDRANGE_H

这里是一个经典的 C 语句,为了避免出现一个头文件被包含不止一次的情况。如果你没有使用过它,这是开发中的一个很好的习惯。#ifndef 需要把这个头文件的全部都包含进去。

class QSlider;
这里是另外一个小伎俩,但是没有前一个用的多。因为我们在类的界面中不需要QSlider,仅仅是在实现中,我们在头文件中使用一个前置的类声明,并且在.cpp文件中包含一个 QSlider 的头文件。

这会使编译一个大的项目变得更快,因为当一个头文件改变的时候,很少的文件需要重新编译。它通常可以给大型编译加速两倍或两倍以上。

Q_OBJECT
这个宏必须被包含到所有使用信号和/或槽的类。如果你很好奇,它定义了在元对象文件中实现的一些函数。

下面这三个成员函数构成了这个窗口部件和程序中其它组件的接口。直到现在,LCDRange 根本没有一个真正的接口。
int value() const
一个可以访问 LCDRange 的值的公共函数。

void setValue(int)
setValue()是我们第一个自定义槽。

void valueChanged(int)
我们第一个自定义信号。

槽必须按通常的方式实现(记住槽也是一个 C++成员函数)。信号可以在元对象文件中自动实现。信号也遵守 C++函数的保护法则(比如,一个类只能发射它自己定义的或者继承来的信号)。

当 LCDRange 的值发生变化时,valueChanged()信号就会被使用——你从这个名字中就可以猜到。这将不会是你将会看到的命名为 somethingChanged()的最后一个信号。

lcdrange.cpp

#include "lcdrange.h"#include <QSlider>
#include <QLCDNumber>LCDRange::LCDRange(QWidget *parent):QWidget(parent)
{QLCDNumber *lcd = new QLCDNumber(2);slider = new QSlider(Qt::Horizontal);slider->setRange(0,99);slider->setValue(10);connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));connect(slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)));QVBoxLayout *part = new QVBoxLayout;part->addWidget(lcd);part->addWidget(slider);setLayout(part);
}int LCDRange::value() const
{return slider->value();
}void LCDRange::setValue(int value)
{slider->setValue(value);
}

connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)), SIGNAL(valueChanged(int)));

这个代码来自 LCDRange 的构造函数。

第一个 connect 和你在上一章中看到的一样。第二个是新的,它把滑块的valueChanged()信号和这个对象的 valueChanged 信号连接起来了。带有三个参数的 connect()函数连接到 this 对象的信号或槽。

是的,这是正确的。信号可以被连接到其它的信号。当第一个信号被发射时,第二个号也被发射。 让我们来看看当用户操作这个滑块的时候都发生了些什么。滑块看到自己的值发生了改变,并发射了 valueChanged()信号。这个信号被连接到 QLCDNumber 的display()槽和 LCDRange 的 valueChanged()信号。

所以,当这个信号被发射的时候,LCDRange 发射它自己的 valueChanged()信号。

另外,QLCDNumber::display()被调用并显示新的数字。

注意你并没有保证执行的任何顺序——LCDRange::valueChanged()也许在QLCDNumber::display()之前或者之后发射,这是完全任意的。

slider->value()
value()的实现是直接了当的,它简单地返回滑块的值。

slider->setValue(value)
setValue()的实现是相当直接了当的。注意因为滑块和 LCD 数字是连接的,设置滑块的值就会自动的改变 LCD 数字的值。另外,如果滑块的值超过了合法范围,它会自动调节。

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QFont>
#include <QSlider>
#include <QLCDNumber>
#include <QVBoxLayout>
#include <QGridLayout>#include "lcdrange.h"class MyWidget:public QWidget
{public:MyWidget(QWidget *parent = 0);};MyWidget::MyWidget(QWidget *parent):QWidget(parent)
{QPushButton *quit = new QPushButton("Quit");quit->setFont(QFont("Times",18,QFont::Bold));connect(quit,SIGNAL(clicked()),qApp,SLOT(quit()));QGridLayout *grid = new QGridLayout;LCDRange *previous = 0;for(int r = 0; r < 4; r++)for(int c = 0; c < 4; c++){LCDRange *lcdRange = new LCDRange;grid->addWidget(lcdRange, r, c);if(previous)connect(lcdRange, SIGNAL(valueChanged(int)), previous, SLOT(setValue(int)));previous = lcdRange;}QVBoxLayout *layout = new QVBoxLayout;layout->addWidget(quit);layout->addLayout(grid);setLayout(layout);}int main(int argc, char *argv[])
{QApplication a(argc, argv);MyWidget w;w.show();return a.exec();
}

当我们创建 16 个 RCDRange 对象时,我们现在使用信号/槽机制连接它们。每一个的valueChanged()信号都和前一个的 setValue()槽连接起来了。因为当 LCDRange 的值发生改变的时候,发射一个 valueChanged()信号(惊奇!),我们在这里创建了一个信号和槽的“链”。

Q4_一个事物领导另一个相关推荐

  1. 一个典型的后台软件系统的设计复盘——(二)如何id一个事物

    这个话题,可以从类与对象说起. Dog dog1 = new Dog(); 哪个是类,哪个是对象?这个问题搞不清楚,后面就无从说起了.然后两个程序员之间沟通说,那个狗有问题.除非两人很默契,不然另一人 ...

  2. mysql一个事务多个log_MySQL识别一个binlog中的一个事物

    MySQL测试版本5.7.14 设置GTID_MODE=ON ON(3): Both new and replicated transactions must be GTID transactions ...

  3. 一个事物两个方面的对比举例_对比属于修辞手法吗

    对比属于修辞手法吗2020-08-17 14:41:53文/张孟影 对比是一种修辞手法.对比是把两个相反.相对的事物或同一事物相反.相对的两个方面放在一起,用比较的方法加以描述或说明,这种写作手法叫对 ...

  4. 如何成为一个搞垮领导的下属?

    点击"技术领导力"关注∆  每天早上8:30推送 作者| Mr.K   整理| Emma 来源| 技术领导力(ID:jishulingdaoli) 老K·伊万诺维奇·门捷列夫,曾说 ...

  5. mave工程中的一个类调用另一个聚合工程的一个类_信息系统管理工程师备考分享(材料重点精炼)——第一章信息化和信息系统(4)...

    本章分享的1.4节的重要考点内容相对来说还是比较多的,里面包括需求.设计.测试等软件工程的内容,同学们学完前几篇文章的分享会发现,第一章与计算机领域的知识的衔接程度还是非常紧密的.我经常会听到很多面授 ...

  6. vtk删除一个actor_如何构建一个基于actor的简单区块链

    vtk删除一个actor Scalachain is a blockchain built using the Scala programming language and the actor mod ...

  7. 为一个 iOS 应用编写一个简单的 Node.js/MongoDB Web 服务

    原文链接:https://github.com/nixzhu/dev-blog/blob/master/2014-04-21-write-a-simple-nodejs-mongodb-web-ser ...

  8. 什么是继承?Java中如何声明一个类继承另一个类?

    在现实生活中,说到继承,多会想到子女继承父辈的财产.事业等.在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关联体系.例如猫和狗都属于动物,程序中便可以描述为猫和狗继承自动 ...

  9. c语言程序只能有一个源程序文件,下列说法哪个正确?() A.一个程序可以包含多个源文件 B.一个源文件中只能有一个类 C.一个源文件中可以...

    下列说法哪个正确?() A.一个程序可以包含多个源文件 B.一个源文件中只能有一个类 C.一个源文件中可以 更多相关问题 [问答题,简答题] 古埃及服饰中时常看到"蛇"." ...

最新文章

  1. Adam真的是最好的优化器吗?
  2. 国际财务报告准则 IFRS 与信息系统
  3. golang获取当前正规时间
  4. leetcode-121-买卖股票的最佳时机
  5. 如何更加简单的理解JS中的原型原型链概念
  6. htaccess文件,强大的功能
  7. JEECG 商业版本和开源版本有什么区别呢?
  8. ThreadLocal类的实现用法
  9. 教你用磁盘分区软件无损扩容c盘的方法
  10. Oracle导入导出二进制文件,你不知道的事
  11. mpush 搭建消息服务器,mpush学习笔记windows服务器部署(一)
  12. vm虚拟机配置动态ip和静态ip的方法
  13. 何小鹏快跑:身家暴涨50亿美元,他还愿坐经济舱吗?
  14. php 0x80004005,错误类型:Provider (0x80004005)未指定的错误 的一个处理方法
  15. 关于调制比、过调制、基波电压和母线电压的概念和关系总结
  16. mysql历史表_MySQL历史表设计和查询
  17. 写出语句的四元式序列
  18. Tomcat学习之路
  19. ckeditor5 全屏功能
  20. electron打包的一些问题

热门文章

  1. hdfs用fileutil读取文件内容_MoviePy - 用Python玩转视频剪辑!(MoviePy安装及视频文件读取)
  2. 将系统升级为鸿蒙11.1系统,即将脱胎换骨!EMUI11.1升级名单遭曝光,或要和跟安卓说再见...
  3. 蜘蛛日志分析工具_如何分析蜘蛛日志?
  4. secureCRT 如何上传下载文件
  5. 关于手机端适配的问题(rem,页面缩放)
  6. java第三次实验作业
  7. Websphere 手动模拟删除应用操作
  8. UIKit框架-高级控件Swift版本: 5.UITextView方法/属性详解
  9. 红黑树(Red-Black Tree)
  10. Java发送HTTP POST请求(内容为xml格式)