界面优化
1、QSS
1.1、QSS设置方式
在网页前端开发领域中,CSS是一个至关重要的部分。描述了一个网页的样式。从而起到对网页美化的作用。CSS能够针对界面的样式来进行设置包括但不限于:大小、位置、颜色、背景、间距、字体等等。Qt 仿照 CSS 的模式,引入了QSS来对Qt中的控件做出样式上的设定,QSS中只能支持部分CS 属性,整体来说QSS要比CSS更简单一些。
注意:如果通过QSS设置的样式和通过C++代码设置的样式冲突,则QSS优先级更高。
基本语法:

例如针对QPushButton设置:
QPushButton { color: red; }
QPushButton {
color: red;
}
1、样例:创建两个按钮,给按钮设置QSS样式,修改文字颜色。

设置样式可以指定某个控件来设置,制定了控件之后设置的样式只会针对这个指定的控件及其子控件。
那么为了让两个按钮的字体颜色都发生变化,此时我们给widget设置样式。

2、样例:可以通过QApplication的setStyleSheet设置整个程序的全局样式。
全局样式的优点:
- 使同一个样式针对多个控件生效,代码更简洁。
- 所有控件样式内聚在一起,便于维护和问题排查。

2.1、如果设置了全局样式,然后在某个控件里面又设置了其他样式会怎么样?
此时这两方面的样式会叠加。这就是样式的层叠性。

2.2、如果设置了全局样式,在某个控件里面设置的样式跟全局样式冲突了,又会怎样?
当全局样式和局部样式冲突了,局部样式的优先级更高,局部样式覆盖全局样式。实际开发中就可以在全局设置比较通用的样式,统一界面的整体风格,然后针对需要微调的控件使用局部样式。

上面的代码我们都是将样式代码和C++代码混在一起,如果QSS代码比较简单那么无所谓,但是如果QSS代码也比较复杂那维护成本就比较高了。因此我们可以将样式代码单独拎出来放到一个文件中,后续通过C++代码读取文件设置样式。
3、样例:将样式写到qss文件中,通过qrc机制引入qss文件并设置样式。
3.1、创建qrc文件,通过qrc管理样式文件。

3.2、创建单独的qss文件,把这样的文件放到qrc中。


3.3、编写C++代码读取qss文件内容,并设置样式。

这个方案仅供参考,实际上还有更好的方式。Qt Designer直接集成了这样的功能,允许我们把样式直接写到ui文件中。
4、样例:通过Qt Designer直接修改样式表。


通过这样的方式可以将样式记录到ui文件中,并且在程序中自动生效,还可以实时预览。后续会根据ui文件中的内容生成C++代码,就会把样式设置过去。
由于设置样式太灵活,就导致如果某个控件样式不符合预期时,排查起来比较麻烦。比如设置样式有下面这样方式:
1、通过全局的方式来设置样式(QApplication)。
2、指定控件来设置样式。
3、通过父控件设置样式(子控件继承父控件的样式)。
4、qss文件设置样式,然后通过qrc引入。
5、Qt Designer编辑样式表,设置到ui文件中。
…
所以实际开发中设置样式最好统一使用一种方式。
1.2、选择器
1.2.1、选择器概况
QSS的选择器支持以下几种:


上面用的就是类型选择器,所有QWidget及其子类都会生效,QPushButton也是QWidget的子类,所以也生效。

上面用的是类选择器,针对所有的QWidget类生效,子类不生效。所以按钮文字没有变色。

上面用了类型选择器和ID选择器,当类型选择器和ID选择器冲突的时候,ID选择器的优先级更高。如果不冲突,两种样式就会叠加生效。

上面用了类型选择器+并集选择器,也可以使用ID选择器+并集选择器的方式来实现。
1.2.2、子控件选择器
有些控件内部包含了多个子控件。比如QComboBox的下拉后的面板,比如QSpinBox的上下按钮等。可以通过子控件选择器::,针对上述子控件进行样式设置。

