QT 5.9 中样式 (Styles) 和样式相关的窗口部件 (Style Aware Widgets)

本文详细介绍了Qt中样式(QStyle)的定制与实现过程,包括样式元素、样式选项及调色板等内容,同时提供了实现自定义样式的具体步骤。

内容 

1 定制样式概述 (Customizing a Style)

2 实现一个自定义样式 (Implementing a Custom Style)

3 与窗口样式相关的类 (Classes for Widget Styling)

4 QStyle的实现 (The QStyle Implementation)

    4.1 样式元素 (The Style Elements)

    4.2 样式选项 (Style Options)

    4.3 QStyle函数 (QStyle Options)

    4.4 调色板 (The Palette)

    4.5 实现过程中的问题 (Implementation Issues)

5 Java 样式 (Java Style)

    5.1 设计与实现 (Design and Implementation)

    5.2 限制与和Java的差异 (Limitations and Differences from Java)

    5.3 Java样式复选框 (Styling Java Check Boxes)

6 窗口预排 (Widget Walkthrough)

    6.1 普通的窗口特性 (Common Widget Properties)

    6.2 窗口参考 (Widget Reference)

 

样式与样式相关的窗口 (Styles and Style Aware Widgets)

样式(继承自QStyle)绘制于窗口之上,封装了某个GUI的外观和感觉。QStyle类是一个抽象基类,封装了某一GUI的外观和感觉。Qt的内置窗口使用它来实现几乎所有绘制。确保他们与等价的本地窗口看起来一模一样。

Styles (classes that ihherit QStyle) draw on behalf of widgets and encapsulate the look and feel of a GUI. The QStyle class is an abstract base class that encapsulates the look and feel of a GUI. Qt's built-in widgets use it to perform nearly all of their drawing, ensuring that they look exactly like the equivalent native widgets.

Qt自带一系列内置样式。一些样式只在特定平台可用 (比如Mac和Windows Vista). 可以通过插件来自定义样式或者通过QStyleFactory::create()函数创建一个特定的样式,然后使用QApplication::setStyle()函数进行设置。

Qt comes with a selection of built-in styles. Some styles are only available on specific platforms (such as the Mac and Windows Vista styles). Custom styles are made available as plugins or by creating an instance of a specific style class with QStyleFactory::create() and setting it with QApplication::setStyle().

 

自定义样式 (Customizing a Style)

为了定制化一个现存的样式, 继承QProxyStyle并实现要求的虚方法。 QProxyStyle允许来指定一个特定的基础样式,如果并未指定基础样式,它会自动使用应用程序的样式。前一种方法完全控制了基础样式并且效果最好,在定制化期望实现某一特定样式行为,与此同时,后一种方法提供了平台无关的方法来定制与本地平台样式默认的应用程序样式。

In order to customize an existing style, inherit QProxyStyle and reimplement the desired virtual methods. QProxyStyle allows one to specify a certain base style, or it will automatically use the application style when the base style is left unspecified. The former gives a full control on the base style and works best if the customization expects a certain style behavior, whereas the latter provides a platform agnostic way to customize the application style that defaults to the native platform style.

 

实现自定义样式 (Implementing a Custom Style)

QCommonStyle为完全自定义样式的实现提供了一个方便的基类。这个方法与QProxyStyle相同,只是继承了QCommonStyle并且实现了QCommonStyle的虚方法。实现一个完整的自定义样式在某种程度上包括了,所以我们提供了这个预览。我们给出一个一步一步的预排关于如何为单独的Qt窗口定制样式。我们会检查QStyle的虚函数,成员变量和枚举。

文章的这个部分并不关心单独窗口的样式意味着最好顺序的读,因为后面的章节依赖于前面的章节。当实现一个样式的时候,窗口的描述可以被用来参考。然而,在某些特定情况下,你可能需要来咨询Qt源码。在阅读这个文档以后,样式处理的顺序会变得清楚,可以帮助你定位相关的代码。

