C++链式继承
继承,对于学习C++的每一个人来说,都不会陌生。在Qt的开发中,如果你需要对一个无边框的界面支持move操作,那么你就得通过继承重写虚函数来实现,这并不难,但如果我还需要对一个按钮支持移动,一般情况,当然是Crtl + c 、Crtl + v搞定,但我们不难发现,对于move这个操作来说,其实代码完全一模一样,那么有没有什么办法可以简化,可以一劳永逸呢?
答案是肯定的,这里我们就需要用到C++的模板来实现了,即本文要介绍的链式继承。
前面有实现过move操作,这里将它抽取出来,代码如下:
1: #include <QWidget>2: #include <QMouseEvent>3: #include <QPoint>4:5: //T 为基类,继续拥有一个QWidget *parent参数的构造函数6: template <typename T>7: class WidgetMove : public T8: {9: public:10: WidgetMove(QWidget *parent = 0):T(parent)11: {12: }13: protected:14: void mousePressEvent(QMouseEvent *event)15: {16: //当鼠标左键按下时,记录当前位置17: if(event->button() == Qt::LeftButton)18: {19: m_CurrentPos = event->globalPos() - T::frameGeometry().topLeft();20: event->accept();21: }22: T::mousePressEvent(event);23: }24:25: void mouseMoveEvent(QMouseEvent *event)26: {27: //支持窗体移动28: if (event->buttons() & Qt::LeftButton)29: {30: T::move(event->globalPos() - m_CurrentPos);31: event->accept();32: }33: T::mouseMoveEvent(event);34: }35: private:36: QPoint m_CurrentPos;37: };
接下来我们实现一个图片按钮:
1: #include <QPushButton>2: #include "widgetmove.h"3:4: //间接继承QPushButton,让按钮支持移动5: class ImgButton : public QPushButton6: {7: Q_OBJECT8: public:9: explicit ImgButton(QWidget *parent = 0);10: void paintEvent(QPaintEvent *event);11: QPixmap m_Pixmap;12: };13:14:15: #include "imgbutton.h"16: #include <QIcon>17: #include <QBitmap>18:19: ImgButton::ImgButton(QWidget *parent) :20: QPushButton(parent)21: {22: //必须设置为无边框,否则可见区域和图片绘制区域将出现不重叠23: setWindowFlags( Qt::FramelessWindowHint );24: m_Pixmap.load("close.png");25: resize(100,100);26: m_Pixmap = m_Pixmap.scaled(this->size(),Qt::IgnoreAspectRatio);27: }28:29: void ImgButton::paintEvent(QPaintEvent *event)30: {31: //绘制背景图片32: QIcon icon(m_Pixmap);33: this->setIcon(icon);34: this->setIconSize(size());35: //将png图片透明部分设置为穿透36: this->setMask(m_Pixmap.mask());37: //绘制38: QPushButton::paintEvent(event);39: }
然后我们把异形窗体重新实现了:
1: #include <QString>2: #include <QBitmap>3: #include <QPaintEvent>4: #include <QPalette>5: //异形窗体实现6:7: //T 为基类,继续拥有一个QWidget *parent参数的构造函数8: template <typename T>9: class WidgetRuleless : public T10: {11: public:12: WidgetRuleless(QWidget *parent = 0):T(parent)13: {14: //设置为无边框15: T::setWindowFlags( Qt::FramelessWindowHint );16: }17: void SetBackgroundImg(const QString &imgFile)18: {19: m_Pixmap.load(imgFile);20:21: //保持图片跟界面一样大小22: m_Pixmap = m_Pixmap.scaled(T::size());23:24: T::setAutoFillBackground(true);25:26: //不规则窗口的关键,将图片透明的地方设为穿透27: T::setMask( m_Pixmap.mask() );28: }29: protected:30: void paintEvent(QPaintEvent *event)31: {32: if(!m_Pixmap.isNull())33: {34: //绘制背景图片35: QPalette bgPalette = this->palette();36: bgPalette.setBrush(QPalette::Background,m_Pixmap);37: T::setPalette(bgPalette);38: }39: }40:41: private:42: QPixmap m_Pixmap;43: };
组件准备好后,我们就可以轻松的使用了
1: //创建一个异形窗体,支持move操作,基类为QWidget2: WidgetRuleless< WidgetMove<QWidget> > wid;3: wid.SetBackgroundImg("hudie.png");4: wid.resize(640, 480);5: //创建一个Button类,并且支持move操作6: WidgetMove<ImgButton> btn(&wid);7: btn.move(300,300);8: wid.show();
简单几行代码,我们就可以得到以下效果:
效果图: 蝴蝶为异形窗体,小树为异形按钮,并且都支持move动作。

