Qt绘制云盘系列1

先抛出一个问题:QImage: out of memory, returning null image,下方错误示范效果图报出此错误,希望各位大佬们帮忙解决一下,在此先谢谢了!
工程链接-百度云链接:https://pan.baidu.com/s/1nccUlTPgZQc5QeP2bzczcw
提取码:akvt
错误示范效果图:
Qt绘制云盘系列1_第1张图片
实际上应该是下方这个效果,但是由于QImage: out of memory, returning null image错误,无法绘制出来!
Qt绘制云盘系列1_第2张图片
头文件

#ifndef QWHARCDISC_H
#define QWHARCDISC_H

/*
 * 云盘系列控件1
 * 该控件支持两种圆弧种类:半圆弧、整圆弧
 * 该控件支持两种按钮样式:矩形、圆形
 * 该控件支持鼠标三态效果:悬浮、按下、离开
 * 其余颜色等效果设置与获取请自行添加函数即可
 */

#include 
#include 
#include 
#include 
#include 
#include 

class QWHArcDisc : public QWidget
{
    Q_OBJECT
public:
    //圆弧种类
    enum ArcDiscType
    {
        SemiCircle, //半圆,圆弧180度
        Circle,     //正圆,圆弧360度
    };
    //按钮样式
    enum BtnStyle
    {
        BtnStyle_Rect,      //矩形
        BtnStyle_Circle,    //圆形
    };

    //鼠标状态
    enum mouseState
    {
        mouseState_Hover,   //鼠标悬浮
        mouseState_Pressed, //鼠标按下
        mouseState_Leave,   //鼠标离开
    };
    //数据结构
    struct ArcDiscData
    {
        QPixmap pixmap;     //存储图片
        QRect rect;         //存储图片区域
        mouseState state;   //鼠标状态
    };

    explicit QWHArcDisc(QWidget *parent = nullptr);
    ~QWHArcDisc();

public:
    //设置图片
    void setPixmaps(QVector pixmaps);
    //设置圆弧种类
    void setArcDiscType(ArcDiscType type);
    //设置按钮样式
    void setBtnStyle(BtnStyle style);

protected:
    void paintEvent(QPaintEvent *);
    //绘制半圆弧背景
    void drawSemiArc(QPainter *painter);
    //绘制半圆弧图片
    void drawSemiPixmaps(QPainter *painter);
    //绘制圆弧背景
    void drawArc(QPainter *painter);
    //绘制圆弧图片
    void drawPixmaps(QPainter *painter);

    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void resizeEvent(QResizeEvent *event);
    void leaveEvent(QEvent *);

private:
    //设置图片区域
    void setRects();
    //绘制图片
    void drawPixmap(QPainter *painter, const QPixmap &pixmap, int index, QRect rect);

signals:
    //发送按钮对应的序号:半圆弧形-序号0从0度(西)开始,整圆弧形-序号0从90度(北)开始
    void clicked(int index);

public slots:

private:
    QColor m_bgArcColor;                //圆弧背景颜色
    QColor m_borderColor;               //圆弧边框颜色
    QColor m_picBorderColor;            //图片边框颜色

    ArcDiscType m_arcDiscType;          //圆弧种类
    BtnStyle m_btnStyle;                //按钮样式
    QVector m_arcDiscData; //存储信息
    QVector m_resizePixmaps;   //保存当前窗口大小下的图片尺寸,避免在paintEvent中pixmap.scale()函数频繁缩放图片大小造成的时间浪费
    int m_curPressedIndex;              //保存当前按下的按钮索引
};

#endif // QWHARCDISC_H

cpp文件

#include "qwharcdisc.h"
#include 
#include 

const float offsetAngle = 10;       //两边角度偏移量
const int sideLength = 20;          //图标正方形边长
const int selectSideLength = 40;    //选中图标正方形边长
const int radius = 80;              //图片中心距离圆弧中心点距离