为了开发样式相关的窗体 (举个例子,需要符合他们所画样式的窗体),你需要来画他们使用当前的样式。这个文档显示了窗体如何绘制他们自己和样式会给他们以何种可能性。

QCommonStyle provides a convenient base for full custom style implementation. The approach is same than with QProxyStyle, but inherit QCommonStyle instead and reimplement the appropriate virtual methods. Implementing a full custom style is somewhat involved, and we therefore provide this overview. We give a step-by-step walkthrough of how to style individual Qt widgets. We will examine the QStyle virtual functions, member variables, and enumerations.

The part of this document that does not concern the styling of individual widgets is meant to be read sequentially because later sections tend to depend on earlier ones. The description of the widgets can be used for reference while implementing a style. However, you may need to consult the Qt source code in some cases. The sequence in the styling process should become clear after reading this document, which will aid you in locating relevant code.

To develop style aware widgets (i.e., widgets that conform to the style in which they are drawn), you need to draw them using the current style. This document shows how widgets draw themselves and which possibilities the style gives them.

窗体样式相关类 (Classes for Widget Styling)

这些类用来自定义一个应用程序的外观和样式。

These classes are used to customize an application's appearance and style.

QCursor带有随机形状的鼠标指针(Mouse cursor with an arbitrary shape)
QPalette为每一个窗体状态包含一个颜色组(Contains color groups for each widget state)
QColor基于RGB,HSV或者CMYK值的颜色(Colors based on RGB, HSV or CMYK values)
QFont为绘制文本指定一种字体(Specifies a font used for drawing text)
QFontDatabase在当前窗体系统中关于字体可用性信息(Information about the fonts available in the underlying window system)
QFontInfo关于字体的一般信息(General information about fonts)
QGraphicsAnchor在QGraphicsAnchorLayout的两个项目之间呈现一个锚(Represents an anchor between two items in a QGraphicsAnchorLayout)
QGraphicsAnchorLayout用户可以用来在图形视图中将窗体固定起来的布局(Layout where one can anchor widgets together in Graphics View)
QCommonStyle封装GUI通用的视图和感觉(Encapsulates the common Look and Feel of a GUI)
QStyle抽象基类封装了GUI的外观和感受(Abstract base class that encapsulates the look and feel of a GUI)
QStyleFactory创建QStyle对象 (Creates QStyle objects)
QStyleHintReturn样式标注,返回的比基本数据类型更多(Style hints that return more than basic data types)
QStyleHintReturnMask样式标注,返回QRegion (Style hints that return a QRegion)
QStyleHintReturnVariant样式标注,返回QVariant (Style hints that return a QVariant)
QStyleOption存储由QStyle函数使用的参数 (Stores the parameters used by QStyle functions)
QStylePainter工具类用于在一个窗体内部绘制QStyle元素 (Convenience class for drawing QStyle elements inside a widget)

 

QStyle的实现 (The QStyle Implementation)

QStyle 的API函数包含了用于绘制窗体,静态帮助函数来做通用的和困难的任务(举例来说,计算滑动条句柄的位置) 和在绘制的过程中做各种各样必要计算工作的函数(举个例子,对窗体而言计算它们的尺寸标注)。 样式也帮助一些窗体来布局它们的内容。此外,它创建了一个QPalette包含了用于绘制的QBrushes。

QStyle绘制图形元素;一个元素是一个窗体或者窗体的一部分像一个按钮斜角,一个窗体框,或者一个滚动条。大多数绘制函数现在接受四个参数:

一个枚举值指定哪一个图形元素要绘制;

一个QStyleOption指定如何和哪里来绘制那个元素;

一个用来绘制这个元素的QPainter;

一个QWidget,绘制行动执行在这个对象之上(可选);

当一个widget要求一个样式来绘制一个元素,它使用一个QStyleOption来提供样式,这是一个包含必要绘制信息的类。感谢有了QStyleOption,这使得QStyle绘制窗体不需要为这个窗体链接任何别的代码。这使得使用QStyle的绘制函数在任何绘制设备上绘画成为可能,举个例子,你可以绘制一个combobox在任何窗体上,而不是仅仅在QComboBox上。

