继承,对于学习C++的每一个人来说,都不会陌生。在Qt的开发中,如果你需要对一个无边框的界面支持move操作,那么你就得通过继承重写虚函数来实现,这并不难,但如果我还需要对一个按钮支持移动,一般情况,当然是Crtl + c 、Crtl + v搞定,但我们不难发现,对于move这个操作来说,其实代码完全一模一样,那么有没有什么办法可以简化,可以一劳永逸呢?
答案是肯定的,这里我们就需要用到C++的模板来实现了,即本文要介绍的链式继承。
前面有实现过move操作,这里将它抽取出来,代码如下:
1: #include
2: #include
3: #include
4:
5: //T 为基类,继续拥有一个QWidget *parent参数的构造函数
6: template <typename T>
7: class WidgetMove : public T
8: {
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
2: #include "widgetmove.h"
3:
4: //间接继承QPushButton,让按钮支持移动
5: class ImgButton : public QPushButton
6: {
7: Q_OBJECT
8: 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
17: #include
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
2: #include
3: #include
4: #include
5: //异形窗体实现
6:
7: //T 为基类,继续拥有一个QWidget *parent参数的构造函数
8: template <typename T>
9: class WidgetRuleless : public T
10: {
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操作,基类为QWidget
2: WidgetRuleless< WidgetMove> wid;
3: wid.SetBackgroundImg("hudie.png");
4: wid.resize(640, 480);
5: //创建一个Button类,并且支持move操作
6: WidgetMovebtn(&wid);
7: btn.move(300,300);
8: wid.show();
简单几行代码,我们就可以得到以下效果:
效果图: 蝴蝶为异形窗体,小树为异形按钮,并且都支持move动作。
这里我们将经常用的小功能(主要是需要通过继承实现的),分解成若干小零件,在日常项目开发中,我们只需要进行简单的组合,就可以得到一个功能强大的控件。
后记:C++是一门异常强大的语言,模板的注入更为C++添加了无穷的潜力,十余年来,他的潜力不断被挖掘出来,但依旧有存在巨大的潜力等待我们去探索,去发现。
注:模板类中不支持Qt信号和槽的机制。