1. 程式人生 > >Qt 原始碼剖析 之 控制元件繪製

Qt 原始碼剖析 之 控制元件繪製

Qt 原始碼剖析 之 控制元件繪製

這裡使用QPushButton為例,講解一下具體QPushButton是怎麼繪製的

首先看一段程式碼,這段程式碼是QPushButton中的繪製事件函式,可以看出來是使用QStylePainter來繪製,
QStylePainter包裝了所有高階控制元件的繪製, QStyleOptionButton是按鈕的樣式引數的分裝類,所有有關按鈕的繪製樣式在QStyleOptionButton都可找到。
initStyleOption初始化引數

void QPushButton::paintEvent(QPaintEvent *)
{
	QStylePainter p(this);
	QStyleOptionButton option;
	initStyleOption(&option);
	p.drawControl(QStyle::CE_PushButton, option);
}

void QPushButton::initStyleOption(QStyleOptionButton *option) const
{
if (!option)
    return;

Q_D(const QPushButton);
option->initFrom(this);
option->features = QStyleOptionButton::None;
if (d->flat)
    option->features |= QStyleOptionButton::Flat;
#ifndef QT_NO_MENU
if (d->menu)
	option->features |= QStyleOptionButton::HasMenu;
#endif
if (autoDefault())
    option->features |= QStyleOptionButton::AutoDefaultButton;
if (d->defaultButton)
    option->features |= QStyleOptionButton::DefaultButton;
if (d->down || d->menuOpen)
    option->state |= QStyle::State_Sunken;
if (d->checked)
    option->state |= QStyle::State_On;
if (!d->flat && !d->down)
    option->state |= QStyle::State_Raised;
option->text = d->text;
option->icon = d->icon;
option->iconSize = iconSize();
}

下面看一下QStylePainter 是怎麼繪製的

void QStylePainter::drawControl(QStyle::ControlElement ce, const QStyleOption &opt)
{
	wstyle->drawControl(ce, &opt, this, widget);
}

wstyle 是QStyle的一個子類,Qt預設使用QCommonStyle,想修改Qt的樣式可以繼承QCommonStyle,
重寫裡面的一些虛擬函式就可以

看一下具體QCommonStyle是怎麼繪製控制元件的

void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
   QPainter *p, const QWidget *widget) const
{
Q_D(const QCommonStyle);
switch (element) {
    case CE_PushButton:
    if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) {
    	proxy()->drawControl(CE_PushButtonBevel, btn, p, widget);
    	QStyleOptionButton subopt = *btn;
    	subopt.rect = subElementRect(SE_PushButtonContents, btn, widget);
    	proxy()->drawControl(CE_PushButtonLabel, &subopt, p, widget);
    	if (btn->state & State_HasFocus) {
    		QStyleOptionFocusRect fropt;
    		fropt.QStyleOption::operator=(*btn);
    		fropt.rect = subElementRect(SE_PushButtonFocusRect, btn, widget);
    		proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
    	}
	}
	break;
	case CE_PushButtonBevel:

這裡給一個例子,修改Qt的預設空間繪製方式的一個例子

  #include "textedit.h"
  #include <QApplication>
  #include <QProxyStyle>

  class MyProxyStyle : public QProxyStyle
  {
	public:
  		int styleHint(StyleHint hint, const QStyleOption *option = 0,
			const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const
	      {
	      	if (hint == QStyle::SH_UnderlineShortcut)
	      		return 0;
	      	return QProxyStyle::styleHint(hint, option, widget, returnData);
	      }
  };

  int main(int argc, char **argv)
  {
      Q_INIT_RESOURCE(textedit);
    
      QApplication a(argc, argv);
      a.setStyle(new MyProxyStyle);
      TextEdit mw;
      mw.resize(700, 800);
      mw.show();
      //...
  }