核心就是自定义一个派生自QWindowStyple类,重载drawScrollBarControls方法
最后在自己的QApplication中应用这个style
自定义style中绘制滚动条的过程
类继承关系:MetalStyle: QWindowsStyle:QStyle
void MetalStyle::drawScrollBarControls( QPainter* p, const QScrollBar* sb, int sliderStart,
uint controls, uint activeControl )
{
// 先用父类的方法绘制除了AddLine|SubLine|Slider之外的控件
// 对于垂直滚动条,就是:向下箭头|向上箭头|滑块
QWindowsStyle::drawScrollBarControls(p,sb,sliderStart,controls&~(AddLine|SubLine|Slider), activeControl & ~(AddLine|SubLine|Slider) );
bool horz = sb->orientation() == QScrollBar::Horizontal;
// b表示间隙,向下箭头|向上箭头的宽度比滚动条的宽度小2*b
int b = 2;
int w = horz ? sb->height() : sb->width();
QColorGroup g = sb->colorGroup();
int sliderMin, sliderMax, sliderLength, buttonDim;
// 下面代码获取的尺寸中最重要的是sliderLength,即滑块高度
// buttonDim表示向下箭头|向上箭头的高度,默认为滚动条的宽度
// 如果垂直滚动条的高度太小,buttonDim就为其高度的一半
scrollBarMetrics( sb, sliderMin, sliderMax, sliderLength, buttonDim );
if (sliderStart > sliderMax)
{ // sanity check
sliderStart = sliderMax;
}
bool maxedOut = (sb->maxValue() == sb->minValue());
// 绘制向下的箭头
if ( controls & AddLine )
{
bool sunken = activeControl & AddLine;
// 确定箭头所在的矩形区域
QRect r( b, b, w-2*b, w-2*b ) ;
if ( horz )
r.moveBy( sb->width() - w, 0 );
else
r.moveBy( 0, sb->height() - w );
drawMetalButton( p, r.x(), r.y(), r.width(), r.height(),sunken, !horz );
drawArrow( p, horz ? RightArrow : DownArrow, sunken,
r.x(), r.y(), r.width(), r.height(), g, !maxedOut );
}
// 绘制向上的箭头
if ( controls & SubLine )
{
bool sunken = activeControl & SubLine;
// 确定箭头所在的矩形区域
QRect r( b, b, w-2*b, w-2*b ) ;
drawMetalButton( p, r.x(), r.y(), r.width(), r.height(),sunken, !horz );
drawArrow( p, horz ? LeftArrow : UpArrow, sunken,
r.x(), r.y(), r.width(), r.height(), g, !maxedOut );
}
// 确定滑块所在的矩形区域
QRect sliderR;
if ( horz )
{
sliderR .setRect( sliderStart, b, sliderLength, w-2*b );
}
else
{
sliderR .setRect( b, sliderStart, w-2*b, sliderLength );
}
if ( controls & Slider )
{
// 绘制滑块,这里是套用绘制按钮的方式
if ( !maxedOut )
{
drawMetalButton( p, sliderR.x(), sliderR.y(), sliderR.width(), sliderR.height(),
FALSE, horz );
}
}
}
这个例子比较简单,省略了很多dd。比如:如果滚动条的高度不到滚动条宽度的两倍,那么向下箭头|向上箭头的尺寸就不能是(w-2*b, w-2*b),而应该是:(w-2*b, buttonDim).
如果要绘制的滑块比较复杂,比如分为三段,就要调整代码了,例如:
QPixmap blockTop = Resource::loadPixmap("arrow_top.png");
QPixmap blockBot = Resource::loadPixmap("arrow_bot.png");
QPixmap blockMid =Resource::loadPixmap("block_mid.png");
QPixmap blockEdge = Resource::loadPixmap("block_edge.png");
int sh = sliderR.height() - blockBot.height() - blockTop.height() - 1;
// 如果滑块高度 > 滑块头高度+滑块尾高度+滑块中间高度
if (sh > blockMid.height())
{
// 画滑块背景,blockEdge的高度只有1,所以要进行拉伸
p->drawTiledPixmap(sliderR.x(), sliderR.y()+blockBot.height(),
sliderR.width(), sh, blockBg );
// 画滑块中间部分
p->drawPixmap(sliderR.x(),sliderR.y() + blockBot.height() +
(sh - blockMid.height())/2, blockMid);
}
else //滑块高度不够,直接画背景
{
p->drawPixmap(sliderR.x(), sliderR.y() + blockBot.height(),blockMid, 0,
(blockMid.height() - sh) / 2, sliderR.width(), sh);
}
// 画头和尾,即滑块的最上/下部,一般为椭圆性过渡
p->drawPixmap(sliderR.x(), sliderR.y(), blockTop);
p->drawPixmap(sliderR.x(), sliderR.bottom() - blockBot.height(), blockBot);