Qt style

1 Qt style

         许多Qt 开发人员经常会发现Qt 提供的风格不能很好的满足客户的个性化的需要,Qt 提供了三种方法来满足定制风格的需求:

         1 )继承并实现QStyle 的子类;

         2 )利用Qt 样式表;

         3 )利用QGraphicsView QGrphicsScene QGraphicsItem 框架来绘制。

1.1 QStyle

         QStyle 是一个封装了实现不同平台上 GUI 观感的基类,它控制了所有控件的界面风格,定义了大量的枚举类型和十几个函数。 QStyle 中只实现了 drawItem(), itemRect(), visualRect() 三个函数:

         1 drawItem() ,负责绘制文本和象素图;

         2 itemRect() ,返回文本或图像所占的区域;

         3 visualRect() ,返回逻辑坐标。

         其他函数在 QStyle 基类中只有声明而没有函数实现,它们的实现在 QWindowsStyle QMacStyle QMotifStyle QCommonStyle 等子类中。 <!-- @page { margin: 0.79in } P { margin-bottom: 0.08in } --> 下图展示了8种不同风格的QComboBox。

1.1.1 创建新风格

         我们可以通过创建一个定制风格来创建一个应用程序的观感,可以选择一个已经存在的 QStyle 类重新实现其虚函数来提供定制行为,或者从零开始创建一个新的 QStyle 类。

         创建 style 的第一步是选择一个 Qt 提供的 style 作为父类,一般会选择 QWindowsStyle QMacStyle QMotifStyle 来作为父类,当然也可以选择 QCommonStyle QStyle 作为父类,但是由于 QCommonStyle QStyle 中许多 GUI Style 函数细节并没有实现,因此选择后者的工作量会比前者大的多。