可以在Qt帮助手册里面搜索style sheet,选择Qt Style Sheets Reference,然后再选择List Of Sub-Controls,查看Qt有哪些子控件。
样例:给QComboBox的子控件下拉框按钮设置图标,图片我们可以提前选择然后通过qrc引入。

1.2.3、伪类选择器
伪类选择器是根据控件所处的某个状态被选择的。例如按钮被按下,,输入框获取到焦点,鼠标移动到某个控件上等。
- 当状态具备时,控件被选中, 样式生效。
- 当状态不具备时,控件不被选中,样式失效。

样例:创建一个QPushButton,通过style设置字体颜色,同时通过伪类选择器设置鼠标放到控件上、鼠标按下字体颜色发生变化。

上述功能也可以通过前面所说的事件来实现。比如重写enterEvent和mousePressEvent函数。
1.3、盒子模型
在文档的Customizing Qt Widgets Using Style Sheets的The Box Model章节介绍了盒模型。

就好比你家房子的墙是有一定的厚度的,这就是边框。你家和邻居家之间会有间隔,这就是外边距。然后你家会有家具,比如冰箱、洗衣机等等,这些家具又和墙有一定的距离,这就是内边距。

样例:创建一个QPushButton,给QPushButton设置样式。

使用外边距,实际上整个控件的大小还是200x100,但是显示效果看起来就像被压缩了一样。还可以创建QLabel给其设置内边距。
1.4、控件样例示例
1、给按钮设置样式。

在设置颜色的时候我们可以直接点击添加颜色进行选择。


2、创建一个复选框,给子控件方框设置样式,当默认状态、鼠标放上去时、鼠标按下时分别有不同的展示效果。

2)创建复选框然后设置样式。这边当我们要设置qrc导入的图片可以点击左上角的添加资源,然后选择resource root就可以选择图片了。



3、给单行输入框设置样式。


4、给QListWidget设置样式。
这里我们想让鼠标放到每一个item上面背景色有一个渐变的效果,也就是设置渐变色。默认直接设置背景色是纯色的,我们可以用qlineargradient设置渐变色(线性渐变)。需要填写六个参数:
x1:起点的横坐标。y1:起点的纵坐标。x2:终点的横坐标。y2:终点的纵坐标。这里坐标的取值只有0和1。
比如:x1=0,y1=0,x2=1,y2=0。就是从左到右渐变。
比如:x1=0,y1=0,x2=0,y2=1。就是从上到下渐变。
比如:x1=0,y1=0,x2=1,y2=1。就是对角线从坐上到右下渐变。
剩下两个参数是:stop:0 起始颜色,stop:1 结束颜色。

5、给菜单和菜单项设置样式。

6、实现一个登录界面,用QSS进行样式美化。

首先创建如图所示控件,然后通过垂直布局管理器管理起来,然后可以给输入框设置高度,可以通过右侧属性设置最小高度、最大高度为50,这样就可以固定输入框的高度。
然后想让一个窗口好看,一个比较好的办法就是设置一张背景图片,那么正常来说我们都会直接给顶层窗口QWidget设置背景图,但是Qt中存在限制,不能直接给顶层窗口设置背景图,如果直接设置会失效。所以想要实现我们的需求就得再套一层QFrame。

接着我们需要通过qrc引入背景图片,然后设置QSS样式表。

说明:Qt中设置背景图片除了background-color还有border-image。前者固定图片大小,后者会自动随着控件的大小变化而变化。
2、绘图
2.1、基本概念
虽然Qt已经内置了很多的控件,但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的自定制能力。Qt提供了画图相关的API,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计。
所谓的控件,本质上也是通过画图的方式画上去的。画图API和控件之间的关系,可以类比成机器指令和高级语言之间的关系。控件是对画图API的进一步封装。画图API是控件的底层实现。

注意事项:画图相关操作一般不会直接放到QWidget构造函数中调用执行。而是重写Qt提供的paintEvent事件处理函数,在该函数中进行调用。与该函数对应的就有一个QPaintEvent事件,而该事件触发有以下几种情况。
1、控件首次创建的时候。比如往QWidget上画画,QWidget创建之前画的东西就不生效,创建之后画的才能生效。
2、控件被遮挡再解除遮挡。这时候需要再次绘制,否则绘制的内容被遮挡之后就没了。
3、窗口最小化再还原。
4、控件大小发生变化。
5、主动在代码中调用repaint或update触发事件,这都是QWidget提供的成员函数。
2.2、绘制各种形状
下面先简单画一些线段图形。