窗体作为最后一个参数被传递,为了万一样式需要窗体来执行特殊效果(比如在macOS上按钮的默认动画效果),但是这不是强制的。

就本节而言,我们会看看样式元素,样式选项和QStyle的函数。最后,我们描述如何使用调色板。

项目在项目视图中通过Qt中的代理绘制。项目视图的头仍然通过样式进行绘制。Qt的默认代理,QStyledItemDelegate,绘制他的项目部分通过当前的样式;他绘制check box  提示器和计算边界矩阵为项目组成的元素。在这个文档中,我们仅仅描述如何来实现QStyle的子类。假如你希望来为其他的数据类型添加支持而不是被QStyledItemDelegate指定的数据类型,你需要来实现一个自定义代理。注意到代理必须为每一个单独的窗体有计划地设置(举个例子,默认代理不能作为一个插件进行提供)。

The API of QStyle contains functions that draw the widgets, static helper functions to do common and difficult task (e.g.,calculating the position of slider handles) and functions to d the various calculations necessary while drawing (e.g., for the widgets to calculate their size hints). The style also helps some widgets with the layout of their contents. In addition, it creates a QPalette that contains QBrushes to draw with.

QStyle draws graphical elements; and element is a widget or a widget part like a push button bevel, a window frame, or a scroll bar. Most draw functions now take four arguments:

an enum value specifying which graphical element to draw

a QStyleOption specifying how and where to render that element

a QPainter that should be used to draw the element

a QWidget on which the drawing is performed (optional)

When a widget asks a style to draw an element, it provides the style with a QStyleOption, which is a class that contains the information necessary for drawing. Thanks to QStyleOption, it is possible to make QStyle draw widgets without linking in any code for the widget. This makes it possible to use QStyle's draw functions on any paint device, i.e., you can draw a combobox on any widget, not just on a QComboBox.

The widget is passed as the last argument in case the style needs it to perform special effects (such as animated default buttons on macOS), but it isn't mandatory.

In the course of this section, we will look at the style elements, the style options, and the functions of QStyle. Finally, we describe how the palette is used.

Items in item views are drawn by delegates in Qt. The item view headers are still drawn by the style. Qt's default delegate, QStyledItemDelegate, draws its items partially through the current style; it draws the check box indicators and calculates bounding rectangles for the elements of which the item consists. In this document, we only describe how to implement a QStyle subclass. If you wish to add support for other datatypes than those supported by the QStyledItemDelegate, you need to implement a custom delegate. Note that delegates must be set programmatically for each individual widget (i.e., default delegates cannot be provided as plugins).

样式元素 (The Style Elements)

一个样式元素是一个GUI的图形部分。一个窗体由样式元素的层级(树)组成。举个例子,当一个样式收到一个请求来绘制一个按钮(从QPushButton, 举个例子), 他绘制一个标签(文字和图标),一个按钮斜角,和一个聚焦框架。按钮斜角,反过来,由斜角周围的框架和两个其他元素组成,这会在后面讲到。下面是一个概念性的展示关于按钮树。我们会看到真实的QPushButton树当我们讲到具体窗体的时候。

窗体不必要绘制通过请求样式只绘制一个元素。窗体可以向样式做几次请求来绘制不同的元素。一个例子是QTabWidget,他分别来绘制标签和框架。

有三种元素类型:基本元素,控件元素,和复杂控件元素。元素通过ComplexControl,ControlElement,和PrimitiveElemen枚举进行定义。 每一种元素枚举有一个前缀来确定它们的类型:CC_表示复杂元素,CE_表示控件元素,PE_表示基本元素。我们会在下面的三个章节中看到什么定义了不同的元素和看到窗体使用它们的例子。

