ZAARONBIN - 博客园

第八章 Qt之界面外观

8.1 Qt风格

Qt的各种风格是一组继承自QStyle抽象基类的类,封装了一个GUI的外观,Qt的内建(built-in)部件使用它来执行几乎所有的绘制工作。

//运行程序的全局风格设定
QApplication a(argc, argv);
a.setStyle(QStyleFactory::create("fusion"));

//特定部件的分隔设定
ui->progressBar->setStyle(QStyleFactory::create("windows"));

//可以通过子类化Qt的风格类或者子类化QCommonStyle类,进行风格的自定义

调色板QPalette类包含了部件各种状态的颜色组。一个调色板包含3中状态:激活(Active)、失效(Disabled)和非激活(Inactive)。Qt中所有部件都包含一个调色板,并且使用各自的调色板来绘制它们自身。

  • 激活颜色组:QPalette::Active, 用于获得键盘焦点的窗口
  • 非激活颜色组:QPalette::Inactive,用于其他没有获得键盘焦点的窗口
  • 失效颜色组:QPalette::Disabled,用于因为一些原因而不可用的部件(非窗口)
palette(); 	//该函数用于获取应用程序或部件的调色板
setPalette();	//该函数用于使用调色板
#include <QStyleFactory>
#include <QPalette>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->progressBar->setStyle(QStyleFactory::create("windows"));

    QPalette palette1 = ui->pushButton->palette();
    palette1.setColor(QPalette::ButtonText, Qt::red);
    palette1.setColor(QPalette::Button, Qt::green);
    ui->pushButton->setPalette(palette1);

    ui->spinBox->setDisabled(true); //设置SpinBox不可用
    QPalette palette2 = ui->spinBox->palette();
    palette2.setColor(QPalette::Disabled, QPalette::Base, Qt::blue);
    ui->spinBox->setPalette(palette2);
}

void QPalette::setColor(QPalette::ColorGroup group, QPalette::ColorRole role, const QColor &color)
/*
ClolorGroup: QPalette::Disabled、QPalette::Active、QPalette::Inactive、QPalette::Normal

ColorRole:QPalette::Window,....
*/


8.2 Qt样式表

Qt样式表是一个可以自定义部件外观的十分强大的机制,除了那些能够通过子类化QStyle更改的外观,其余的都可以使用Qt样式表来美化。

8.2.1 样式表介绍

QApplication::setStyleSheet();	//设置全局样式
QWideget::setStyleSheet();	//对特定部件设置样式
//如果在不同的级别都设置了样式表,那么Qt会使用所有有效的样式表,这被称为样式表的层叠

样式表与调色板的比较

  • 样式表比调色板强大
  • 调色板受风格的限制、平台的限制和本地化引擎的限制
  • 样式表可以执行所有的那些单独使用调色板很困难或者无法执行的自定义操作
  • 样式表应用在当前的部件风格之上
  • 可以不用子类化QStyle,对应用程序提供一个独特的外观

a)使用代码设置样式表

//    ui->pushButton->setStyleSheet("background:yellow");				//对于特定部件设置样式
//    ui->horizontalSlider->setStyleSheet("background:blue");			//对于特定部件设置样式
setStyleSheet("QPushButton{background:yellow}QSlider{background:blue}");	//对于一类部件设置样式

b)在设计模式中设置样式表

8.2.2 样式表语法

Qt样式表的术语和语法规则与HTML CSS基本相同

a)样式规则

样式表包含了一系列的样式规则,每个样式规则由选择器(selector)和声明(declaration)组成,选择器制定了受该规则影响的部件,声明指定了这个部件上要设置的属性。样式表中一般不区分大小写,只有类名、对象名和Qt属性名是区分大小写的

QPushButton{
    color:red;
}
/*QPushButton为选择器、color表示属性、red表示该属性的值*/

QPushButton,QLineEdit,QComBox{
    color:red;	/*所有的属性可通过Qt Style Sheet Reference关键字的List of Properties中查看*/
}
/*当多个选择器采用相同的声明时,可以用逗号将选择器隔开*/

b)选择器类型

c)子控件

QComboBox::drop-down{
    image:url(dropdown,png);
}
/*为QComboBox部件的drop-down控件设置样式表;spinBox中的上下箭头等都为子控件*/
Qt Style Sheet Reference
	List of Properties			//样式表中的属性
	List of Stylable Widgets	//可以使用样式表自定义的Qt部件
	List of Sub-Controls		//所有可用的子控件
	List of Pseudo-States		//Qt支持的所有伪状态

e)伪状态(Pseudo-States)

选择器可以包含伪状态来限制规则在部件的指定状态上的应用,伪状态出现在选择器之后,哦那个冒号隔开

QPushButton:hover{
    color:red;
}
/*该规则表明当鼠标悬停在一个QPushButton部件上时才被应用,伪状态可以使用感叹号来表示否定,使用感叹号后表示鼠标没有悬停才使用该规则*/
QPushButton:!hover{
    color:red;
}
/*伪状态可以连用,状态之间通过冒号隔开*/
QCheckBox:hover:checked{}

f)冲突解决

当多个样式规则对相同属性制定了不同的值时就会产生冲突

