QT自绘控件

一、QT自绘控件有两种方式
1、从QWidget或QFrame继承实现了一个自定义的widget,重写void paintEvent(QPaintEvent * event)函数,然后在这个函数里利用QPainter类进行绘制。
2、qml中canvas

二、什么情况下调用paintEvent
当发生一下情况时会产生绘制事件并调用paintEvent()函数:
1、在窗口部件第一次显示时,系统会自动产生一个绘图事件,从而强制绘制这个窗口部件。
2、当重新调整窗口部件的大小时,系统也会产生一个绘制事件。
3、当窗口部件被其他窗口部件遮挡,然后又再次显示出来的时候,就会对那些隐藏的区域产生一个绘制事件。
同时可以调用QWidget::update()或者QWidget::repaint()来强制产生一个绘制事件。二者的区别是:
repaint()函数会强制产生一个即时的重绘事件,而update()函数只是在Qt下一次处理事件时才调用一次绘制事件。
如果多次调用update(),Qt会把连续多次的绘制事件压缩成一个单一的绘制事件,这样可避免闪烁现象。

三、QFrame与QWidget的区别
QFrame是基本控件的基类,QWidget是QFrame基类,关系如下:
QPushButton,QLabel… -> QFrame -> QWidget
QFrame可以设置样式表,另外QFrame窗口显示边框,而QWidget默认不显示边框。

#include <QWidget>
#include <QFrame>
namespace Ui {
class Dialog;
}

class MyWidget : public QWidget {
    Q_OBJECT
public:
    MyWidget(QWidget *parent = 0) : QWidget(parent) {
        //this->setStyleSheet("QWidget{background:#ff0000;} QWidget:hover{background:#00ff00;}");//样式不起作用
    }
};

class MyFrame : public QFrame {
    Q_OBJECT
public:
    MyFrame(QWidget *parent = 0) : QFrame(parent) {
        this->setStyleSheet("QWidget{background:#ff0000;} QWidget:hover{background:#00ff00;}");
    }
};

四、实例
paintEvent方法
Qt 中没有专门显示图片的控件,通常我们会使用QLabel来显示图片。但是QLabel 显示图片的能力还是有点弱。比如不支持图像的缩放一类的功能,使用起来不是很方便。因此我就自己写了个简单的类。
转载https://www.cnblogs.com/findumars/p/6546096.html
我这个类支持三种图像显示模式,我分别称之为:FIXED_SIZE, CENTRED,AUTO_ZOOM, AUTO_SIZE。
FIXED_SIZE 模式下,显示的图像大小等于图像尺寸乘以缩放因子,如果控件的尺寸小于这个大小则多出的部分被裁切掉。
FIX_SIZE_CENTRED模式与FIXED_SIZE 模式类似,但是,显示的图像居于窗口正中。
AUTO_ZOOM 模式下,显示的图像大小自动适应控件窗口大小。
AUTO_SIZE 模式下,这个控件的尺寸等于图像尺寸乘以缩放因子。
//代码

//PictureBox.h
#ifndef PICTUREBOX_H
#define PICTUREBOX_H
 
#include <QWidget>
#include <QImage>
#include <QPixmap>
 
 
class PictureBox : public QWidget
{    
    Q_OBJECT
public:
    enum PB_MODE {FIXED_SIZE, FIX_SIZE_CENTRED, AUTO_ZOOM, AUTO_SIZE};
    explicit PictureBox(QWidget *parent = 0);
    void setMode(PB_MODE mode);
    ~PictureBox();
private:
    QPixmap m_pixmap;
    double m_scale;
    PB_MODE m_mode;
    QBrush m_brush;
protected:
    void paintEvent(QPaintEvent * event);
signals:
 
public slots:
    bool setImage(QImage &image, double scale = 1.0);
    void setBackground(QBrush brush);
};
 
#endif // PICTUREBOX_H
//PictureBox.cpp
#include "picturebox.h"
#include <QPainter>
#include <QDebug>
static const int IMAGE_WIDTH = 160;
static const int IMAGE_HEIGHT = 120;
static const QSize IMAGE_SIZE = QSize(IMAGE_WIDTH, IMAGE_HEIGHT);
 
PictureBox::PictureBox(QWidget *parent) : QWidget(parent)
{
    m_pixmap = QPixmap(IMAGE_SIZE);
    m_pixmap.fill();
    m_scale = 1.0;
    m_mode = FIXED_SIZE;
    m_brush = QBrush(Qt::white);
}
 
void PictureBox::setBackground(QBrush brush)
{
    m_brush = brush;
    update();
}
 