QStyle类描述包含一个这些元素和它们的角色在样式窗体中的列表。我们会看到当我们定义单独窗体样式的时候它们是如何被使用的。

A Style element is a graphical part of a GUI. A widget consists of a hierarchy (or tree) of style elements. For instance, when a style receives a request to draw a push button (from QPushButton, for example), it draws a label (text and icon), a button bevel, and a focus frame. The button bevel, in turn, consists of a frame around the bevel and two other elements, which we will look at later. Below is a conceptual illustration of the push button element tree. We will see the actual tree for QPushButton when we go through the individual widgets.

Widgets are not necessary drawn by asking the style to draw only one element. Widgets can make several calls to the style to draw different elements. An example is QTabWidget, which draws its tabs and frame individually.

There are three element types: primitive elements, control elements, and complex control elements. The elements are defined by the ComplexControl, ControlElement, and PrimitiveElement enums. The values of each element enum has a prefix to identify their type: CC_ for complex elements, CE_ for control elements, and PE_ for primitive elements. We will in the following three sections see what defines the different elements and see examples of widgets that use them.

The QStyle class description contains a list of these elements and their roles in styling widgets. We will see how they are used when we style individual widgets.

基本元素 (Primitive Elements)

基本元素是普通的GUI元素经常被一些窗体使用。这些元素的例子是被spin boxes,scroll bars,combo boxes使用的边框,按钮斜角和箭头。基本元素不能独立存在,他们经常作为一个大结构的部分而存在。他们不与用户进行交互,只是被动的装饰GUI。

Primitive elements are GUI elements that are common and often used by several widgets. Example of these are frames, button bevels, and arrows for spin boxes, scroll bars, and combo boxes. Primitive elements cannot exist on their own: they are always part of a larger construct. They take no part in the interaction with the user, but are passive decorations in the GUI.

控件元素 (Control Elements)

一个控件元素执行一个动作或者向用户展示信息。例子关于控件元素是push buttons, check boxes 和表和数视图的头部分。控件元素不必要如按钮一般的完整的窗体,也可以是诸如标签条标签和滚动条滑块之类的部分窗体。他们与基本元素不同是他们并不是被动的,而是在于用户的交互过程中满足了一个功能。由一些元素组成的控件经常使用这个样式来计算元素的矩阵边界。子元素的可用性由枚举SubElement定义。这个枚举只用来计算矩阵边界;子元素不是图形元素,如同基本、控件和复杂控件一般被绘制。

A control element performs an action or displays information to the user. Examples of control elements are push buttons, check boxes and header sections in tables and tree views. Control elements are not necessarily complete widgets such as push buttons, but can also be widget parts such as tab bar tabs and scroll bar sliders. They differ from primitive elements in that they are not passive, but fill a function in the interaction with the user. Controls that consist of several elements often use the style to calculate the bounding rectangles of the elements. The available sub elements are defined by the SubElement enum. This enum is only used for calculating bounding rectangles; sub elements are not graphical elements to be drawn like primitive, control, and complex elements.

复杂控件元素(Complex Control Elements)

复杂控件元素包含子控件。复杂控件表现出不同行为依赖于用户在何处使用鼠标处理他们和那些键盘按键被按下。这依赖于哪一个子控件(假如有的话)鼠标在上面或者按下。关于复杂控件的例子是scroll bars和combo boxes。在滚动条里面,你可以使用鼠标来移动滑条以及按下上下滚动按钮。可用的子控件被SubControl枚举定义。

除了绘制以外,样式需要提供给窗口关于子控件的信息当鼠标点击发生情况下。举个例子,一个QScrollBar需要知道用户是否按下了滑条,滑条槽或者上下滚动按钮。

注意到子控件与上面描述的控件元素不太一样。你不能使用样式来绘制一个子控件;样式只会计算子控件应该被绘制区域的边界矩阵。尽管这是正常的,复杂元素使用控件和基本元素来绘制他们的子控件,这是一个QT内置样式和Java样式经常使用的方法。举个例子,Java样式使用PE_IndicatorCheckBox来绘制check box在group boxes中(这是CC_GroupBox的子控件)。一些子控件有等价的控件元素,举个例子,滚动条滑条(SC_SCrollBarSlider 和 CE_ScrollBarSlider)。