说明:
1、创建QPainter的时候我们是在栈上创建的,但是传入this不是指定父元素,而是指定绘制的设备,往哪里画。
2、画线段就是给出两个点,参数可以直接传两个点的坐标,也可以传QPoint。画矩形参数就是坐标+宽度+高度。画圆形的参数一个是圆心,一个是外接矩形的宽度和高度。比如我们第二个画的正圆形,他的外界矩形长宽一致,就是正方形,所以画出来的就是正圆形。
接下来是绘制文字:

我们发现第一个在原点绘制的文字没有显示出来,然后第二次绘制的正常显示了。这是为什么呢?

如上图,我写英语作文的时候会有四条线,然后我们正常写单词如上所示。这第三条线就是基线,然后我们会发现绘制的hello这些字母都是在基线上面的。而我们前面函数指定的坐标0,0,第一个0横坐标表示文字的最左侧位置,第二个0纵坐标表示文字的基线位置,而字母都在基线上所以显示不出来。
另外我们也可以设置绘制文字的样式:

接着我们还可以设置画笔QPen,QPainter在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在Qt中,QPen类中定义了QPainter应该如何绘制形状、线条和轮廓。同时通过QPen类可以设置画笔的线宽、颜色、样式、画刷等。画笔的颜色可以在实例化画笔对象时进行设置,画笔的宽度是通过setWidth()方法进行设置,画笔的风格是通过setStyle()方法进行设置,设置画刷主要是通过setBrush() 方法。

比如设置画笔宽度和颜色和风格,让他画一个红色、虚线的椭圆。

设置画刷:在 Qt 中,画刷是使用QBrush类来描述,画刷大多用于填充。QBrush定义了QPainter的填充模式,
具有样式、颜色、渐变以及纹理等属性。画刷的格式中定义了填充的样式,使用Qt::BrushStyle枚举,默认值是Qt::NoBrush,也就是不进行任何填充。可以通过Qt助手查找画刷的格式。如下图示:

设置画刷主要通过void QPen::setBrush(const QBrush &brush) 方法,其参数为画刷的格式。
下面添加画刷,给我们画出来的椭圆填充绿色。

2.3、绘制图片
Qt提供了四个类来处理图像数据:QImage、QPixmap、QBitmap和QPicture,它们都是常用的绘图设备。
其中QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且可以用来直接访问和操作像素;
QPixmap主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;
QBitmap是QPixmap的子类,用来处理颜色深度为1的图像,即只能显示黑白两种颜色;
QPicture用来记录并重演QPainter命令。
下面演示通过QPixmap来绘制图片,首先创建新项目通过qrc导入图片。

下面还可以将图片进行旋转绘制:


说明:
1、旋转后坐标系就变成了如上图所示,所以正常直接绘制图片是看不到的,因为此时坐标系已经变了。
2、为了能够正常绘制图片,我们需要把坐标系原点平移以下,也就是转移到窗口的右下角,但是由于坐标系已经翻转了,所以此时右下角的坐标应该是-800,-600,所以通过transalte平移。
相当于是先旋转坐标系,然后再移动画家,最终再根据旋转后的坐标系绘制出图片。
还可以保存和加载画家的状态。在绘制图形的过程中,可以通过save()函数来保存画家的状态,使用restore()函数还原画家状态。函数原型如下:


save函数只会保存绘制的状态,在代码中我们先移动了画家然后保存一次状态,又移动了一次画家然后恢复,此时画家就会回到只移动了一次的状态,因为我们再那里保存了一次状态。再比如下面的执行顺序:
初始状态
└─ save()
└─ translate
└─ save()
└─ rotate
└─ draw
└─ restore() ← 只撤销 rotate
└─ draw
└─ restore() ← 撤销 translate
330

被折叠的 条评论
为什么被折叠?