QWHArcDisc::QWHArcDisc(QWidget *parent) : QWidget(parent)
{
    m_bgArcColor = QColor(30, 30, 30);  //圆弧背景颜色
    m_borderColor = QColor(Qt::blue);   //圆弧边框颜色
    m_picBorderColor = Qt::white;       //图片边框颜色
    m_arcDiscType = SemiCircle;         //圆弧种类
    m_btnStyle = BtnStyle_Circle;       //按钮样式
    m_curPressedIndex = -1;             //保存当前按下的按钮索引
    this->setMouseTracking(true);
}

QWHArcDisc::~QWHArcDisc()
{

}

void QWHArcDisc::setPixmaps(QVector pixmaps)
{
    m_arcDiscData.clear();
    m_curPressedIndex = -1;
    for (int i = 0; i < pixmaps.count(); i++)
    {
        ArcDiscData data;
        data.pixmap = pixmaps[i];
        data.state = mouseState_Leave;
        m_arcDiscData.append(data);
    }
    //重新设置pixmap大小
    m_resizePixmaps.clear();
    QPixmap pixmap;
    for (int i = 0; i < m_arcDiscData.count(); i++)
    {
        if (m_arcDiscType == SemiCircle)
            pixmap = m_arcDiscData[i].pixmap.scaled(sideLength * 200, sideLength * 100, Qt::IgnoreAspectRatio);
        else
            pixmap = m_arcDiscData[i].pixmap.scaled(sideLength * 200, sideLength * 200, Qt::IgnoreAspectRatio);
        m_resizePixmaps.append(pixmap);
    }
    update();
}

void QWHArcDisc::setArcDiscType(QWHArcDisc::ArcDiscType type)
{
    m_arcDiscType = type;
    update();
}

void QWHArcDisc::setBtnStyle(QWHArcDisc::BtnStyle style)
{
   m_btnStyle = style;
   update();
}

void QWHArcDisc::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    int width = this->width();
    int height = this->height();
    if (m_arcDiscType == SemiCircle)
    {
        painter.translate(width / 2.0, height);
        painter.scale(width / 200.0, height / 100.0);
        drawSemiArc(&painter);
        drawSemiPixmaps(&painter);
    }
    else if (m_arcDiscType == Circle)
    {
        painter.translate(width / 2, height / 2.0);
        painter.scale(width / 200.0, height / 200.0);
        drawArc(&painter);
        drawPixmaps(&painter);
    }
}

void QWHArcDisc::drawSemiArc(QPainter *painter)
{
    painter->save();

    QRect outRect = QRect(-99, -99, 198, 198);
    QRect inRect = QRect(-60, -60, 120, 120);
    QPainterPath path;
    path.moveTo(60, 0);
    path.lineTo(100, 0);
    path.arcTo(outRect, 0, 180);
    path.lineTo(-100, 0);
    path.lineTo(-60, 0);
    path.arcTo(inRect, 180, -180);

    painter->setPen(QPen(m_borderColor, 1));
    painter->setBrush(m_bgArcColor);
    painter->drawPath(path);

    painter->restore();
}