Complex control elements contain sub controls. Complex controls behave differently depending on where the user handles them with the mouse and which keyboard are pressed. This is dependent on which sub control (if any) the mouse is over or pressed on. Examples of complex controls are scroll bars and combo boxes. With a scroll bar, you can use the mouse to move the slider and press the line up and line down buttons. The available sub controls are defined by the SubControl enum.

In addition to drawing, the style needs to provide the widgets with information on which sub control (if any) a mouse press was made on. For instance, a QScrollBar needs to know if the user pressed the slider, the slider groove, or one of the buttons.

Note that sub controls are not the same as the control elements described in the previous section. You cannot use the style to draw a sub control; the style will only calculate the bounding rectangle in which the sub control should be drawn. It is common, though, that complex elements use control and primitive elements to draw their sub controls. which is an approach that is frequently used by the built-in styles in Qt and also the Java style. For instance, the Java style uses PE_IndicatorCheckBox to draw the check box in group boxes (which is a sub control of CC_GroupBox). Some sub controls have an equivalent control element, e.g., the scroll bar slider (SC_SCrollBarSlider and CE_ScrollBarSlider).

其他的QStyle任务 (Other QStyle Tasks)

样式元素和窗体,正如上面提到的,使用样式来计算子元素和子控件的边界矩阵。像素基准,是一个屏幕像素中样式独立的大小,在绘制时被用来测量。可用的矩阵和像素基准在QStyle中用三个枚举来表现:SubElement, SubControl和PixelMetric。这些枚举的值可以通过SE_,SC_和PM_来轻松的定义。

一个样式经常有一些列标准图形(如同警告,问题和错误图像)对于信息框,文件对划框等。QStyle提供了StandardPixmap枚举。它的值代表标准图形。Qt的窗口使用这些,所以当你实现一个自定义样式你应该提供被这个样式使用的图形。

样式计算布局中窗体之间的空间。有两种方法在样式中可以处理这些计算。你可以设置PM_LayoutHorizontalSpacing 和PM_LayoutVerticalSpacing枚举,这是Java style使用的方法(通过QCommonStyle)。另外,你可以实现QStyle::layoutSpacing()方法和QStyle::layoutSpacingImplementation()方法假如你需要更多的空间在布局的某个位置。在这些函数中你可以计算基于控件类型的空间分布(QSizePolicy::ControlType)对于不同的尺寸政策(QSizePolicy::Policy)。

The style elements and widgets, as metioned, use the style to calculate bounding rectangles of sub elements and sub controls. Pixel metrics, which are style-dependent sizes in screen pixels, are also used for measurements when drawing. The available rectangles and pixel metrics are represented by three enums in QStyle::SubElement, SubControl, and PixelMetric. Values of the enums can easily by identified as they start with SE_, SC_ and PM_.

The style also contains a set of style hints, which is represented as values in the StyleHint enum. All widgets do not have the same functionality and look in the different styles. For instance, when the menu items in a menu do not fit in a single column on the screen, some styles support scrolling while others draw more than one column to fit all items.

A style usually has a set of standard images (such as a warning, a question, and an error image) for message boxes, file dialogs, etc. QStyle provides the StandardPixmap enum. Its values represent the standard image. Qt's widgets use these, so when you implement a custom style you should supply the images used by the style that is being implemented.

The style calculates the spacing between widgets in layouts. There are two ways the style can handle these calculations. You can set the PM_LayoutHorizontalSpacing and PM_LayoutVerticalSpacing, which is the way the Java style does it (through QCommonStyle). Alternatively, you can implement QStyle::layoutSpacing() and QStyle::layoutSpacingImplementation() if you need more control over this part of the layout. In these functions you can calculate the spacing based on control types (QSizePolicy::ControlType) for different size policies (QSizePolicy::Policy) and also the style option for the widget in question.

