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);
}