Qt源码分享(二)-- 圆角+阴影+可移动+大小可变+标题

  1. Qt源码分享(一)– 圆角+阴影+可移动+大小可变

Qt源码分享(一)– 圆角+阴影+可移动+大小可变

关注微信公众号在菜单栏获取源码

image

在源码分享(一)基础上,实现无窗口实际上还是有点不完整,这次我在原来代码的基础上增加了标题栏

好,我们先看下效果:
image

#include "centerwidget.h"

#include <QApplication>

CenterWidget::CenterWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setMouseTracking(true);
}

CenterWidget::~CenterWidget()
{
}

void CenterWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    QRect rect = this->rect()-QMargins(0, 0, 1, 1);
    painter.setPen(Qt::red);
    painter.setBrush(Qt::white);
    painter.drawRect(rect);


    painter.drawText(this->rect(), Qt::AlignVCenter | Qt::AlignHCenter, 
                        tr("this is custome center widget..."));
}

void CenterWidget::mouseMoveEvent(QMouseEvent *event)
{
    qApp->postEvent(this->parentWidget(), new QEvent(QEvent::User));
}

头文件的实现:

/*!
 * @file     mainwindow.h
 * @author   ZhaoYanbo
 * @date     2019-10-29
 * @details  ...
 * @version  v1.0.0
 */
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QDialog>
#include <QWidget>

class MainWindow : public QWidget
{
    Q_OBJECT

enum Direction{
    UP = 0,
    DOWN,
    LEFT,
    RIGHT,
    LEFTTOP,
    LEFTBOTTOM,
    RIGHTBOTTOM,
    RIGHTTOP,
    NONE
};

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public:    
    void SetResizeable(bool isResize);
    bool IsResizeable() const;

    void SetRadius(bool radius);
    int GetRadius() const;

protected:
    void resizeEvent(QResizeEvent *) override;
    void paintEvent(QPaintEvent *) override;
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);

private:
    void region(const QPoint &cursorPoint);

    /*!
     * \brief 绘制带尖的图片
     * \param w      图片宽度
     * \param h      图片高度
     * \param tip_w  尖的宽度
     * \param tip_h  尖的高度
     * \param radius 矩形圆角半径
     * \param margin 边距
     * \return
     */
    QPixmap drawTip(const int w, const int h, const int tip_w, const int tip_h,
                    const int radius, const int margin);

private:
    QPixmap     m_pixmap;
    bool        mIsLeftPressDown;
    QPoint      mDragPosition;
    Direction   mDirec;
    bool        mResizeable;
    int         mRadius;

};

#endif // MAINWINDOW_H

实现的部分cpp文件:

#include "mainwindow.h"
#include "labelex.h"
#include "config.h"

#include <QLabel>
#include <QDebug>
#include <QPainter>
#include <QToolButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QResizeEvent>
#include <QApplication>
#include <QGraphicsBlurEffect>

const int kSHADOWWIDTH = 16;
const int kTITLEHEIGHT = 30;
const int kTITLEWIDTH  = 30;
const int kMAXLENGTH   = 0xFFFFFF;

const int kPADDING      = 18;
const int kPADDING_TOP  = 29;

MainWindow::MainWindow(QWidget *centerwidget, QWidget *parent) : QWidget(parent)
{
    this->mCenterWidget = centerwidget;

    init();
    updateUI();
    drawShadow();
}

MainWindow::MainWindow(bool drawshadow, QWidget *centerwidget, QWidget *parent)
    : QWidget(parent)
{
    this->mCenterWidget = centerwidget;

    init();
    updateUI();

    if (drawshadow) { drawShadow(); }
}

MainWindow::~MainWindow()
{}

void MainWindow::SetResizeable(bool isResize)
{
    mResizeable = isResize;
}

bool MainWindow::IsResizeable() const
{
    return mResizeable;
}

void MainWindow::SetRadius(bool radius)
{
    mRadius = radius;
}

int MainWindow::GetRadius() const
{
    return mRadius;
}

void MainWindow::resizeEvent(QResizeEvent *e)
{
    const QSize s = e->size();
    int w = s.width();
    int h = s.height();
    if(w > 1 && h > 1) {
        m_pixmap = drawTip(w, h, 18, 12, mRadius, kSHADOWWIDTH);
    }
}

void MainWindow::paintEvent(QPaintEvent *)
{
    if(m_pixmap.isNull())
        return;

    QPainter p;
    p.begin(this);
    p.drawPixmap(this->rect(), m_pixmap);
    p.end();
}