样式选项(Style Options)

QStyleOption的子类包含了所有必要的信息来样式单独的元素。样式选项被初始化,经常在栈上,被填写通过调用QStyle的函数。依赖于什么被绘制样式会期望不同的样式选项类。举个例子,QStyle::PE_FrameFocusRect元素期望一个QStyleOptionFocusRect类型的参数,有可能创建一个可以被自定义样式使用的自定义子类。由于性能原因,样式选项保持公共变量。

窗体可以保持在一系列不同的状态,这通过State枚举进行定义。根据窗体的不同,一些状态标志有不同的意义,但是其他状态标志对所有窗体来说是一样的,比如State_Disabled。QStyleOption::initFrom()为QStyleOption设置共同的状态;剩余部分的状态通过单独的窗体实现。

最重要的是,样式选项包含调色板和将被绘制的窗体边界矩阵。许多窗体包含特殊的样式选项。QPushButton 和 QCheckBox,举个例子,使用QStyleOptionButton作为他们的样式选项,这包含了文本,图标和图标大小。当我们浏览单独窗体的时候,所有选项的明确内容被描述。

当实现包含QStyleOption参数的QStyle函数时,你经常需要将QStyleOption转换到子类(举个例子,QStyleOptionFocusRect)。为了安全性,你可以使用qstyleoption_cast()来确保指针类型是正确的。假如对象不是正确的类型,qstyleoption_cast()返回 0, 举个例子:

const QStyleOptionFocusRect *focusRectOption =

    qstyleoption_cast<const QStyleOptionFocusRect *>(option);

if(focusRectOption)

{

    ...

}

The following code snippet illustrates how to use QStyle to draw the focus rectangle from a custom widget's painEvent():

void MyWidget::paintEvent(QPaintEvent *event)

{

    QPainter painter(this);

    ...

    QStyleOptionFocusRect option(1);

    option.init(this);

    option.backgroundColor = palette().color(QPalette::Window);

    style().drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);

}

The next example shows how to derive from an existing style to customize the look of a graphical element:

QStyle函数 (QStyle Functions)

QStyle 类定义了三个函数来绘制基本元素,控件元素和复杂元素:分别是drawPrimitive(), drawControl()和drawComplexControl()。这些函数接收如下参数。

将要绘制元素的枚举值。

QStyleOption报了了将要绘制元素的信息。

QPainter用来绘制该元素。

指向QWidget的指针,一般情况下是该元素将要在骑上绘制的那个窗体。

不是所有窗体发送一个指针给他们自己。加入样式选项发送给函数的信息并不包含你所要的信息,你应该检查窗体实现来看看他是否给自己发送了一个指针。

QStyle类也提供了帮助函数当绘制元素的时候。drawItemText()函数绘制文本在一个指定的矩阵之内,接收一个QPalette作为一个参数。drawItemPixmap()函数帮助来对齐一个位图在一个指定的边界矩阵之中。

其他的QStyle函数做各种各样的计算为了那些绘制函数。窗体也使用这些函数来计算大小提示和边界矩阵,假如他们自己绘制一些样式元素。跟绘制元素的函数一样,帮助函数一般接收相同的参数。

subElementRect()函数接收一个SubElement枚举值并为一个子元素计算边界矩阵。样式使用这个函数来指导哪里来绘制一个元素的不同部分。 这主要用来做复用;假如你创建了一个新样式,你可以使用相同想通过位置的子元素正如他们的父类一样。

subControlRect()函数用来为复杂控件的子控件计算边界矩阵。当你实现了一个新样式,你重新实现subControlRect()函数计算与父类不同的矩阵。

pixelMetric()函数返回一个像素基准,这以屏幕像素的方式给出了与样式独立的大小。他接收一个PixelMetric枚举值返回正确的观测值。注意到像素基准并不必要是静态观测,但是可以被计算,举个例子,使用样式选项。