解决冲突的原则:特殊的选择器优先。

QPushButton#okButton{color:gray}
QPushButton{color:red}
/*okButton相对于QPushButton而言,前者为某一固定部件,后者为一类部件,前者优先
有伪状态比没有伪状态优先
选择器的特殊性相同时,后面出现的比前面的优先*/

g)层叠

​ 样式表可以设置在QApplication上、父部件上或子部件上。部件有效的样式表是通过部件祖先的样式表和QApplication上的样式表合并得到的。当发生冲突时,部件自己的样式表优先于任何继承的样式表,同样,父部件的样式表优先于祖先的样式表。即越接近部件本身越优先

h)继承

​ 当使用Qt样式表时,部件并不会自动从父部件继承字体和颜色设置。例如,一个QPushButton包含在一个QGroupBox中,当对QGroupBox设置样式表并不会对QPushButton起作用,应对选择器的类型进行更改使QPushButton应用相同的样式表:

QGroupBox{
    color:red;
}

//对QGroupBox和它的的子孙部件应用样式
QGroupBox,QGroupBox *{
    color:red;
}

I)设置QObject属性

从Qt4.3开始,任何可设计的Q_PROPERTY都可以使用”qproperty-属性名称“语法设置样式表

MyLabel{qproperty-pixmap:url(pixmap.png);};
MyGroupBox{qproperty-titleColor:rgb(100,200,100);}
QPushButton{qproperty-iconSize:20px 20px;}

8.2.3 自定义部件外观与换肤

当使用样式表时,每一个部件都被看做拥有4个同心矩阵的盒子,从内到外分别表示为内容(content)、填衬(padding)、边框(border)和边距(margin)。边距、边框宽度和填衬等属性默认值为0,默认4个矩形恰好重合。

  • 通过background-image属性为部件指定一个背景,该背景在边框以内的区域绘制,通过background-clip属性更改
    • 通过background-repeat和background-origin控制背景图片的重复方式以及原点
    • 该属性设置的背景不能随着部件的大小自动缩放,使用border-image可以实现该效果
      • 如果同时指定了上述两个属性,则border-image会绘制在background-image上

Qt样式表可以存放在一个.qss为后缀的文件中,这样就可以在程序中调用不同的.qss文件来实现更换样式表的功能

#include <QFile>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qssFile = new QFile(":/qss/my.qss", this);
    // 只读方式打开该文件
    qssFile->open(QFile::ReadOnly);
    // 读取文件全部内容
    QString styleSheet = QString(qssFile->readAll());
    // 为QApplication设置样式表
    qApp->setStyleSheet(styleSheet);
    qssFile->close();
}

void MainWindow::on_pushButton_clicked()
{
    if(qssFile->fileName() == ":/qss/my.qss")
        qssFile->setFileName(":/qss/my1.qss");
    else qssFile->setFileName(":/qss/my.qss");
    qssFile->open(QFile::ReadOnly);
    QString styleSheet = QString(qssFile->readAll());
    qApp->setStyleSheet(styleSheet);
    qssFile->close();
}

8.3 特殊效果窗体

8.3.1 不规则窗体

​ 使用样式表可以实现矩形、圆形等规则形状的部件;对于一个不规则形状的部件或者窗口,Qt提供了部件遮罩(mask)来实现不规则窗体。

#include <QPixmap>
#include <QBitmap>
#include <QPainter>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

//    QPixmap pixmap(":/images/yafeilinux.png");		//加载资源文件中的图片
//    ui->label->setPixmap(pixmap);						//为标签设置图片
//    ui->label->setMask(pixmap.mask());				//为标签设置遮罩

    QPixmap pix;
    pix.load(":/images/yafeilinux.png");
    //设置窗口大小为图片大小
    resize(pix.size());
    //为窗口设置遮罩
    setMask(pix.mask());

}

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

void Widget::mousePressEvent(QMouseEvent *event)
{
    Q_UNUSED(event);
    close();
}

8.3.2 透明窗体

通过样式表将背景色指定的alpha值进行更改即可实现。

QPushButton{
    background-color:rgba(255,255,255,100);
}
/*rgba中的a即代表alpha,其取值范围为0~255,取值为0时表示完全透明,取值为255时表明完全不透明。
部件的透明效果可以像上述一样进行设置,但顶级窗口无法使用该方式实现透明效果
*/

设置窗口的透明度

//方法1
setWindowOpacity();	//通过该函数可以设置窗口整体的透明效果(包括部件),其参数值在0~1.0之间;0表示完全透明
//方法2
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground); //仅对窗体背景起作用,不影响部件;该方法的透明效果为背景完全透明,无法实现半透明效果
//方法3:在方法2的基础上添加paintEvent事件
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.fillRect(rect(), QColor(255,255,255,200));
    /*通过rect()函数获取窗口的内部矩形,不包含任何边框
    之后使用半透明的白色对该矩形进行填充
    fillrect()函数可以指定任意一个区域*/
}
//方法4:通过QGraphics相关的类可以进行设置
posted @ 2021-03-29 10:51  BINBINBINZ  阅读(875)  评论(0)    收藏  举报