void MainWindow::init()
{
    this->mDirec        = NONE;
    this->mRadius       = 4;
    this->mResizeable   = true;
    this->mIsLeftPressDown = false;
    this->setMouseTracking(true);
}

void MainWindow::region(const QPoint &cursorGlobalPoint)
{
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());
    int x = cursorGlobalPoint.x();
    int y = cursorGlobalPoint.y();

    if(tl.x() + kPADDING_TOP >= x && tl.x() <= x && tl.y() + kPADDING_TOP >= y && tl.y() <= y) {
        // 左上角
        mDirec = LEFTTOP;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if(x >= rb.x() - kPADDING && x <= rb.x() && y >= rb.y() - kPADDING && y <= rb.y()) {
        // 右下角
        mDirec = RIGHTBOTTOM;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if(x <= tl.x() + kPADDING && x >= tl.x() && y >= rb.y() - kPADDING && y <= rb.y()) {
        //左下角
        mDirec = LEFTBOTTOM;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if(x <= rb.x() && x >= rb.x() - kPADDING_TOP && y >= tl.y() && y <= tl.y() + kPADDING_TOP) {
        // 右上角
        mDirec = RIGHTTOP;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if(x <= tl.x() + kPADDING && x >= tl.x()) {
        // 左边
        mDirec = LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if( x <= rb.x() && x >= rb.x() - kPADDING) {
        // 右边
        mDirec = RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    }else if(y >= tl.y() && y <= tl.y() + kPADDING_TOP){
        // 上边
        mDirec = UP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else if(y <= rb.y() && y >= rb.y() - kPADDING) {
        // 下边
        mDirec = DOWN;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    }else {
        // 默认
        mDirec = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    }
}

void MainWindow::updateUI()
{
    this->resize(800, 750);

    this->setAttribute(Qt::WA_TranslucentBackground, true);
    this->setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint);

    setupTitleWidget();
}

void MainWindow::drawShadow()
{
    QGraphicsDropShadowEffect* pShadowEffect = new QGraphicsDropShadowEffect(this);
    pShadowEffect->setOffset(0, 0);
    pShadowEffect->setColor(Qt::lightGray);
    pShadowEffect->setBlurRadius(kSHADOWWIDTH);
    this->setGraphicsEffect(pShadowEffect);
}

void MainWindow::setupTitleWidget()
{
    QVBoxLayout *top_vlayout = new QVBoxLayout(this);
    top_vlayout->setSpacing(0);
    top_vlayout->setContentsMargins(kPADDING, kPADDING_TOP, kPADDING, kPADDING);
    top_vlayout->setObjectName(QString::fromUtf8("top_vlayout"));

    QHBoxLayout *title_hlayout = new QHBoxLayout();
    title_hlayout->setSpacing(0);
    title_hlayout->setContentsMargins(0, 0, 0, 0);
    title_hlayout->setObjectName(QString::fromUtf8("title_hlayout")); 

    LabelEx *label_title = new LabelEx(this);
    label_title->setObjectName(QString::fromUtf8("label_title"));
    label_title->setText(tr("this is title label."));
    QSizePolicy expand_preferred_policy(QSizePolicy::Expanding, QSizePolicy::Preferred);
    expand_preferred_policy.setVerticalStretch(0);
    expand_preferred_policy.setHorizontalStretch(0);
    expand_preferred_policy.setHeightForWidth(label_title->sizePolicy().hasHeightForWidth());
    label_title->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter);
    label_title->setCursor(QCursor(Qt::ArrowCursor));
    title_hlayout->addWidget(label_title);

    QToolButton *btn_menu = new QToolButton(this);
    btn_menu->setObjectName(QString::fromUtf8("btn_menu"));
    btn_menu->setText(tr("menu"));
    btn_menu->setFixedSize(QSize(kTITLEWIDTH, kTITLEHEIGHT));
    btn_menu->setFocusPolicy(Qt::NoFocus);
    // btn_menu->setPopupMode(QToolButton::InstantPopup);
    title_hlayout->addWidget(btn_menu);

    QPushButton *btn_min = new QPushButton(this);
    btn_min->setObjectName(QString::fromUtf8("btn_min"));
    btn_min->setText(tr("min"));
    btn_min->setFixedSize(QSize(kTITLEWIDTH, kTITLEHEIGHT));
    btn_min->setCursor(QCursor(Qt::ArrowCursor));
    btn_min->setFocusPolicy(Qt::NoFocus);
    title_hlayout->addWidget(btn_min);

    QPushButton *btn_max = new QPushButton(this);
    mMaxBtn = btn_max;
    btn_max->setText(tr("max"));
    btn_max->setObjectName(QString::fromUtf8("btn_max"));
    btn_max->setFixedSize(QSize(kTITLEWIDTH, kTITLEHEIGHT));
    btn_max->setCursor(QCursor(Qt::ArrowCursor));
    btn_max->setFocusPolicy(Qt::NoFocus);

    title_hlayout->addWidget(btn_max);

    QPushButton *btn_close = new QPushButton(this);
    btn_close->setObjectName(QString::fromUtf8("btn_close"));
    btn_close->setText(tr("close"));
    btn_close->setFixedSize(QSize(kTITLEWIDTH, kTITLEHEIGHT));
    btn_close->setCursor(QCursor(Qt::ArrowCursor));
    btn_close->setFocusPolicy(Qt::NoFocus);

    title_hlayout->addWidget(btn_close);

    top_vlayout->addLayout(title_hlayout);

    if (nullptr == mCenterWidget) {
        mCenterWidget = new QWidget(this);
        mCenterWidget->setStyleSheet("background-color: rgb(255,0, 255)");
        mCenterWidget->setObjectName(QString::fromUtf8("widget"));

        QSizePolicy sizePolicy1(QSizePolicy::Preferred, QSizePolicy::Expanding);
        sizePolicy1.setHorizontalStretch(0);
        sizePolicy1.setVerticalStretch(0);
        sizePolicy1.setHeightForWidth(mCenterWidget->sizePolicy().hasHeightForWidth());
        mCenterWidget->setSizePolicy(sizePolicy1);
    }

    top_vlayout->addWidget(mCenterWidget);

    connect(btn_max, SIGNAL(clicked()), this, SLOT(DoMax()));
    connect(btn_close, SIGNAL(clicked()), this, SLOT(DoClose()));
    connect(btn_min, SIGNAL(clicked()), this, SLOT(DoMin()));
    connect(btn_menu, SIGNAL(clicked()), this, SLOT(DoMenu()));
}

QPixmap MainWindow::drawTip(const int w, const int h, const int tip_w, const int tip_h, const int radius, const int margin)
{
    const int w2 = w - margin * 2 - radius * 2 - tip_w;

    QPainterPath path;
    //三角形
//    path.moveTo(radius + margin + w2 / 2, tip_h + margin);
//    path.lineTo(w / 2, margin);
//    path.lineTo(radius + margin + w2 / 2 + tip_w, tip_h + margin);

    //3个矩形
    path.addRect(margin+radius,margin+tip_h,w-(margin+radius)*2, h-margin*2-tip_h);
    path.addRect(margin,margin+tip_h+radius,radius,(h-margin-radius)-(margin+tip_h+radius));
    path.addRect(w-margin-radius,margin+tip_h+radius,radius,(h-margin-radius)-(margin+tip_h+radius));

    //4个圆角
    //
    path.moveTo(w-margin-radius, tip_h + margin + radius);
    path.arcTo(QRectF(margin + w2 + tip_w, tip_h + margin, radius * 2, radius * 2), 0, 90);
    //
    path.moveTo(w - margin-radius, h - margin - radius);
    path.arcTo(QRectF(margin + w2 + tip_w, h - margin - radius * 2, radius * 2, radius * 2), 270, 90);
    //
    path.moveTo(margin + radius, h -margin-radius);
    path.arcTo(QRectF(margin, h - margin - radius*2, radius * 2, radius * 2), 180, 90);
    //
    path.moveTo(margin + radius, margin + tip_h+radius);
    path.arcTo(QRectF(margin, margin+tip_h, radius * 2, radius * 2), 90, 90);

    //绘制到图片
    QPixmap pixmap(w, h);
    pixmap.fill(Qt::transparent);

    QPainter p;
    p.begin(&pixmap);
    p.setRenderHint(QPainter::Antialiasing);
    p.setBrush(QBrush(QColor(249, 249, 249)));
    p.setPen(Qt::NoPen);
    p.drawPath(path);
    p.end();

    return pixmap;
}

void MainWindow::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        mIsLeftPressDown = false;
        if(mDirec != NONE) {
            this->releaseMouse();
            this->setCursor(QCursor(Qt::ArrowCursor));
        }
            // mDirec = NONE;
    }
}

void MainWindow::mousePressEvent(QMouseEvent *event)
{
    switch(event->button()) {
    case Qt::LeftButton:
        mIsLeftPressDown = true;
        if(mDirec != NONE) {
            this->mouseGrabber();
        } else {
            mDragPosition = event->globalPos() - this->frameGeometry().topLeft();
            // mDirec = NONE;
        }
        break;
    default:
        // QMainWindow::mousePressEvent(event);
        QWidget::mousePressEvent(event);
    }
}

void MainWindow::focusOutEvent(QFocusEvent *event)
{
    mDirec = NONE;
    this->setCursor(QCursor(Qt::ArrowCursor));
}

bool MainWindow::event(QEvent *event)
{
    if (event->type() == QEvent::User) {
        mDirec = NONE;
        this->setCursor(QCursor(Qt::ArrowCursor));
    } else if (event->type() == MAX_WINDOW) {
        DoMax();
    }

    return QWidget::event(event);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    QPoint gloPoint = event->globalPos();
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());

    if(!mIsLeftPressDown) {
        if (mResizeable) {
            this->region(gloPoint);
        }
    } else {

        if(mDirec != NONE && mResizeable) {
            QRect rMove(tl, rb);

            switch(mDirec) {
            case LEFT:
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                    rMove.setX(tl.x() - kSHADOWWIDTH);
                else
                    rMove.setX(gloPoint.x() - kSHADOWWIDTH);
                break;
            case RIGHT:
                rMove.setWidth(gloPoint.x() - tl.x() + kSHADOWWIDTH);
                break;
            case UP:
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                    rMove.setY(tl.y() - kPADDING_TOP);
                else
                    rMove.setY(gloPoint.y() - kPADDING_TOP);
                break;
            case DOWN:
                rMove.setHeight(gloPoint.y() - tl.y() + kSHADOWWIDTH);
                break;
            case LEFTTOP:
                if(rb.x() - gloPoint.x() <= this->minimumWidth())
                    rMove.setX(tl.x() - kPADDING);
                else
                    rMove.setX(gloPoint.x() - kPADDING);
                if(rb.y() - gloPoint.y() <= this->minimumHeight())
                    rMove.setY(tl.y() - kPADDING_TOP);
                else
                    rMove.setY(gloPoint.y() - kPADDING_TOP);
                break;
            case RIGHTTOP:
                rMove.setWidth(gloPoint.x() - tl.x() + kPADDING);
                rMove.setY(gloPoint.y()-kPADDING_TOP);
                break;
            case LEFTBOTTOM:
                rMove.setX(gloPoint.x() - kPADDING);
                rMove.setHeight(gloPoint.y() - tl.y() + kPADDING);
                break;
            case RIGHTBOTTOM:
                rMove.setWidth(gloPoint.x() - tl.x() + kPADDING);
                rMove.setHeight(gloPoint.y() - tl.y() + kPADDING);
                break;
            default:
                break;
            }
            this->setGeometry(rMove);
        } else {
            move(event->globalPos() - mDragPosition);
            event->accept();
        }
    }
    // QMainWindow::mouseMoveEvent(event);
    QWidget::mouseMoveEvent(event);
}