Qstyle 类将UI 的组成元素分为三类:

         1 Primitive Elements : 基本元素,如边框,倒角,箭头等一些基本的,被多个控件所复用的元素。基本元素本身不能单独存在。

         2 Control Elements : 控件元素,如按键,复选框等,不单是这些单独的控件,也包括复杂控件中的组成元素,如滚动条中的滑块。它和基本元素不同的地方是,它能够单独处理用户交互操作。

         3 Complex Control Elements : 复杂控件元素,复杂控件元素包含有子控件元素。例如combo boxes (复合选择框)等。它的用户交互响应,取决于用户操作的对象是哪个子控件。

         对应的有三个函数用于绘制这三类UI 元素。第二步即重新实现定制界面风格的那部分相关函数。因为不同的控件对各自的UI 有不同的要求,具体控件在绘制自己的UI 的时候,调用这些函数时所需要的参数也会有不同。这三类函数都需要传入相应的参数,大部分函数包括以下4 个参数:

         1 )绘制元素的类型(specify an enum value)

         2 )该类型对应的具体参数(用类的方式传递,基本上绘制不同的元素都需要传递自己特定的参数类(specify a QStyleOption 的子类))

         3 )用于具体绘图的QPainter

         4 )控件本身( 可选)

         下面将具体介绍一下这几个主要函数:

         1 void drawPrimitive( PrimitiveElement pe,

                                              QPainter *p,

                                              const QRect & r,

                                              const QColorGroup & cg,

                                              SFlags flags = Style_Default,

                                              const QStyleOption &opt = QStyleOption::Default ) ;

         功能:绘制基本图形元素,如QSpinBox 中的带箭头的按钮等。

         参数:PrimitiveElement pe: 这个枚举型变量表示将要绘制的基本图形界面元素(这里说的基本图形用户界面元素是指GUI 中不可再分的一个原子元素,如组合框中的绘有黑色三角形的按钮,spinBox 中的按钮;

         QPainter *p :指向QPainter 类的指针,Qt 中的所有绘制操作不管是绘制文本、图形还是图像都由这个类来处理;

         QRect &r :表示一个矩形区域,Qt 在这个区域中绘制基本界面元素(PrimitiveElement)

         QColorGroup &cg QColorGroup 表示一个控件的颜色组(color group) color group 含有控件绘制自己时使用的各种颜色,譬如前景色背景色等。下图展示了color group 中的各种颜色属性;

         SFlags flags :控制如何绘制图形界面元素的标志;

         QStyleOption &opt :绘制不同的控件时会需要不同的参数,如绘制面板(panel) 可能需要线宽作为额外参数而绘制焦点矩形(focus rect) 可能需要背景色作为额外参数,所以Qt 专门提供了一个类QStyleOption 来封装不同的widget 可能需要的不同的参数,opt 指向这样一个类的对象。

         2 void drawComplexControl( ComplexControl control,

                                                        QPainter *p,

                                                        const QWidget *widget,

                                                        const QRect &r,

                                                        const QColorGroup &cg,

                                                        SFlags flags = Style_Default,

                                                        SCFlags controls = QStyle::SC_All,

                                                        SCFlags active = QStyle::SC_None,

                                                        const QStyleOption& opt = QStyleOption::Default)

         功能:绘制复杂控制控件(widget )如SpinWidget comboBox slider listView

         参数:ComplexControl control :是一个枚举 ,表示将要 绘制 的复杂 控制控件 widget )如组合框、 列表 框等;

         QPainter *p :指向 QPainter 的指针,Qt 中的 所有绘制 操作不管是绘制文本、图形还是图像都由这个类 来处 理;

         QWidget * widget :指向 QWdget 或其 子类 的指针,可以根据上面control 的值转变(cast )成 合适 的类型,例如如果 绘制 QSpinWidget ,那么control 取值为CC_ SpinWidget widget 指向一个QSpinWidget(QWidget 的子类) 的实例。使用这个变量可以访问QSpinWidget 的成员函数和成员变量,譬如可以调用QSpinWidget sizeHint 函数获得这个部件的缺省大小(一个矩形空 间);

         QRect &r: 表示一个矩形区域,Qt 在这个区域中绘制控件或其子 控件

         QColorGroup &cg: QColorGroup 表示一个 控件 (widget) 的颜色组(color group ),color group 含有 控件 绘制自己时使用的各种颜色,譬如前景色背景色等;

         SFlags flags: 控制如何绘制图形界面元素的标志;

         SCFlags controls 表示绘制复杂控制 控件 control 的哪个子部件,缺省为SC_All, 即绘制整个control 而不是其某个子部件;

         QStyleOption &opt: 在绘制不同的 控件 时可能需要不同的额外的参数,这个变量在绘制不同的widget 时提供不同的信息。

         3 QRect querySubControlMetrics(ComplexControl control,

                                                                 const QWidget* widget,

                                                                 SubControl sc,

                                                                  const QStyleOption&

                                                                  = QStyleOption::Default)

        功能:获取子部件的坐标和尺寸信息。这个函数控制着一个复杂控件的布局,重载这个函数可以使的组合框的下拉按钮绘制在左边 而不是默认的右边。

        参数:ComplexControl control :枚举量,表示将要绘制的复杂控制 控件 widget )如组合框、列表框等;

        QWidget *widget :指向QWidget 或其子类的指针,可以根据上面control 的值转变(cast )成合适的类型,例如如果要绘制 QSpinWidget ,那么control 取值为CC_SpinWidget, widget 指向一个QSpinWidget(QWidget 的子类) 的实例。使用这个变量可以访问QSpinWidget 的成员函数和成员变量,譬如可以调用QSpinWidget sizeHint 函数获得这个部件的缺省大小(一个矩形空间);

        SubControl sc :枚举量,一个复杂 控件 可能由多个的子 控件 组成,使用sc 变量说明要获取那个子 控件 的坐标和尺寸信息;

        QStyleOption &opt: 计算不同 控件 的尺寸时可能需要不同的额外信息,QStyleOption 封装了这些信息。

1.1.2使用 QStyle 新风格

        使用新风格的方法有两种,第一种是直接在应用程序中使用重新实现的新风格,下面的例子很清晰的说明了这种方法:

        #include <QtGui>

#include “customstyle.h”

int main( int argc, char **argv )

{

QApplication::setStyle(new CustomStyle);

QApplication app(argc, argv);

QSpinBox spinBox;

spinBox.show();

return app.exec();

}

        customstyle.h 为定制的 style 头文件,上面的代码将整个应用程序的风格设置为定制的新风格。如果希望只改变应用程序的某个控件的风格,只需要调用 setStyle() 将相应的控件设置为你创建的新风格即可。另一种使用新风格的方式是直接在程序运行时加入风格参数,例如: ./xxx( 可执行文件 ) -style motif 。当然,也可以选择 mac windows 等风格,或者自定义的风格。

如果希望定制的风格可以在其他的应用程序中被使用,而不用重新编译源文件, Qt 提供了 plugin 的方式来实现其新风格的使用。 Qt 提供了一个简单的插件接口,可以轻松地生成作为独立组件的定制数据库驱动、图像格式、文本编解码、风格和控件。风格插件的基类为: QStylePlugin ,主要实现两个虚函数 keys() create() ,然后调用 QStyleFactory 将风格插件动态的装载到应用程序中。

1.2Qt 样式表

        Qt 提供第二种方式来实现一个新的风格— Qt 样式表 (QStyleSheet) Qt 样式表 (QSS) 很大程度上借鉴和参考了 HTML 的层叠样式表 (CSS) 的语法和思想,通过调用 QWidget::setStyleSheet() QApplication::setStyleSheet() ,或者通过命令行参数 - stylesheet filename.qss 可以为一个独立的子部件、整个窗口,甚至是整个个应用程序指定一个样式表。