void PictureBox::setMode(PB_MODE mode)
{
    m_mode = mode;
    if(m_mode == AUTO_SIZE)
    {
        setFixedSize(m_pixmap.size() * m_scale);
    }
    else
    {
        setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
        setMinimumSize(0, 0);
    }
    update();
}
 
bool PictureBox::setImage(QImage &image, double scale)
{
    if(image.isNull())
    {
        return false;
    }
    m_pixmap = QPixmap::fromImage(image);
    m_scale = qBound(0.01, scale, 100.0);
    if(m_mode == AUTO_SIZE)
    {
        setFixedSize(m_pixmap.size() * m_scale);
    }
    update();
    return true;
}
 
void PictureBox::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setBackground(m_brush);
    painter.eraseRect(rect());
 
    double window_width, window_height;
    double image_width, image_height;
    double r1, r2, r;
    int offset_x, offset_y;
    switch (m_mode)
    {
    case FIXED_SIZE:
    case AUTO_SIZE:
        painter.scale(m_scale, m_scale);
        painter.drawPixmap(0, 0, m_pixmap);
        break;
    case FIX_SIZE_CENTRED:
        window_width = width();
        window_height = height();
        image_width = m_pixmap.width();
        image_height = m_pixmap.height();
        offset_x = (window_width - m_scale * image_width) / 2;
        offset_y = (window_height - m_scale * image_height) / 2;
        painter.translate(offset_x, offset_y);
        painter.scale(m_scale, m_scale);
        painter.drawPixmap(0, 0, m_pixmap);
        break;
    case AUTO_ZOOM:
        window_width = width();
        window_height = height();
        image_width = m_pixmap.width();
        image_height = m_pixmap.height();
        r1 = window_width / image_width;
        r2 = window_height / image_height;
        r = qMin(r1, r2);
        offset_x = (window_width - r * image_width) / 2;
        offset_y = (window_height - r * image_height) / 2;
        painter.translate(offset_x, offset_y);
        painter.scale(r, r);
        painter.drawPixmap(0, 0, m_pixmap);
        break;
    }
}
 
PictureBox::~PictureBox()
{
 
}


qml方法

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls.Material 2.2
import QtQuick.Controls.Styles 1.4
import "../CustomComponent"

Rectangle{
    id: rhomboidButton
    implicitWidth: mw
    implicitHeight: mh
    border.width: 0
    color: Qt.rgba(0.2, 0.2, 0.2, 0);

    property int mw : 150           //边框宽度
    property int mh : 40             //边框高度
    property int padding: 4
    property int gap : (mh-2*padding)/2;

    property string outlineColor: "#FF8100"
    property string shadowColor:  "#FF9800"
    property string textColor:      "#64FF98"
    
    property string title: "展示线路"
    signal buttonClicked()
    
    states: [
            State {
                name: "default"
                PropertyChanges { target: titleText; opacity: 0.5 }
                PropertyChanges { target: outline; opacity: 0.5 }
                PropertyChanges { target: aniCircle1; opacity: 0.5 }
                PropertyChanges { target: aniCircle2; opacity: 0.5 }
            },
            State {
                name: "hovered"
                PropertyChanges { target: titleText; opacity: 1 }
                PropertyChanges { target: outline; opacity: 1 }
                PropertyChanges { target: aniCircle1; opacity: 1 }
                PropertyChanges { target: aniCircle2; opacity: 1 }
            }
        ]

    state: "default"

    MouseArea{
        anchors.fill: parent
        acceptedButtons: Qt.LeftButton
        hoverEnabled: true
        onClicked: {
            buttonClicked();
        }

        onPressed: {
            titleText.topPadding = padding/2;
        }

        onReleased: {
            titleText.topPadding = 0;
        }

        onEntered: {
            rhomboidButton.state = "hovered";
        }

        onExited: {
           rhomboidButton.state = "default";
        }
    }

    Text{
        id: titleText
        anchors.fill: parent
        verticalAlignment: Text.AlignVCenter
        horizontalAlignment: Text.AlignHCenter
        text: title
        font.family: "微软雅黑"
        font.pointSize: 12
        color: textColor
        z: 10
    }

    Canvas {
        id: outline
        anchors.fill: parent
        contextType: "2d"
        z: 5

        onPaint: {
            var ctx = outline.getContext("2d");
            ctx.strokeStyle = outlineColor;
            ctx.fillStyle = Qt.rgba(0.2, 0.2, 0.2, 0.5);
            ctx.lineWidth = 2;
            ctx.shadowBlur = 2;
            ctx.shadowColor = shadowColor;
            ctx.beginPath();
            ctx.moveTo(padding, padding);
            ctx.lineTo(mw - padding - gap, padding);
            ctx.lineTo(mw - padding, mh - padding);
            ctx.lineTo(padding + gap, mh - padding);
            ctx.lineTo(padding, padding);
            ctx.stroke();
            ctx.fill();
        }
    }

    Canvas {
        id: aniCircle1
        x:0
        y:0
        width: rhomboidButton.width
        height: rhomboidButton.height
        contextType: "2d"
        z: 10

        onPaint: {
            var ctx = aniCircle1.getContext("2d");
            ctx.strokeStyle = "#EEF4F2";
            ctx.fillStyle = "#EEF4F2";
            ctx.lineWidth = 4;
            ctx.shadowBlur = 2;
            ctx.shadowColor = shadowColor;

            ctx.beginPath();
            ctx.arc(padding, padding, padding/2, 0, Math.PI*2, false);
            ctx.stroke();
            ctx.fill();
        }
    }

    PathAnimation{
        id: pathAnim1
        target: aniCircle1
        running: true
        duration: 4500
        anchorPoint: Qt.point(padding,padding)
        path: Path{
            startX: padding
            startY: padding
            PathLine{x: mw - padding - gap;  y: padding ;}
            PathLine{x: mw - padding;        y: mh - padding }
            PathLine{x: padding + gap;       y: mh - padding }
            PathLine{x: padding;             y: padding }
        }
        easing.type: Easing.InOutSine
        loops: Animation.Infinite
    }

    Canvas {
        id: aniCircle2
        x:0
        y:0
        width: rhomboidButton.width
        height: rhomboidButton.height
        contextType: "2d"
        z: 10

        onPaint: {
            var ctx = aniCircle2.getContext("2d");
            ctx.strokeStyle = "#EEF4F2";
            ctx.fillStyle = "#EEF4F2";
            ctx.lineWidth = 4;
            ctx.shadowBlur = 2;
            ctx.shadowColor = shadowColor;

            ctx.beginPath();
            ctx.arc(mw - padding, mh - padding, padding/2, 0, Math.PI*2, false);
            ctx.stroke();
            ctx.fill();
        }
    }

    PathAnimation{
        id: pathAnim2
        target: aniCircle2
        running: true
        duration: 4500
        anchorPoint: Qt.point(mw - padding,mh - padding)
        path: Path{
            startX: mw - padding
            startY: mh - padding
            PathLine{x: padding + gap;       y: mh - padding }
            PathLine{x: padding;             y: padding }
            PathLine{x: mw - padding - gap;  y: padding ;}
            PathLine{x: mw - padding;        y: mh - padding }
        }
        easing.type: Easing.InOutSine
        loops: Animation.Infinite
    }
}