void QWHArcDisc::drawSemiPixmaps(QPainter *painter)
{
    painter->save();

    painter->setPen(QPen(m_picBorderColor, 2));
    int count = m_arcDiscData.count();
    if (count % 2 == 0)
    {
        float perAngle = (180 - 2 * offsetAngle) / (count - 1);
        for (int i = 0; i < count; i++)
        {
            int x = radius * qCos(qDegreesToRadians(i * perAngle + offsetAngle));
            int y = -radius * qSin(qDegreesToRadians(i * perAngle + offsetAngle));
            QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
            const QPixmap &pixmap = m_resizePixmaps[i];
            drawPixmap(painter, pixmap, i, rect);
        }
    }
    else
    {
        //绘制中间图片
        int midIndex = count / 2;
        const QPixmap &pixmap = m_resizePixmaps[midIndex];
        QRect rect = QRect(-sideLength / 2, -radius - sideLength / 2, sideLength, sideLength);
        drawPixmap(painter, pixmap, midIndex, rect);
        //绘制offsetAngle-90度之间的图片
        float perAngle = (90 - offsetAngle) / midIndex;
        for (int i = midIndex - 1; i >= 0; i--)
        {
            int x = radius * qCos(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
            int y = -radius * qSin(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
            QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
            const QPixmap &pixmap = m_resizePixmaps[i];
            drawPixmap(painter, pixmap, i, rect);
        }
        //绘制90度-(180-offsetAngle)之间的图片
        for (int i = midIndex + 1; i < count; i++)
        {
            int x = radius * qCos(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
            int y = -radius * qSin(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
            QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
            const QPixmap &pixmap = m_resizePixmaps[i];
            drawPixmap(painter, pixmap, i, rect);
        }
    }
    //绘制选中图片
    if (m_curPressedIndex != -1)
    {
        QRect rect = QRect(-selectSideLength / 2, -selectSideLength, selectSideLength, selectSideLength);
        QPainterPath path;
        path.addEllipse(rect);
        painter->setClipPath(path);
        QPixmap pixmap = m_resizePixmaps[m_curPressedIndex];
        pixmap = pixmap.scaled(pixmap.width() * 2, pixmap.height() * 2);
        painter->drawPixmap(rect, pixmap);
    }

    painter->restore();
}

void QWHArcDisc::drawArc(QPainter *painter)
{
    painter->save();

    QPainterPath path1, path2, path;
    path1.addEllipse(QRect(-99, -99, 198, 198));
    path2.addEllipse(QRect(-60, -60, 120, 120));
    path = path1 - path2;

    painter->setPen(QPen(m_borderColor, 1));
    painter->setBrush(m_bgArcColor);
    painter->drawPath(path);

    painter->restore();
}

void QWHArcDisc::drawPixmaps(QPainter *painter)
{
    painter->save();

    painter->setPen(QPen(m_picBorderColor, 2));
    int count = m_arcDiscData.count();
    float perAngle = 360 / count;
    for (int i = 0; i < count; i++)
    {
        //+90度是为了使得第一个图标绘制在正上方(奇数个对齐)
        int x = radius * qCos(qDegreesToRadians(i * perAngle + 90));
        int y = -radius * qSin(qDegreesToRadians(i * perAngle + 90));
        QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
        QPixmap pixmap = m_resizePixmaps[i];
        drawPixmap(painter, pixmap, i, rect);
    }
    //绘制选中图片
    if (m_curPressedIndex != -1)
    {
        QRect rect = QRect(-selectSideLength * 0.75, -selectSideLength * 0.75, selectSideLength * 1.5, selectSideLength * 1.5);
        QPainterPath path;
        path.addEllipse(rect);
        painter->setClipPath(path);
        QPixmap pixmap = m_resizePixmaps[m_curPressedIndex];
        pixmap = pixmap.scaled(pixmap.width() * 2, pixmap.height() * 2);
        painter->drawPixmap(rect, pixmap);
    }

    painter->restore();
}

void QWHArcDisc::mouseMoveEvent(QMouseEvent *event)
{
    for (int i = 0; i < m_arcDiscData.count(); i++)
    {
        if (i == m_curPressedIndex)
            continue;
        else if (m_arcDiscData[i].rect.contains(event->pos().x(), event->pos().y(), true))
            m_arcDiscData[i].state = mouseState_Hover;
        else
            m_arcDiscData[i].state = mouseState_Leave;
    }
    update();
}

void QWHArcDisc::mousePressEvent(QMouseEvent *event)
{
    bool mouseInRect = false;
    for (int i = 0; i < m_arcDiscData.count(); i++)
    {
        if (m_arcDiscData[i].rect.contains(event->pos().x(), event->pos().y(), true))
        {
            m_arcDiscData[i].state = mouseState_Pressed;
            m_curPressedIndex = i;
            mouseInRect = true;
        }
        else
            m_arcDiscData[i].state = mouseState_Leave;
    }
    if (!mouseInRect && m_curPressedIndex != -1)
        m_arcDiscData[m_curPressedIndex].state = mouseState_Pressed;
    if (mouseInRect)
        emit clicked(m_curPressedIndex);

    update();
}

void QWHArcDisc::resizeEvent(QResizeEvent *event)
{
    setRects();
    //重新设置pixmap大小
    m_resizePixmaps.clear();
    QPixmap pixmap;
    for (int i = 0; i < m_arcDiscData.count(); i++)
    {
        if (m_arcDiscType == SemiCircle)
            pixmap = m_arcDiscData[i].pixmap.scaled(sideLength * 200, sideLength * 100, Qt::IgnoreAspectRatio);
        else
            pixmap = m_arcDiscData[i].pixmap.scaled(sideLength * 200, sideLength * 200, Qt::IgnoreAspectRatio);
        m_resizePixmaps.append(pixmap);
    }
}

void QWHArcDisc::leaveEvent(QEvent *)
{
    for (int i = 0; i < m_arcDiscData.count(); i++)
    {
        if (m_arcDiscData[i].state == mouseState_Hover)
            m_arcDiscData[i].state = mouseState_Leave;
    }
    update();
}

void QWHArcDisc::setRects()
{
    int width = this->width();
    int height = this->height();
    int translateX = width / 2;
    int translateY = height;
    float scaleX = width / 200.0;
    float scaleY = height / 100.0;

    int count = m_arcDiscData.count();
    int midIndex = count / 2;
    if (m_arcDiscType == SemiCircle)
    {
        if (count % 2 == 0)
        {
            float perAngle = (180 - 2 * offsetAngle) / (count - 1);
            for (int i = 0; i < count; i++)
            {
                int x = radius * qCos(qDegreesToRadians(i * perAngle + offsetAngle));
                int y = -radius * qSin(qDegreesToRadians(i * perAngle + offsetAngle));
                QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
                //将paintEvent函数中的图片区域转换为实际区域
                rect = QRect(rect.x() * scaleX + translateX, rect.y() * scaleY + translateY, sideLength * scaleX, sideLength * scaleY);
                m_arcDiscData[i].rect = rect;
            }
        }
        else
        {
            //存储中间图片区域
            QRect rect = QRect(-sideLength / 2, -radius - sideLength / 2, sideLength, sideLength);
            rect = QRect(rect.x() * scaleX + translateX, rect.y() * scaleY + translateY, sideLength * scaleX, sideLength * scaleY);
            m_arcDiscData[midIndex].rect = rect;
            //存储offsetAngle-90度之间的图片区域
            int perAngle = (90 - offsetAngle) / midIndex;
            for (int i = midIndex - 1; i >= 0; i--)
            {
                int x = radius * qCos(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
                int y = -radius * qSin(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
                QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
                //将paintEvent函数中的图片区域转换为实际区域
                rect = QRect(rect.x() * scaleX + translateX, rect.y() * scaleY + translateY, sideLength * scaleX, sideLength * scaleY);
                m_arcDiscData[i].rect = rect;
            }
            //存储90度-(180 - offsetAngle)之间的图片区域
            for (int i = midIndex + 1; i < count; i++)
            {
                int x = radius * qCos(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
                int y = -radius * qSin(qDegreesToRadians(90.0 - perAngle * (midIndex - i)));
                QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
                //将paintEvent函数中的图片区域转换为实际区域
                rect = QRect(rect.x() * scaleX + translateX, rect.y() * scaleY + translateY, sideLength * scaleX, sideLength * scaleY);
                m_arcDiscData[i].rect = rect;
            }
        }
    }
    else if (m_arcDiscType == Circle)
    {
        float perAngle = 360.0 / count;
        scaleY = scaleY / 2.0;
        translateY = translateY / 2.0;
        for (int i = 0; i < count; i++)
        {
            int x = radius * qCos(qDegreesToRadians(i * perAngle + 90));
            int y = -radius * qSin(qDegreesToRadians(i * perAngle + 90));
            QRect rect = QRect(x - sideLength / 2, y - sideLength / 2, sideLength, sideLength);
            //将paintEvent函数中的图片区域转换为实际区域
            rect = QRect(rect.x() * scaleX + translateX, rect.y() * scaleY + translateY, sideLength * scaleX, sideLength * scaleY);
            m_arcDiscData[i].rect = rect;
        }
    }
}

void QWHArcDisc::drawPixmap(QPainter *painter, const QPixmap &pixmap, int index, QRect rect)
{
    if (m_btnStyle == BtnStyle_Rect)
    {
        painter->drawPixmap(rect, pixmap);
        if (m_arcDiscData[index].state == mouseState_Pressed || m_arcDiscData[index].state == mouseState_Hover)
            painter->drawRect(rect);
    }
    else if (m_btnStyle == BtnStyle_Circle)
    {
        QPainterPath path;
        path.addEllipse(rect);
        painter->setClipPath(path);
        painter->drawPixmap(rect, pixmap);
        if (m_arcDiscData[index].state == mouseState_Pressed || m_arcDiscData[index].state == mouseState_Hover)
            painter->drawEllipse(rect);
    }
}

测试代码

#include "widget.h"
#include "ui_widget.h"
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //半圆弧形奇数个
    QVector pixmaps1;
    for (int i = 0; i < 5; i++)
    {
        QPixmap pixmap(QString(":/RES/%1.png").arg(i + 1));
        pixmaps1.append(pixmap);
    }
    ui->widget->setPixmaps(pixmaps1);
    ui->widget->setArcDiscType(QWHArcDisc::SemiCircle);
    ui->widget->setBtnStyle(QWHArcDisc::BtnStyle_Rect);
    //半圆弧形偶数个
    QVector pixmaps2;
    for (int i = 0; i < 4; i++)
    {
        QPixmap pixmap(QString(":/RES/%1.png").arg(i + 1));
        pixmaps2.append(pixmap);
    }
    ui->widget_2->setPixmaps(pixmaps2);
    ui->widget_2->setArcDiscType(QWHArcDisc::SemiCircle);
    ui->widget_2->setBtnStyle(QWHArcDisc::BtnStyle_Circle);
    //正圆弧形奇数个
    QVector pixmaps3;
    for (int i = 0; i < 3; i++)
    {
        QPixmap pixmap(QString(":/RES/%1.png").arg(i + 1));
        pixmaps3.append(pixmap);
    }
    ui->widget_3->setPixmaps(pixmaps3);
    ui->widget_3->setArcDiscType(QWHArcDisc::Circle);
    ui->widget_3->setBtnStyle(QWHArcDisc::BtnStyle_Rect);
    //正圆弧形偶数个
    QVector pixmaps4;
    for (int i = 0; i < 5; i++)
    {
        qDebug() << QString(":/RES/%1.png").arg(i + 1);
        QPixmap pixmap(QString(":/RES/%1.png").arg(i + 1));
        pixmaps4.append(pixmap);
    }
    ui->widget_4->setPixmaps(pixmaps4);
    ui->widget_4->setArcDiscType(QWHArcDisc::Circle);
    ui->widget_4->setBtnStyle(QWHArcDisc::BtnStyle_Circle);

    connect(ui->widget, &QWHArcDisc::clicked, this, [&](int index){ui->lblValue1->setText(QString::number(index));});
    connect(ui->widget_2, &QWHArcDisc::clicked, this, [&](int index){ui->lblValue2->setText(QString::number(index));});
    connect(ui->widget_3, &QWHArcDisc::clicked, this, [&](int index){ui->lblValue3->setText(QString::number(index));});
    connect(ui->widget_4, &QWHArcDisc::clicked, this, [&](int index){ui->lblValue4->setText(QString::number(index));});
}

Widget::~Widget()
{
    delete ui;
}

你可能感兴趣的:(自定义控件)