void MainWindow::DoClose()
{
    this->close();
}

void MainWindow::DoMenu()
{
    //TODO something
    qDebug() << "this is menu";
}

void MainWindow::DoMax()
{
    QVBoxLayout *top_layout = this->findChild<QVBoxLayout*>(tr("top_vlayout"));
    if (this->isMaximized()) {
        top_layout->setContentsMargins(kPADDING, kPADDING_TOP, 
                                        kPADDING, kPADDING);
        this->showNormal();
        mMaxBtn->setText(tr("max"));
    } else {
        top_layout->setContentsMargins(0, 0, 0, 0);
        this->showMaximized();
        mMaxBtn->setText(tr("restore"));
    }
}

void MainWindow::DoMin()
{
    this->showMinimized();
}

关注微信公众号获取源码:菜单-》Qt源码分享


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 635672377@qq.com

文章标题:Qt源码分享(二)-- 圆角+阴影+可移动+大小可变+标题

文章字数:1.9k

本文作者:刘世雄

发布时间:2020-06-02, 19:11:28

最后更新:2020-06-02, 11:16:15

原始链接:http://lsxcpp.com/2020/06/03/Qt%E6%BA%90%E7%A0%81%E5%88%86%E4%BA%AB%EF%BC%88%E4%BA%8C%EF%BC%89-%E5%9C%86%E8%A7%92-%E9%98%B4%E5%BD%B1-%E5%8F%AF%E7%A7%BB%E5%8A%A8-%E5%A4%A7%E5%B0%8F%E5%8F%AF%E5%8F%98-%E6%A0%87%E9%A2%98/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录