QT使用QWidget绘制圆角窗口

1. 使用QSS样式绘制

正常情况下QWIDget是不支持border-radius样式属性的,但可以通过添加Qt::WA_TranslucentBackground来使其支持border-radius
属性设置代码如下:

// Qt::FramelessWindowHint 使窗口不使用默认框架如关闭最大最小化等
// Qt::Dialog 由于我这里的窗口是继承自QDialog的,如果这里不设置此属性,在创建窗口时传入parent指针,exec()会显示不出来窗口
setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
// 设置窗口透明永用来支持圆角样式属性
setAttribute(Qt::WA_TranslucentBackground);
QStringList qss;
// 全局背景 角度
qss << "#About{background-color:#FFFFFF;border-radius:4px;}";
setStyleSheet(qss.join(""));

Qt::WA_TranslucentBackground的作用是可以使窗体背景透明,而其中部件不受影响,而此时若要设置窗口的样式则要重paintEvent(QPaintEvent *event)

1.1 重写paintEvent

绘制窗口背景颜色显示代码如下:

void About::paintEvent(QPaintEvent *event)
{
	// 指定样式操作对象
	// QStyleOption及其子类包含QStyle函数绘制图形元素所需的所有信息
    QStyleOption opt;
    // 指定要绘制this对象的样式
    opt.init(this);
    // 创建绘制对象,this为最终要进行绘制的对象
    QPainter painter(this);
    /*
    * drawPrimitive
    * 	使用option指定的样式,绘制painter指定的对象 
    * 	QStyle::PE_Widget 标识要绘制的原始元素
    */ 
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
}

1.1 不重写paintEvent的实现方式

此方式需要在Widget(About)中在放置一个Widget(foreground),但本质上还是依赖于Qt::WA_TranslucentBackground
About设置如下属性:

setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
setAttribute(Qt::WA_TranslucentBackground);

使用QGraphicsDropShadowEffect设置foreground的阴影及圆角,同时使用border-radius属性设置foreground的圆角:

//实例阴影shadow
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
//设置阴影距离
shadow->setOffset(0, 0);
//设置阴影颜色
shadow->setColor(QColor("#444444"));
//设置阴影圆角
shadow->setBlurRadius(6);
ui->forground->setStyleSheet("#forground{background-color:#FFFFFF;border-radius:6px;}");

/*
 * setGraphicsEffect(shadow); 会触发UpdateLayeredWindowIndirect failed for ptDst= ..... (参数错误)
*/
ui->forground->setGraphicsEffect(shadow);

1.2 总结

  1. 第一步设置窗口属性
  2. 第二步重新绘制窗口样式

2. 使用paintEvent绘制

总体步骤与第一种方式的步骤一致。

属性设置代码如下:


setWindowFlags(Qt::FramelessWindowHint | Qt::Dialog);
setAttribute(Qt::WA_TranslucentBackground);

绘制窗口显示代码如下:

void About::paintEvent(QPaintEvent *event)
{
	// 创建绘图对象,并指定this为“画板”
	QPainter painter(this);
	/*
	* setRenderHint:设置渲染属性
	*    QPainter::Antialiasing:表示如果可能,引擎应该对图元的边缘进行抗锯齿处理
	*/ 
	painter.setRenderHint(QPainter::Antialiasing);
	/*
	* Brush用于填充背景
	*/ 
	painter.setBrush(QColor(255,255,255));
	// Pen 用于绘制轮廓线
	painter.setPen(Qt::transparent);
	// 获取绘制区域
	QRect rect = this->rect();
	// 设置绘制区域宽度
	rect.setWidth(rect.width());
	// 设置绘制区域高度
	rect.setHeight(rect.height());
	/*
	* drawRoundedRect 绘制带圆角的矩形
	*/ 
	painter.drawRoundedRect(rect, 4, 4);
	
	QWidget::paintEvent(event);
}

3. 增加鼠标拖动事件

为了使无框架窗口捕获事件需要安装事件捕获,以便捕获各种事件。

安装事件过滤器:

installEventFilter(this);

捕获事件进行处理:

bool About::eventFilter(QObject *watched, QEvent *evt) {
	// 鼠标位置
    static QPoint mousePoint;
    // 是否按下标记
    static bool mousePressed = false;
	// 将事件转换为鼠标事件
    QMouseEvent *event = static_cast<QMouseEvent *>(evt);
    // 鼠标按下
    if (event->type() == QEvent::MouseButtonPress) {
    	// 左键按下
        if (event->button() == Qt::LeftButton) {
        	// 设置按下标记为true
            mousePressed = true;
            /*
            * this->pos() 获取此窗口在父窗口中的位置
            * event->globalPos() 鼠标按下时的全局位置
            * mousePoint 鼠标按下时在此窗口中的位置
            */ 
            
            mousePoint = event->globalPos() - this->pos();
            return true;
        } else {
            exit(0);
        }
    } else if (event->type() == QEvent::MouseButtonRelease) {
        mousePressed = false;
        return true;
    } else if (event->type() == QEvent::MouseMove) {
        if (mousePressed && (event->buttons() && Qt::LeftButton)) {
        	/*
        	* 移动窗口
        	*/ 
            this->move(event->globalPos() - mousePoint);
            return true;
        }
    }
    return QWidget::eventFilter(watched, event);
}

4. Demo

使用border-radius属性方式一
使用border-radius属性方式二
不使用border-radius属性方式

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值