QCalendarWidget 是一个比较复杂的 widget,由几个 QToolButton, QSpinBox, QMenu, QTableView 等组成,Qt 的帮助文档里没有其 QSS 的相关文档,当要修改其样式的时候应该怎么办呢?
我们这里采用的方法是分析组成 QCalendarWidget 的 widget 的 className 和 objectName,然后 QSS 每个 widget,最终达到修改 QCalendarWidget 样式的目的。
大圣,此去欲何?踏南天,碎凌霄。若一去不回…… 便一去不回!
QCalendarWidget 是一个比较复杂的 widget,由几个 QToolButton, QSpinBox, QMenu, QTableView 等组成,Qt 的帮助文档里没有其 QSS 的相关文档,当要修改其样式的时候应该怎么办呢?
我们这里采用的方法是分析组成 QCalendarWidget 的 widget 的 className 和 objectName,然后 QSS 每个 widget,最终达到修改 QCalendarWidget 样式的目的。
普通的 QSS 和 CSS 没什么区别,难度不大,但除此之外,想要使用好 QSS,还必须得掌握好 subcontrol,这个在 CSS 里没有,是 Qt 独有的。
什么是 subcontrol?一个复杂的 widget 由多个部分组成,它们可以是一个 widget,也可以是逻辑上的部件,例如 QCheckBox 由 icon 和 text 两个部分组成,不仅可以定义 text 的样式,还可以定义 icon 相关的样式,icon 部分就是 QCheckBox 的 subcontrol ::indicator
。
在 Qt 的帮助文档里有所有 subcontrol 的说明,但是相信很多人看了还是不明白每个 subcontrol 具体是什么,这一节将使用可视化的方式标记出 subcontrol,介绍使用 QSS 自定义有 subcontrol 的常用 widget,这里的重心是怎么去 QSS subcontrol 而不是样式效果,复杂漂亮的界面需要大量的图片和更多的 QSS,这里不作介绍,以免陷入细节,掩盖本节主题。只要知道了原理,结合已经掌握的 QSS,找美工提供一套界面切图,就能很容易实现出来很专业效果了。
Subcontrol 的 QSS 和大多数 widget 的差不多,也支持盒子模型,可以自定义 color, background, background-color, background-image, border, padding, margin, width, height 等,也支持 Pseudo-States。
Subcontrol 的绘制位置由 subcontrol-origin、subcontrol-position, top, left 来指定,就先从这几个属性开始入手。
选择器决定了 style sheet 作用于哪些 widget,QSS 支持 CSS2 定义的所有选择器。
QSS 的选择器有
*
很多时候,可以使用不同的选择器实现相同效果的样式,使用非常灵活。
每个 Widget 所在的范围都是一个矩形区域(无规则窗口也是一个矩形,只是有的地方是透明的,看上去不是一个矩形),像是一个盒子一样。QSS 支持盒子模型(Box Model),和 CSS 的盒子模型是一样的,由 4 个部分组成:content, padding, border, margin,也就是说,Widget 的矩形区域,用这 4 个矩形表示
content
: 绘制内容的矩形区域(如绘制文本、图片),Qt 自带的 widget 都是在 content 区里绘制内容,这只是一个约定,只要你愿意,也可以在绘制到 padding, border, margin 区padding
: 内容区和边框之间的间隔border
: 边框,可视化的显示一个 widget 的逻辑范围,而不一定是 widget 所占矩形区域的实际大小margin
: 想像 widget 的矩形区域有一个隐形的边框,margin 就是 border 和这个隐形边框之间的间隔QWidget 的 content, padding, border, margin 的矩形区域都是一样大的,也就是说,margin, border, padding 的值为 0,content 的矩形和 QWidget 的矩形一样大,但是 QPushButton 默认的 margin, border, padding 的值不为 0(可以试试 setFlat(true)
后再看看这几个值是什么)。
Margin,Border,Padding 都分为 4 个部分:上、右、下、左,它们的值可以不同:
前一章节我们已经知道怎么写简单的 QSS 了,但是,应该把它们放在什么地方才能生效呢?
加载 QSS 有三种方式:
setStyleSheet(qss)
函数加载 QSS,QSS 的作用域是 widget 自己和它的所有子 widgetsetStyleSheet(qss)
函数加载 QSS,QSS 的作用域是整个程序里的所有 widgetChange styleSheet...
打开的 QSS 编辑器中添加 QSS,在哪个 widget 上添加的,QSS 的作用域是那个 widget 自己和它的所有子 widget,其实和 1
是一样的,只不这里过是在 Qt Designer 里添加,不是我们自己手动写 C++ 代码添加而已。打开 ui 文件生成的代码(ui_xxxx.h),可以看到里面也是自动生成代码调用 setStyleSheet(qss)
添加 QSS 的,和我们写代码添加没有区别,只是在 Qt Designer 里添加的话,有时候方便一些,也可以实时看到 QSS 的效果
Qt 提供的 widget 的默认外观很多时候都不符合项目的界面需求,必须要改,修改一个 widget 的外观(Look and Feel)有以下的方法:
这几种方式里最简单灵活的是使用 QSS,虽然有人说 QSS 的效率低,具体有多低没测试过,但是在普通 PC 上从来没感觉出来,再说现在的硬件也不差这么点性能消耗,随便一个写的差点的函数的消耗就比这多的多,作为一个实用主义者,不追求理论上的效率完美,能满足需求的前提下什么好用用什么,QSS 就是修改 widget 外观的首选,什么效果不满意,修改一下 QSS 的文件就可以看到效果,甚至不需要重新编译、打包发布程序(如果把 QSS 放在文件中,并且实现动态加载 QSS)。
我们按下面的章节来介绍 QSS:
普通随机数算法生成的随机数真的很随意,不能做到在某个序列内是升序或者降序的,如果要生成某个范围内一序列的升序或者降序的随机数,例如用于游戏中生成随机地图,渲染海洋等,可以使用 Noise 随机数生成算法,Flow Noise 是 Noise 算法的 Java 实现,其 github 地址为 https://github.com/flow/noise#documentation
Noise generation library for Java, based on the libnoise C++ library. It is used to generate coherent noise, a type of smoothly-changing noise. It can also generate Perlin noise, ridged multifractal noise, and other types of coherent noise. https://flowpowered.com/noise
使用 Gradle 编译项目,在下载 jar 包时如果遇到 PKIX path building failed: sun.security.provider… 错误,则说明是 ssl 证书的问题,把证书加入到 JVM 的 $JAVA_HOME/jre/lib/security/cacerts 文件即可。
1 | > Could not resolve net.ltgt.gradle:gradle-errorprone-plugin:0.0.14. |
上面的异常,显示在获取 maven.eveoh.nl 下的资源时 ssl 证书有问题,可以使用 SSLPoke.class 来确定是否这个域名的 ssl 是否有问题: 执行 java SSLPoke maven.eveoh.nl 443
,输出 Successfully connected 说明 ssl 证书没问题,如抛出下面的异常则 ssl 证书有问题:
1 | sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target |
确认证书有问题的域名后,下载这个域名的证书,导入到 cacerts 文件就可以了,可以使用下面的 2 种方式下载证书:
执行 openssl s_client -showcerts -connect maven.eveoh.nl:443
(域名和端口根据实际情况进行修改)
输出:
1 | CONNECTED(00000005) |
subject (s:) 为申请证书的网站,issuer(i:) 为证书颁发者
保存证书:
1 | -----BEGIN CERTIFICATE----- |
可能会有像上面这样格式的多个证书,我们只需要 eveoh.nl 的证书,因为 0 s:/CN=eveoh.nl,所以保存第一个为文本文件 need.crt
导入证书:
1 | sudo keytool -importcert -keystore $JAVA_HOME/jre/lib/security/cacerts -file need.crt -alias eveoh |
输入 cert 文件的密码,默认的都是 changeit
使用 Firefox 打开 https 的链接: https://repo1.maven.org
点击地址栏中的小锁图标
点击 Security Connection 右边的向右箭头
More Information > Security > View Certificate > Details > Export
例如上面 cert 文件保存为 repo1.maven.org.crt
打开终端,导入 cert 文件
1 | sudo keytool -importcert -keystore $JAVA_HOME/jre/lib/security/cacerts -file repo1.maven.org.crt -alias maven |
cacerts 文件的路径和 JRE/JDK 安装的路径有关
输入 cert 文件的密码,默认的都是 changeit
重启系统
1 | sudo keytool -delete -keystore $JAVA_HOME/jre/lib/security/cacerts -alias eveoh |
1 | keytool -list -v -keystore $JAVA_HOME/jre/lib/security/cacerts |
通过查找 Alias name: yourAlias
查看证书是否导入成功。