hitTestComplexControl()函数返回复杂控件中鼠标指针在上面的子控件。一般情况下,这仅仅是使用subControlRect()函数返回子控件的边界矩阵,然后看看那一个矩阵包含了鼠标的位置。

QStyle也有polish()和unpolish()函数。所有的窗体都发送给polish()函数在他们将要显示之前,在他们将要隐藏之前发送给unpolish()函数。你可以使用这些函数来设置窗体之上的属性或者做其他你的样式所要求的工作。举个例子,假如当鼠标滑过窗体的时候你想要知道,你需要设置窗体的WA_Hover属性。然后State_MouseOver状态标志会被设置到窗体的样式选项中。

QStyle中有一些静态帮助函数来做一些共同的和男的工作。他们可以计算华东条的位置根据滑动条的值和转移矩阵,然后根据反向布局绘制文本;查看QStyle类文档来获取更多信息。

一般的方法来实现QStyle虚函数是在元素上做与父类不一样的工作;对所有其他元素,你可以仅仅使用父类的实现。

The QStyle class defines three functions for drawing the primitive, control, and complex elements: drawPrimitive(), drawControl(), and drawComplexControl(). The functions takes the following parameters:

the enum value of the element to draw.

a QStyleOption which contains the information needed to draw the element.

a QPainter with which to draw the element.

a pointer to a QWidget, typically the widget that the element is painted on.

Note all widgets send a pointer to themselves. If the style option sent to the function does not contain the information you need, you should check the widget implementation to see if it sends a pointer to itself.

The QStyle class also provides helper functions that used when drawing the elements. The drawItemText() function draws text within a specified rectangle, taking a QPalette as a parameter. The drawItemPixmap() function helps to align a pixmap within a specified bounding rectangle.

 Other QStyle functions do various calculations for the functions that do drawing. The widgets also use these functions for calculating size hints and bounding rectangles if they draw several style elements themselves. As with the functions that draw elements, the helper functions typically take the same arguments.

The subElementRect() function takes a SubElement enum value and calculates a bounding rectangle for a sub element. The style uses this function to know where to draw the different parts of an element. This is mainly done for reuse; if you create a new style, you can use the same location of sub elements as the super class.

The subControlRect() function is used to calculate bounding rectangles for sub controls in complex controls. When you  implement a new style, you reimplement subControlRect() and calculate the rectangles that are different from the super class.

The pixelMetric() function returns a pixel metric, which is a style-dependent size given in screen pixels. It takes a value of the PixelMetric enum and returns the correct measurement. Note that pixel metrics do not necessarily have to be static measurements, but can be calculated with, for example, the style option.

The hitTestComplexControl() function returns the sub control that the mouse pointer is over in a complex control. Usually, this is simply a matter of using subControlRect() to get the bounding rectangles of the sub controls, and then seeing which rectangle contains the position of the cursor.

QStyle also has the functions polish() and unpolish(). All widgets are sent to the polish() function before being shown and to unpolish() when they are hidden. You can use these functions to set attributes on the widgets or do other work that is required  by your style. For instance, if you need to know when the mouse is hovering over the widget, you need to set the WA_Hover widget attribute. The State_MouseOver state flag will then be set in the widget's style options.

QStyle has a few static helper functions that do some common and difficult tasks. They can calculate the position of a slider handle from the value of the slider and transform rectangles and draw text considerting reverse layouts; see the QStyle class documentation for more details.

The usual approach when one reimplements QStyle virtual functions is to do work on elements that are different from the super class; for all other elements, you can simply use the super class implementation.

调色板 (The Palette)

每一个样式提供一种颜色 - 就是,QBrush - 调色板应该被用来绘制窗体。有一组颜色为了不同的窗体状态(QPalette::ColorGroup): 激活(窗体在窗口中有键盘聚焦), 不激活(窗体用于其他窗口),和禁用(窗体被禁用)。 状态可以被找到通过查询State_Active和State_Enabled状态标志。每一个集合包含特定的颜色角色有QPalette::ColorRole枚举指定。角色描述了在那种情况下颜色应该被使用(举个例子,绘制窗体背景,文本,或者按钮)。