参考文章
https://blog.csdn.net/liyuanbhu/article/details/46687495#
https://blog.csdn.net/foruok/article/details/41152297/

Qt是一个跨平台的C++应用程序开发框架,它提供了丰富的GUI(图形用户界面)和功能组件,其中包括自绘控件自绘控件是指通过重写绘制函数来实现自定义外观和行为的控件。 在Qt中,自绘控件通常是从QWidget类派生而来的子类。要使用自绘控件,你需要重写QWidget的paintEvent()函数,并在其中进行绘制操作。paintEvent()函数会在控件需要重新绘制时被调用,你可以在该函数中使用Qt提供的绘图工具进行绘制。 以下是使用paintEvent()函数自绘控件的基本步骤: 1. 创建一个继承自QWidget的子类,并重写其paintEvent()函数。 2. 在paintEvent()函数中,创建一个QPainter对象,并使用该对象进行绘制操作。 3. 使用QPainter提供的绘图函数(如drawRect()、drawText()等)来实现你想要的外观效果。 4. 根据需要,可以在其他事件处理函数中添加交互逻辑,例如鼠标点击事件等。 下面是一个简单的示例代码,展示了如何使用paintEvent()函数自绘一个简单的矩形控件: ```cpp #include <QtWidgets> class MyWidget : public QWidget { public: MyWidget(QWidget *parent = nullptr) : QWidget(parent) {} protected: void paintEvent(QPaintEvent *event) override { Q_UNUSED(event); QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); // 设置抗锯齿 painter.fillRect(rect(), Qt::blue); // 绘制蓝色背景 painter.setPen(Qt::white); // 设置画笔颜色为白色 painter.drawRect(rect().adjusted(10, 10, -10, -10)); // 绘制带边距的矩形 } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); MyWidget widget; widget.resize(200, 200); widget.show(); return app.exec(); } ``` 这个示例中,我们创建了一个名为MyWidget的自定义控件,重写了其paintEvent()函数,在其中使用QPainter对象绘制了一个带有蓝色背景和白色边框的矩形。在main()函数中,我们创建了一个应用程序对象,并显示了这个自定义控件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byxdaz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值