• 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 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 <QPushButton>
    
      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 <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 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<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动作。

    image

    这里我们将经常用的小功能(主要是需要通过继承实现的),分解成若干小零件,在日常项目开发中,我们只需要进行简单的组合,就可以得到一个功能强大的控件。

    后记:C++是一门异常强大的语言,模板的注入更为C++添加了无穷的潜力,十余年来,他的潜力不断被挖掘出来,但依旧有存在巨大的潜力等待我们去探索,去发现。

    注:模板类中不支持Qt信号和槽的机制。

  • 相关阅读:
    Java的三种代理模式
    关于C# 中的Attribute 特性
    jvm虚拟机原理1
    Java和C#中的接口对比(有你不知道的东西)
    c# 方法参数(传值,传引用,ref,out,params,可选参数,命名参数)
    Java运行时,各种类型存储介绍
    Java中的内存处理机制和final、static、final static总结
    Debug目录、Release目录,bin目录、obj目录,vshost.exe.config文件、.exe.config文件分析【C#】
    C#有关的vshost、exe、config格式说明
    C#中的程序集和命名空间
  • 原文地址:https://www.cnblogs.com/lingluotianya/p/4430190.html
Copyright © 2020-2023  润新知