Qt 使用自己的方式绘制组件。然而我们也看到,在不同的平台上,Qt 的组件表现也不相同。这和 Swing 有些类似:Swing 使用 look and feel 表现组件的外观,Qt 也是类似的。用来绘制组件外观的类就是 QStyle。多数情况是没有必要实现的!
style实现外观。这里通常有两种实现方式:
第一,重写 widget 的 paintEvent() 函数;
第二,使用 QStyle 类。两种方式的侧重点不同:重写组件的 paintEvent() 函数,可以简单地实现某一类组件的样式,而继承 QStyle 类,则可以实现对全部组件一致性处理。
第一种实现 paintEvent()
void mystyleButton::paintEvent(QPaintEvent *event)
{
QStyleOptionButton option;
option.initFrom(this);
option.state = isDown() ? QStyle::State_Sunken : QStyle::State_Raised;
if (1)
option.features |= QStyleOptionButton::AutoDefaultButton;
option.text = text();
option.icon = icon();
QPainter painter(this);
//参数一用于指定要绘制哪个元素 ,
//保存了 painter 绘制时所需要的所有数据信息
//画家,对象
style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
}
第二种,QStyle 的实现。
其实在上面,我们已经使用了 QStyle。想必也能够想到,
这里我们依旧要用到 QStyle 的各个 draw 函数,只不过这里我们不是简单的去调用它们,
而是通过继承,将这些 draw 函数替换成我们自己的版本,达到自定义样式的目的。
虽然我们可以直接继承 QStyle 来实现,但是这并不是一个好主意。因为 QStyle 这个类很复杂,
几乎所有的函数都是纯虚函数,这要求我们必须一个个实现它们。有时候,我们并不需要自己实现所有功能,
仅仅是做简单的修改。于是,从 4.6 版本开始,Qt 提供了一个专门的类,
QProxyStyle。我们要做的就是继承 QProxyStyle,覆盖我们感兴趣的函数即可。看下面一个简单的实例:
class MyProxyStyle : public QProxyStyle
{
public:
void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const;
};
void MyProxyStyle::drawControl(
ControlElement element,
const QStyleOption *option,
QPainter *painter,
const QWidget *widget
) const
{
if(element == QStyle::CE_PushButtonLabel) {
painter->drawText(option->rect, "button");
} else {
QProxyStyle::drawControl(element, option, painter, widget);
}
}
MyProxyStyle 覆盖了 drawControl() 函数,然后判断,如果是 button label 的话,绘制文本 “button”。
QPushButton::setText() 函数已经没有作用了,因为我们在绘制时没有使用这个属性,也就不会显示出来了。不管你设不设置,所有 button 的 text 都会是button。如果要使用这个 style ,需要在运行前设置,例如:
int main(int argc, char **argv)
{
QApplication app(argc, argv);
app.setStyle(new MyProxyStyle);
MainWindow w;
w.show();
return app.exec();
}
这样,我们就可以用我们自己的 style 显示组件了。
通过学习这个可以窥探到自定义控件的方法实现细节!