Qt源码分享(一)-- 圆角+阴影+可移动+大小可变
关注微信公众号在菜单栏获取源码
在源码分享(一)基础上,实现无窗口实际上还是有点不完整,这次我在原来代码的基础上增加了标题栏
好,我们先看下效果:
#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源码分享
x()
{
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源码分享**