1.2.1 QSS 语法

        Qt 样式表与 CSS 的语法规则几乎完全相同,一个样式表由一系列的样式规则构成,一般包括选择器 (selector) 和属性定义 (declearation) 组成, selector 指定哪些窗口将被这些规则影响, declearation 指定哪些属性将会被指定在窗口上。每个样式规则通常都有如下形式:

selector { attribute: value }

        selector( 选择器 ) 通常是一个类名 (eg: QComboBox) ,属性 (attribute) 部分是一个样式表属性的名字,值 (value) 部分是赋给该属性的值。

如果有几个 selector 指定了相同的 declaration, 可以使用逗号 (,) 将各个选择器分开,规则如下:

selector1,selector2,...,selectorM

{

attribute1: value1;

attribute2: value2;

attributeN: valueN;

}

        这种方式可以同时为与 M 个选择器相匹配的控件设置 N 种属性。例如:

QCheckBox,QSpinBox,QComboBox

{

color: red;

background-color: white;

font: bold;

}

        这个规则设置了所有的 QCheckBox,QSpinBox,QComboBox 的前景色、背景色和字体。此外,还可以有如下的格式:

QComboBox#myComboBox::down-arrow:!pressed { color: blue; }

        其中, QComboBox 为类型选择器 (Type Selector) #myComboBox 指定对象的实例名 ( 非必须 ) down-arrow 为子控件描述符 (subcontrol) ,和前面的字段之间用 :: 隔开,此处 down-arrow 表示组合框的下拉按键; pressed 为伪状态描述符,和前面的字段之间用 : 隔开,此处表示压下状态。完整表达的意思为:当 QComboBox 的对象 myComboBox down-arrow 按键没有被点击时显示蓝色。

1.2.2QSS 规则冲突和优先级

        由于 QSS 规则的层级关系比较复杂,有时候会出现多条规则和某一个控件相关的情况,因此,需要定义一个规则来决定哪一条规则被应用到这个控件上,主要有以下几种情况:

        1 )规则冲突

        多条规则低制定了不同的内容,这种情况经常会出现,例如:

        QPushButton:hover { color: white }

        QPushButton { color: red }

        上面这种情况其实也可以不算是冲突,因为更加具体的类型描述符定义的规则拥有更高的优先级,所以上面的规则表示:一个有鼠标悬停的按钮的文本颜色是白色的,某则为红色。然而下面的规则就可能出现冲突:

        QPushButton:hover { color: white }

        QPushButton:enable { color: red }

        两条规则的类型描述符具体程度相同,那么当一个使能的按钮有鼠标悬停的时候,颜色的定义是什么呢? QSS 的判断原则是:后面的规则的优先级高于前面的规则,因此,此处的两条规则只有后面那条规则生效,即红色生效。

        QPushButton { color: white }
        QAbstractButton { color: gray }

        一个基类及其子类都定义了针对文本颜色的规则,那么子类应用哪一条规则呢? QSS 不考虑类的继承层级优先关系,所以还是后一条规则优先级高于前一条规则。如果确实要单独设定子类的规则,需要交换规则的顺序。

        2 QSS 层叠

        QSS 可以应用在 QApplication 上,也可以单独应用在控件上,因此最终应用到某一个控件的 QSS 是通过叠加合并所有的父控件乃至应用程序的 QSS 设定来得到的。这种情况下也可能发生规则冲突,例如:

        qApp->setStyleSheet(“QPushButton { color: white }”);

        myPushButton->setStyleSheet(“* { color: blue }”);

        出现这种情况时,控件自身的 QSS 优先级高于父控件或应用程序的 QSS

        3 QSS 继承

        在标准 CSS 样式表中,一个控件的字体和颜色属性如果没有明确设定,那么将自动继承父控件属性,而 QSS 则不会自动继承,例如:

        qApp->setStyleSheet(“QGroupBox { color: white }”);

        Qt 中,这种情况下,对于 QGroupBox 中添加的子控件不会自动设置其颜色属性,如果要设置其子控件的属性,则需要明确设定:

        qApp->setStyleSheet(“QGroupBox, QGroupBox * { color: white }”);

1.3利用 QGraphics(View/Scene/Item) 框架

        Qt examples and demos 程序就是用这个框架做的,它只提供了一些简单的点、线、矩形等等,因此它能做些什么就要看你的想象力了,只不过场景和场景中所有的部件必须要重画。将现有的程序移植到新的利用 QGraphicsView QGrphicsScene QGraphicsItem 框架制作的界面上,所要的时间显然比前两者要大的多。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值