这里我们将经常用的小功能(主要是需要通过继承实现的),分解成若干小零件,在日常项目开发中,我们只需要进行简单的组合,就可以得到一个功能强大的控件。
后记:C++是一门异常强大的语言,模板的注入更为C++添加了无穷的潜力,十余年来,他的潜力不断被挖掘出来,但依旧有存在巨大的潜力等待我们去探索,去发现。
注:模板类中不支持Qt信号和槽的机制。
C++链式继承的更多相关文章
- ThinkPHP通过类的链式继承优化空操作的实现
上篇<ThinkPHP空操作和空控制器的处理>中,在处理空操作时修改了父类Controller.class.php中代码,不到万不得已不能 修改基类控制器中的原码,此时可在子类与父类之间, ...
- C++ 链式继承下的虚函数列表
目录 1.虚函数列表的位置 2.虚函数列表的内容 3.链式继承中虚函数列表的内容 注: 虚函数列表 又称为虚表, vtbl , 指向它的指针称为vptr, vs2019中称为__vfptr 操作系 ...
- 读书笔记之 - javascript 设计模式 - 接口、封装和链式调用
javascript 采用设计模式主要有下面的三方面原因: 可维护性:设计模式有助于降低模块之间的耦合程度.这使代码进行重构和换用不同的模块变得容易,也使程序员在大型项目中合作变得容易. 沟通:设计模 ...
- JavaScript中的原型链和继承
理解原型链 在 JavaScript 的世界中,函数是一等公民. 上面这句话在很多地方都看到过.用我自己的话来理解就是:函数既当爹又当妈."当爹"是因为我们用函数去处理各种&quo ...
- 使用Object.create()实现继承 用 Object.create实现类式继承
使用Object.create()实现继承:https://www.cnblogs.com/cuew1987/p/4075027.html 用 Object.create实现类式继承:https:// ...
- JavaScript继承基础讲解,原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承
说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象J ...
- JS高级. 03 混入式继承/原型继承/经典继承、拓展内置对象、原型链、创建函数的方式、arguments、eval、静态成员、实例成员、instanceof/是否在同一个原型链
继承:当前对象没有的属性和方法,别人有,拿来给自己用,就是继承 1 混入式继承 var I={ }; var obj = { name: 'jack', age:18, sayGoodbye : fu ...
- JavaScript ES5类 原型 原型链 组合、原型、寄生式继承
ES5类 原型 原型链 继承 JavaScript中,原型是相对于构造函数(类)的叫法(或者说概念),原型链是相对于构造函数(类)的实例对象的叫法. 对于JavaScript对象,如果在对象自身上找 ...
- 如何写 JS 的链式调用 ---》JS 设计模式《----方法的链式调用
1.以$ 函数为例.通常返回一个HTML元素或一个元素集合. 代码如下: function $(){ var elements = []; ;i<arguments.length;i++){ v ...
随机推荐
- c# 路径空格---ProcessStartInfo参数问题
今天在整合程序的时候,要从一个程序转到另一个程序 当然要使用: ProcessStartInfo startInfo = new ProcessStartInfo("\\Program ...
- android 表情,软键盘冲突解决方案(仿微博等SNS应用)
之前总想搞一下这个模块,可是由于忙碌总是推迟,现在就把这块好好的弥补过来,下面是我实现的思路.本人才疏学浅,还望大家不要见笑. 首先我们还是先看写示例: 上面应用应该不用我过多介 ...
- -_-#【JS】defer / async
引用JavaScript文件时的两个属性defer和async <script src="js1.js" defer></script> <scrip ...
- debian创建apt-proxy代理
由于公司网络比较慢.所以需要建立一个代理服务器或镜象站点!考虑到创建和维护镜象的投入比较大!所以选择apt-proxy代理来做!可以缓解公司带宽不足的矛盾.而且只有在代理缓存,没有相应组件的情况下才去 ...
- Line Search and Quasi-Newton Methods
Gradient Descent 机器学习中很多模型的参数估计都要用到优化算法,梯度下降是其中最简单也用得最多的优化算法之一.梯度下降(Gradient Descent)[3]也被称之为最快梯度(St ...
- linux下获取ip
如果打开虚拟机 没有ip置灰显示了 lo 可以使用dhclient自动获取ip 如果想开机就自动获取ip: vim /etc/rc.d/rc.local 在这里插入dhclient命令
- [改善Java代码]覆写equals方法必须覆写hashCode方法
覆写equals方法必须覆写hashCode方法,这条规则基本上每个Javaer都知道,这也是JDK API上反复说明的,不过为什么要这样做呢?这两个方法之间有什么关系呢?本建议就来解释该问题,我们先 ...
- [未完成]关于CSS的总结
CSS和html 数据和样式分离,在java中称为降低了耦合性. css和html相结合的第一种方式. 1,每一个html标签中都有一个style样式属性.该属性的值就是css代码. 2,使用styl ...
- Wince 中的图形编程
图形编程程序当中,笔者主要要和大家讨论的是画刷的创建和使用以及绘图函数,比如2D图像的绘制等等. *画刷的定义: HBRUSH hBrush; *画刷的类型: 1. 系统内置画刷:GetStockOb ...
- 【简单dp+模拟】hdu-5375(2015多校#7-1007)
给你一个二进制数,,每一位有一个权值,让你转格雷码,求所对应格雷码位为1的权值的和:二进制位中的某些位为?,你需要给这些问号赋值使得到的和最大. 首先你得知道二进制转格雷码的规则,即格雷码位为[二进制 ...