颜色角色如何被使用取决于样式。举个例子,加入样式使用渐变,可以使用调色板颜色使他更深或者更浅使用QColor::draker()和QColor::lighter()来创建梯度。一般来说,加入你需要一个刷子并不由调色板提供,你应该尝试获取一个。

QPalette应该提供调色板,存储颜色为不同的窗体状态和颜色角色。样式的调色板通过standardPalette()函数返回。标准的调色板并不是自动安装的当一个新的样式被设置进应用程序(QApplication::setStyle())或者窗体(QWidget::setStyle())之中,所以你必须自行设置调色板(QApplication::setPalette() 或者 QWidget::setPalette())。

并不推荐硬编码颜色,正如应用程序和单独窗体可以设置他们自己的调色板和也是用他们样式的调色板来绘制。注意到没有一个Qt的窗体可以设置他们自己的调色板。Java样式确实硬编码了一些颜色,但是只作为作者的决策;并不建议这样做。当然,并不是在所有调色板下样式都是好看的。

Each style provides a color - that is, QBrush - palette that should be used for drawing the widgets. There is one set of colors for the different widget states (QPalette::ColorGroup): active (widgets in the window that have keyboard focus), inactive (widgets used for other windows), and disabled (widgets that are diabled). The states can be found by querying the State_Active and State_Enabled state flags. Each set contains certai color roles given by the QPalette::ColorRole enum. The roles describe in which situations the colors should be used (e.g., for painting widget backgrounds, text, or buttons).

How the color roles are used is up to the style. For instance if the style uses gradients, one can use a palette color and make it darker or lighter with QColor::draker() and QColor::lighter() to create the gradient. In general, if you need a brush that is not provided by the palette, you should try to derive it from one.

QPalette, which provides the palette, stroes colors for different widgets states and color roles. The palette for a style is returned by standardPalette(). The standard palette is not installed automatically when a new style is set on the application (QApplication::setStyle()) or widget (QWidget::setStyle()), so you must set the palette yourself with (QApplication::setPalette()) or (QWidget::setPalette()).

It is not recommended to hard-core colors, as applications and individual widgets can set their own palette and also use their style's palette for drawing. Note that none of Qt's widgets set their own palette. The Java style does hard-code some colors, but only as a decision of the author; it is not advised. Of course, it is not intended that the style should look good with any palette.

实现问题 (Implementation Issues)

当你实现样式的时候,需要考虑一些问题。我们会给出一些提示和建议关于实现。

当实现样式的时候,必要来看看窗体的代码和基类的代码和他的祖先。这是因为窗体使用不同的样式,因为实现不同样式的虚函数可以影响到绘制的状态(举个例子,通过选择QPainter的状态而不保存它,绘制一些元素不是用合适的像素基准和子元素)。

推荐这个样式并不合适的窗体大小使用QStyle::sizeFromContents()函数,而是让QCommonStyle实现句柄来代替。假如需要进行改变,你可以尝试这让他们很小;应用程序开发可能会困难假如窗体的布局看起来在各种样式下困难。

When you implement styles, there are several issues to consider. We will give some hints and advice on implementation here.

When implementing styles, it is necessary to look through the code of the widgets and code of the base class and its ancestors. This is because the widgets use the style differently, because the implementation in the different styles' virtual functions can affect the state of the drawing (e.g., by altering the QPainter state without restoring it and drawing some elements without using the appropriate pixel metrics and sub elements).

It is recommended that the styles do not alter the proposed size of widgets with the QStyle::sizeFromContents() function, but let the QCommonStyle implementation handle it instead. If changes need to be made, you should try to keep them small; application development may be difficult if the layout of widgets looks considerably different in the various styles.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值