Qt样式与特殊效果窗口

时间:2022-02-24 04:19:27

Qt样式表是一个可以自定义部件外观的十分强大的机制,可以执行所有那些单独使用调色板很困难或者无法执行的自定义操作,不会受到不同平台的准则和本地主题引擎所限制。此外,样式表可以用来给应用程序提供一个独特的外观,而不用去子类化QStyle,这样就可以很容易地实现现在大多数应用程序中所拥有的换肤功能。

1、样式规则

样式表包含了一系列的样式规则,一个样式规则由一个选择符和声明组成。选择符指定了受该规则影响的部件,声明制定了这个部件上要设置属性。

QPushButton{
background-color: rgba(100, 225, 100, 30);/*背景色*/
border-style: outset; /*边框样式*/
border-width: 4px; /*边框宽度为4像素*/
border-radius: 10px; /*边框圆角半径*/
border-color: rgba(255, 225, 255, 30);/*边框颜色*/
font: bold 14px;/*字体*/
color:rgba(0, 0, 0, 100);/*字体颜色*/
padding: 6px; /*填衬*/
}
在这个样式规则中,QPushButton是选择符,{……}是声明,而background-color等是属性,rgba(100, 225, 100, 30)是值。Qt样式表中一般不区分大小写,例如color、Color、COLOR和COloR表示相同的属性。只有类名、对象名和Qt属性名是区分大小写的。


2、伪状态

选择符可以包含伪状态来限制规则在部件的指定的状态上应用。伪状态出现在选择符之后,用冒号隔离,如:

QPushButton:hover{ /*鼠标悬停在按钮上时*/
background-color:rgba(100,255,100, 100);
border-color: rgba(255, 225, 255, 200);
color:rgba(0, 0, 0, 200);
}
这个规则表明当鼠标悬停在一个QPushButton部件上时才被应用。同时,伪状态可以使用感叹号来表示否定


3、冲突解决

当几个样式规则对相同的属性指定了不同的值时就会产生冲突。例如:

QPushButton#okButton{ color:gray }
QPushButton{ color:red }
这样okButton的color属性便产生了冲突。解决这个冲突的原则是:特殊的选择符优先。在这里,因为QPushButton#okButton一般代表一个单一的对象,而不是一个类所有的实例,所以它比QPushButton更特殊,那么这时便会使用第一个规则,okButton的文本颜色为灰色。相似的,有伪状态比没有伪状态优先。如果两个选择符的特殊性相同,则后面出现的比前面的优先。Qt样式表使用CSS2规范来确定规则的特殊性。


Qt Style Sheets Reference关键字对应的帮助文档的List of Properties一项中列出Qt样式表支持的所有属性、List of Stylable Widgets一项中列出所有可以使用Qt样式表来自定义样式的Qt部件、List of Sub-Controls一项中列出所有可用的子控件、List of Pseudo-States一项中列出Qt支持的所有伪状态。


4、不规则窗体

使用样式表可以实现矩形、圆形等规则形状的部件,不过有时想设计一个不规则形状的部件或者窗口,以使得应用程序的外观更加个性化。Qt中提供了部件遮罩(mask)来实现不规则窗体。

#include "widget.h"
#include "ui_widget.h"
#include <QPixmap>
#include <QBitmap>
#include <Qpainter>
#include <QMouseEvent>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QPixmap pix;
// 加载图片
pix.load(":/image/yafeilinux.png");
// 设置窗口大小为图片大小
resize(pix.size());
// 为窗口设置遮罩
setMask(pix.mask());
}

Widget::~Widget()
{
delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// 从窗口左上角开始绘制图片
painter.drawPixmap(0,0,QPixmap(":/image/yafeilinux.png"));
}

void Widget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
QCursor cursor;
cursor.setShape(Qt::ClosedHandCursor);
QApplication::setOverrideCursor(cursor);

qDebug() << event->globalPos() << event->pos();
qDebug() << event->x() << event->y() << pos();
offset = event->globalPos() - pos();
}
else if (event->button() == Qt::RightButton)
{
// 关闭窗口
close();
}
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
qDebug() << event->button() << event->buttons();
//if (event->button() == Qt::LeftButton)
if (event->buttons() && Qt::LeftButton)
{
QPoint temp;
temp = event->globalPos() - offset;
qDebug() << temp << event->buttons();
move(temp);
}
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
QApplication::restoreOverrideCursor();
}
这里必须在paintEvent()函数中将图片绘制在窗口上,这样运行程序时才可以正常显示图片。此程序使用一张图片来设置遮罩,其实还可以使用QRegion设置一个区域来作为遮罩。

5、透明窗体

如果想实现窗体内容部件的透明效果,只需在设置其背景色时制定alpha值即可,例如:

QPushButton{background-color:rgba(255, 255, 255, 100)}
部件的透明效果可以使用这种方式来设置,但作为*部件的窗口却无法使用这种方式来实现透明效果。不过可以使用其他两种方法来实现透明效果。

#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QMouseEvent>
#include <QLabel>
#include <QPixmap>
#include <QBitmap>
#include <Qpainter>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置窗口的不透明度为0.3
//setWindowOpacity(0.3);
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
}

Widget::~Widget()
{
delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.fillRect(rect(),QColor(255,255,255,100));
}

void Widget::mousePressEvent( QMouseEvent *event )
{
if (event->button() == Qt::LeftButton)
{
QCursor cursor;
cursor.setShape(Qt::ClosedHandCursor);
QApplication::setOverrideCursor(cursor);

offset = event->globalPos() - pos();
}
else if (event->button() == Qt::RightButton)
{
//关闭窗口
close();
}
}

void Widget::mouseReleaseEvent( QMouseEvent *event )
{
QApplication::restoreOverrideCursor();
}

void Widget::mouseMoveEvent( QMouseEvent *event )
{
if (event->buttons() & Qt::LeftButton)
{
QPoint temp;
temp = event->globalPos() - offset;
move(temp);
}
}

void Widget::mouseDoubleClickEvent( QMouseEvent *event )
{
if (event->button() == Qt::LeftButton)
{
if (windowState() != Qt::WindowFullScreen)
setWindowState(Qt::WindowFullScreen);
else
setWindowState(Qt::WindowNoState);
}
}
使用setWindowOpacity()函数就可以实现窗口的透明效果,参数取值范围为0.0~1.0,当取值为0.0时完全透明,取值为1.0时完全不透明。采用这种方式的效果是整个应用程序界面都是半透明的。


如果不想让窗口中的部件透明,可以使用如下方法:

setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
这里使用了setAttribute()函数指定窗口的Qt::WA_TranslucentBackground属性,它可以使窗体背景透明,而其中的部件不受影响。不过在Windows下,还要使用setWindowFlags()函数指定Qt::FramelessWindowHint标志,这样才能实现透明效果。这样子实现的效果是背景完全透明,要是还想实现透明效果,可以使用重绘事件。