Qt自定义窗口圆角

Qt设置圆角

在Qt中一般设置窗口圆角有两种方式,

  • QSS
  • 通过paintEvent自绘窗口
QSS 设置圆角

这种设置圆角的方式相对来说比较灵活,但我们设置基类窗口(最外层窗口)用qss就很不方便,会收到后续qss的影响,另外当圆角设置大小超过高度的1/2时,圆角效果就会消失,所以窗口动态变化时,这个用起来也不方便

border-radius:8px;//四个角
border-top-left-radius:8px; 左上角;
border-top-right-radius:8px; 右上角;
border-bottom-left-radius:8px; 左下角;
border-bottom-right-radius:8px; 右下角;

paintEvent自绘窗口

大家最常见的就是绘制同时绘制四个角

void CustomRadiusWidget::paintEvent(QPaintEvent *event)
{
	QPainter painter(this);
	painter.setRenderHint(QPainter::Antialiasing);
	painter.setBrush(bg_color_);
	painter.setPen(Qt::transparent);
	painter.drawRoundedRect(rect(), radius_, radius_);
}

但这时候,如果我们想实现类似qss中让四角某一个或几个实现圆角,就无法实现了,查了一下也没有找到相关的demo。这里把我实现的思路和大家分享一下
核心的思想就是:绘制出四个圆角,然后在不需要的圆角上添加带棱角的矩形进行覆盖

以左上角为例
在这里插入图片描述
核心代码

void CustomRadiusWidget::paintEvent(QPaintEvent *event)
{
	//美化样式,防止设置的圆角过大(超过高度1/2)
	auto half_height = height() / 2;
	auto radius = radius_ > half_height ? height() / 2 : radius_;
	//auto radius = radius_;
	QPainter painter(this);
	QPainterPath draw_path;
	draw_path.addRoundedRect(rect(), radius, radius);
	draw_path.setFillRule(Qt::WindingFill);
	if (!left_top_) {
		draw_path.addRect(0, 0, width() / 2, height() / 2);
	}
	if (!left_bottom_) {
		draw_path.addRect(0, height() / 2, width() / 2, height() / 2);
	}
	if (!right_top_) {
		draw_path.addRect(width() / 2, 0, width() / 2, height() / 2);
	}
	if (!right_bottom_) {
		draw_path.addRect(width() / 2, height() / 2, width() / 2, height() / 2);
	}
	painter.setRenderHint(QPainter::Antialiasing);
	painter.setPen(Qt::transparent);
	painter.setBrush(bg_color_);
	painter.drawPath(draw_path);
}

QPainterPath 填充规则

  • Qt::OddEventFill(奇偶填充规则)判断一个点是否在形状内, 从该点到形状外的位置画一条水平线,并计算交叉点的数量。 如果交叉点的数量为奇数,则该点位于形状内部。 此模式为默认模式。
  • Qt::WindingFill (非零弯曲规则)判断一个点是否在形状内, 从该点到形状外部的位置绘制一条水平线。 确定每个交点处的线的方向是向上还是向下。 绕组数是通过对每个交叉点的方向求和来确定的。 如果数字不为零,则该点位于形状内部。 这种填充模式在大多数情况下也可以被认为是闭合形状的交集。
    在这里插入图片描述
    通过上述代码,你就能随意控制到底是显示哪个圆角
    完整代码
//===================================.h==========================================//
#pragma once
#include <QWidget>
class CustomRadiusWidget : public QWidget
{
	Q_OBJECT
public:
	CustomRadiusWidget(QWidget *parent=nullptr);
	~CustomRadiusWidget();
	void SetRadius(int radius);
	void SetRadiusEnable(bool left_top, bool left_bottom, bool right_left, bool right_bottom);
protected:
	virtual void paintEvent(QPaintEvent* event)override;
private:
	int radius_ = {0};
	QColor bg_color_ = {106 ,90 ,205};
	bool left_top_=false;
	bool left_bottom_ = false;
	bool right_top_ = false;
	bool right_bottom_ = false;
};
//===================================.cpp==========================================//
#include "CustomRadiusWidget.h"
#include <QPainter>
#include <QPainterPath>
CustomRadiusWidget::CustomRadiusWidget(QWidget *parent) : QWidget(parent){
	setWindowFlag(Qt::FramelessWindowHint);
	setAttribute(Qt::WA_TranslucentBackground, true);
}

CustomRadiusWidget::~CustomRadiusWidget() {}

void CustomRadiusWidget::SetRadius(int radius){
	radius_ = radius;
}

void CustomRadiusWidget::SetRadiusEnable(bool left_top, bool left_bottom, bool right_top, bool right_bottom){
	left_top_ = left_top;
	left_bottom_ = left_bottom;
	right_top_ = right_top;
	right_bottom_ = right_bottom;
}

void CustomRadiusWidget::paintEvent(QPaintEvent *event)
{
	auto half_height = height() / 2;
	auto radius = radius_ > half_height ? height() / 2 : radius_;
	QPainter painter(this);
	QPainterPath draw_path;
	draw_path.addRoundedRect(rect(), radius, radius);
	draw_path.setFillRule(Qt::WindingFill);
	if (!left_top_) {
		draw_path.addRect(0, 0, width() / 2, height() / 2);
	}
	if (!left_bottom_) {
		draw_path.addRect(0, height() / 2, width() / 2, height() / 2);
	}
	if (!right_top_) {
		draw_path.addRect(width() / 2, 0, width() / 2, height() / 2);
	}
	if (!right_bottom_) {
		draw_path.addRect(width() / 2, height() / 2, width() / 2, height() / 2);
	}
	painter.setRenderHint(QPainter::Antialiasing);
	painter.setPen(Qt::transparent);
	painter.setBrush(bg_color_);
	painter.drawPath(draw_path);
}
  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值