现在的位置: 首页 > 综合 > 正文

QStyle类参考

2013年06月30日 ⁄ 综合 ⁄ 共 6039字 ⁄ 字号 评论关闭

                                                            QStyle类参考

QStyle类是一个封装了GUI外观感觉的抽象基类。
使用中:#include <QStyle>
继承自QObject。
被QCommonStyle继承。


详细描述
       QStyle类是封装了GUI外观感觉的抽象基类。
       Qt包含了一系列QStyle的子类,枚举了Qt支持不同平台的样式(例如:QWindowsStyle,QMacStyle,QMotifStyle等)。
默认情况下,这些样式都是内建在QtGui类中。Style也能够以插件的形式提供。
       Qt内建堵塞窗口部件使用QStyle来呈现几乎所有的绘制,确保它们看起来十分接近原生的窗口部件。下面的图用8种不同的样式展示了QComboBox。



主题
设置一个样式表
       整个应用的样式可以通过QApplication::setStyle()函数设置。它也可以被用户使用-style命令行参数指定:
./myapplication -style motif
如果没有指定样式,Qt会自动为用户平台或者是桌面环境选择最适合的样式。
我们也可以通过QWidget::setStyle()函数为单个窗口部件设置样式。
开发样式敏感的自定义窗口部件
       如果你开发了自定义窗口部件并且希望他们在所有的平台上都看起来十分美观,那么你可以使用QStyle函数来
展现部门窗口部件的绘制,例如:drawItem(),drawItemPixmap(),drawPrimitive(),drawControl()和drawComplexControl()。
      大部分的QStyle函数使用四个参数:
*一个枚举值,用来指定绘制哪一个图形元素;
*一个QStyleOption参数,指定如何、在哪里渲染该图形元素;
*一个QPainter,用来绘制该图形元素;
*一个QWidget,指定将在哪里绘制该图形元素(可选参数)。

      例如,如果你想在你的窗口部件上绘制一个聚焦的矩形,那什么你可以如下编写:

void MyWidget::paintEvent(QPaintEvent * /* event */)
 {
     QPainter painter(this);

     QStyleOptionFocusRect option;
     option.initFrom(this);
     option.backgroundColor = palette().color(QPalette::Background);

     style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);
 }

           QStyle从QStyleOption中获取渲染图形元素所需的所有信息。窗口部件作为最后一个参数传递,以防样式需要
它来实现特殊的效果(例如在Mac OS X上带有动画的按钮),但是这并非强制性的。实际上你可以使用QStyle在任意
的绘图设备上绘制,不仅仅是窗口部件,通过设置QPainter的属性即可。

       QStyleOption对不同的可绘制的图形元素有不同的子类。例如:PE_FrameFocusRect希望获取一个QStyleOptionFocusRect类型的参数。
为了确保绘制操作尽可能的快速,QStyleOption和它的子类有一些公有的数据元素。查阅QStyleOption类的文档来了解如何使用它们。
为了提供便利,Qt提供了QStylePainter类,该类结合了QStyle,QPainter和QWidget。因此可以如下编写代码:
QStylePainter painter(this);
...
painter.drawPrimitive(QStyle::PE_FrameFocusRect, option);
        来代替如下的代码:
QPainter painter(this);
...
style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter, this);


创建一个自定义的样式
    你可以通过创建自定义样式为自己的应用自定义外观感觉。这里有两种方法来创建一个自定义的样式。
*在静态方法中,你可以选择一个已经存在的QStyle类,继承它,实现虚函数来提供自定义的操作;你也可以选择从头    开始创建一个完整的QStyle类。
*在动态方法中,你可以在运行时修改系统样式的行为。
        静态方法将在下面介绍,动态方法将会在QProxyStyle中介绍。
静态方法的第一步就是选择一个Qt提供的样式来实现自定义样式。你选择QStyle类的主要依据就是哪一个样式最能满足
你期望的样式。最常使用的基类是QCommonStyle(而不是QStyle)。这是因为Qt要求它的样式是QCommonStyle。
       依赖于你想改变基类的哪一部分的样式,你必须实现那些用来绘制这部分的接口。为了表明这个操作,我们将会修改由QWindowsStyle绘制的spin box的箭头。箭头是原始的元素,通过drawPrimitive()函数绘制,因此我们需要实现这个函数。我们需要如下的类定义:

class CustomStyle : public QWindowsStyle
 {
     Q_OBJECT

 public:
     CustomStyle()
     ~CustomStyle() {}

     void drawPrimitive(PrimitiveElement element, const QStyleOption *option,
                        QPainter *painter, const QWidget *widget) const;
 };

        为了绘制向上和向下的箭头,QSpinBox使用PE_IndicatorSpinUp和PE_IndicatorSpinDown两个原始元素。下面打代码表明如何实现drawPrimitive()函数来分别的绘制它们。

void CustomStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
                                 QPainter *painter, const QWidget *widget) const
 {
     if (element == PE_IndicatorSpinUp || element == PE_IndicatorSpinDown) {
         QPolygon points(3);
         int x = option->rect.x();
         int y = option->rect.y();
         int w = option->rect.width() / 2;
         int h = option->rect.height() / 2;
         x += (option->rect.width() - w) / 2;
         y += (option->rect.height() - h) / 2;

         if (element == PE_IndicatorSpinUp) {
             points[0] = QPoint(x, y + h);
             points[1] = QPoint(x + w, y + h);
             points[2] = QPoint(x + w / 2, y);
         } else { // PE_SpinBoxDown
             points[0] = QPoint(x, y);
             points[1] = QPoint(x + w, y);
             points[2] = QPoint(x + w / 2, y + h);
         }

         if (option->state & State_Enabled) {
             painter->setPen(option->palette.mid().color());
             painter->setBrush(option->palette.buttonText());
         } else {
             painter->setPen(option->palette.buttonText().color());
             painter->setBrush(option->palette.mid());
         }
         painter->drawPolygon(points);
     } else {
         QWindowsStyle::drawPrimitive(element, option, painter, widget);
     }
 }

        注意你将不会使用到widget这个参数,除非你将它传递给QWindowsPrimitive()函数。正如先前提到的,绘制那一个图形以及如何绘制的信息是通过QStyleOption对象指定的,因此这里不需要询问widget。如果你需要使用widget参数来回去额外的信息,必须小心确保它不是0并且在使用之前确保它是正确的类型。例如:
QSpinBox *spinBox = qobject_cast<QSpinBox *>(widget);
if (spinBox) {
...
}
       当实现一个自定义样式时,你不能因为枚举参数的值是PE_IndicatorSpinUp或者PE_IndicatorSpinDown,就假设那个widget就是QSpinBox。
    QStyle示例的文档对这个话题有比较详细的介绍。


警告:Qt 样式表目前不支持自定义的QStyle子类。我们计划在以后的版本中将它们添加进来。


使用自定义的样式
       在Qt应用程序中有几种方式应用自定义的样式。最简单的方式就是在创建QApplication对象之前将自定义的样式传递给QApplication::setStyle()这个静态函数。
#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();
}
       你可以在任意时刻调用QApplication::setStyle()方法,但是必须在构造函数之前调用,你必须确保用户的偏好,
最好使用-style命令行参数。
       你可能希望你的自定义样式在其它的应用程序中也能够使用,该应用程序也许不是你的因此你不能够重新编译。
Qt的插件系统是的你可以将自定义样式制作为插件。样式制作为插件后就会在运行时作为共享对象被载入。对于如何制作样式插件详情请参阅和Qt Plugin有关的文档。
        编译你的插件并且将它们放在Qt的plugins/styles目录下。现在我们就拥有了一个插件式的样式,Qt可以自动载入它。
        对于已有的应用程序要想使用你自定义的样式,仅仅是使用如下参数来启动应用程序:
./myapplication -style custom
该应用程序就会使用你实现的自定义样式。


Right-to-Left Desktops
       从右向左写的语言(例如:Arabic和Hebrew)通常是将窗口部件的这个布局都镜像,并且要求光亮从屏幕的右上角发出而不是左上角。
       如果你创建自定义的样式,那么你在你绘制不对称的元素时必须十分小心确保在镜像布局中它们也是正确的。一个简单的方法测试你的样式是使用-reverse参数来启动你的应用程序,或者是在你的mian()函数中调用QApplication::setLayoutDirection()函数。
       为了使样式在right-to-left环境中也能正常工作,如下几点必须高度注意:
*subControlRect()和subElementRect()返回屏幕坐标的矩形;
*QStyleOption::direction表明元素绘制的方向;
*如果一个样式不是right-to-left敏感的,那么它将会以left-to-right的方式呈现元素;
*visualRect(,visualPos()和visualAlignment()对于将逻辑转化为屏幕表现是十分有用的函数;
*alignedRect()将会从当前方向返回一个逻辑矩形。


元素视图的样式
      视图中元素的绘制是通过代理实现的。Qt默认的代理,QStyleDelegate,也用于计算矩形元素的边框,以及它们的子元素用于不同元素的数据类型QStyleItemDelegate的支持。查看QStyleItemDelegate类来了解目前支持的数据类型和角色。你可以通过阅读Model/View Programming和获取更多关于元素数据类型和角色的信息。
      当QStyledItemDelegate绘制它的元素时,它绘制CE_ItemViewItem并且计算它们的CT_ViewItem尺寸。注意,它们使用SE_ItemViewItemText来设置编辑器的尺寸。当实现一个绘制元素视图的自定义样式时,你需要检查
QCommonStyle(以及任何从基类继承的子类)的实现。这种方式下,你知道哪一些其它的样式元素会被绘制以及它们
如何被绘制,因此你可以以不同的方式重新实现这些元素的绘制操作。

我们这里有一个小的示例来展示我们如何自定义绘制一个元素的背景:

switch (element) {
    case (PE_PanelItemViewItem): {
        painter->save();

        QPoint topLeft = option->rect.topLeft();
        QPoint bottomRight = option->rect.topRight();
        QLinearGradient backgroundGradient(topLeft, bottomRight);
        backgroundGradient.setColorAt(0.0, QColor(Qt::yellow).lighter(190));
        backgroundGradient.setColorAt(1.0, Qt::white);
        painter->fillRect(option->rect, QBrush(backgroundGradient));

        painter->restore();
    break;
    }
    default:
        QWindowsStyle::drawPrimitive(element, option, painter, widget);
}

       原始元素PE_PanelItemViewItem就是相应要绘制背景的元素,并且它是从QCommonStyle中的CE_ItemViewItem
的实现中被调用的。
       为了添加对绘制新数据类型和元素数据角色的支持,我们必须创建一个自定义的代理。但是,如果你仅仅需要
在默认代理中添加对新数据类型的支持,那么一个自定义的样式就不需要一个伴随的代理。QStyledItemDelegate类
对自定义代理做了更多的描述。
       元素视图的首部绘制同样由样式来完成,但是可以控制元素首部以及行列的尺寸。

抱歉!评论已关闭.