Board logo

标题: 用QT创建新风格Howto(2) [打印本页]

作者: look_w    时间: 2018-5-7 18:43     标题: 用QT创建新风格Howto(2)

2.创建新风格下面用一个例子来介绍一下创建新风格的整个过程,在编程之前,先看一下最终的结果是什么样的。(在Qt内部QSpinBox类是通过QSpinWidget实现的)

默认风格的效果:            使用新风格的效果:            可以看到在新风格中我们的SpinBox有了垂直显示的效果。下面我们按上面说明的步骤来创建一种新的风格。
1)选择基类:我们选择QWindowsStyle类作为我们新风格类的基类,当然也可以选择QMotifStyle,在这个例子种也可以选择QCommonStyle。一般不建议选择QCommonStyle作为基类,因为QCommonStyle只实现了一部分界面部件,如果要实现一个完整的风格类,我们需要重新写很多代码。
2)重载相关的函数:在这个例程中我们只修改了spinBox的风格,实现这个部件(widget)只与QStyle类的三个函数drawPrimitive, drawComplexControl, qureySubControlMerics相关,所以我们只需重载这三个函数的相关部分代码.下面对代码中的关键部分做一下注释,不重要的部分省略了。详细的代码可以从后面下载。
绘制spinbox中按钮的函数:
void CustomStyle::drawPrimitive( PrimitiveElement pe,                                QPainter * p,                            const QRect & r,                            const QColorGroup & cg,                            SFlags flags,                            const QStyleOption & opt ) const{/*PE_SpinWidgetUp,PE_SpinWidgetDown表示spinBox中的下按钮和上按钮,下面的代码使得这两个按钮中的三角形分别向左和向右*/if ((pe == PE_SpinWidgetUp) || (pe == PE_SpinWidgetDown)){                int fw = pixelMetric( PM_DefaultFrameWidth, 0 );//fw表示边框宽度,默认为2                QRect br;  //spinBox上按钮的边界矩形不是spinBox的边界矩形。                br.setRect( r.x() + fw, r.y() + fw, r.width() - fw*2,                    r.height() - fw*2 );                p->fillRect( br, cg.brush( QColorGroup::Button ) );                int x = r.x(), y = r.y(), w = r.width(), h = r.height();                int sw = w-4;                int sh = sw/2 + 2;      // Must have empty row at foot of arrow                int sx = x + w / 2 - sw / 2 - 1;                int sy = y + h / 2 - sh / 2 - 1;                QPointArray a;/* 设置三角形的三个点的坐标,修改这三个点可以使得QSpinBox上按钮里的三角型呈现任意的形状,下面的设置使得三角形表示的箭头分别向左和向右。*/                if ( pe == PE_SpinWidgetDown )                    a.setPoints( 3,  0, sh/2,  sw-1, 1,  sw-1, sh-1 );          else                    a.setPoints( 3,  0, 1,  0, sh-1,  sw-1, sh/2 );                ...........                p->drawPolygon( a );    //绘制三角形}else if((pe == PE_ButtonBevel) || (pe == PE_ButtonCommand) || (pe == PE_ButtonTool) || (pe == PE_ButtonDropDown) || (pe == PE_HeaderSection))    { //绘制按钮的各种效果使得看起来凸起或凹下。            qDrawShadePanel(p, r, cg, flags & (Style_Sunken | Style_Down | Style_On),                 1, &cg.brush(QColorGroup::Button));    }else{ /*对于其他基本图形元素(PrimitiveElement)的绘制我们不作处理只是简单的调用父类的函数。*/                QWindowsStyle::drawPrimitive( pe, p, r, cg, flags, opt);    }}绘制整个spinBox的函数:
void CustomStyle::drawComplexControl( ComplexControl control,                                       QPainter *p,                                       const QWidget *widget,                                       const QRect &r,                                       const QColorGroup &cg,                                       SFlags flags,                                       SCFlags controls,                                       SCFlags active,                                       const QStyleOption& opt ) const{    //下面的代码使得spinWidget呈现垂直显示的风格而不是通常的水平显示if (control == CC_SpinWidget) {                const QSpinWidget * sw = (const QSpinWidget *) widget;                //绘制向上按钮部分,controls默认为SC_All,即绘制整个spinwidget                if ( controls & SC_SpinWidgetUp ) {                                            if ( sw->buttonSymbols() == QSpinWidget:lusMinus )                                pe = PE_SpinWidgetPlus;  // 使用加减号                    else                                pe = PE_SpinWidgetUp;   // 使用三角形        QRect re = sw->upRect();        QColorGroup ucg = sw->isUpEnabled() ? cg : sw->palette().disabled();        drawPrimitive(PE_ButtonBevel, p, re, ucg, flags); //绘制按钮的边框      drawPrimitive(pe, p, re, ucg, flags);       //绘制按钮    }    //绘制向左按钮部分。    if ( controls & SC_SpinWidgetDown ) {      /*与绘制向下按钮相似*/    }}else{//不处理spinbox之外的其他复杂控制部件,调用父类函数处理QWindowsStyle::drawComplexControl(control, p, widget, r, cg, flags, controls, active, opt);    }}获取部件(widget)中各个子部件布局信息的函数,这个函数控制着一个widget的外观
QRect CustomStyle::querySubControlMetrics( ComplexControl control,                                            const QWidget *widget,                                            SubControl sc,                                            const QStyleOption &opt ) const{    if(control == CC_SpinWidget){            int fw = pixelMetric( PM_SpinBoxFrameWidth, widget);/*QSize 定义二维对象的大小,也就是宽和高. 坐标类型是QCOORD定义为int)*/                QSize bs;  //此处bs表示每个按钮的大小,因为有两个按钮所以下面除以2.                bs.setWidth(widget->width()/2 -fw);                if(bs.width() < 8) bs.setWidth(8);                /*按钮高度设置为QMIN{按钮宽度的1.6倍, 部件高度的四分之一}                bs.setHeight(  QMIN(bs.width()*8/5, widget->height() / 4) );                 bs = bs.expandedTo( QApplication::globalStrut() );                                int x = fw;                int y, ly, ry;                y = widget->height() - x - bs.height();                ly = fw;                ry = y - fw;        //下面定义了QSpinWidget的各个子部件的坐标位置.        switch ( sc ) {        case SC_SpinWidgetUp:                //返回向右按钮的坐标信息            return QRect(x + bs.width(), y, bs.width(), bs.height());        case SC_SpinWidgetDown:                //返回向左按钮的坐标信息            return QRect(x, y, bs.width(), bs.height());        case SC_SpinWidgetButtonField:                //返回两个按钮的总区域大小            return QRect(x, y, widget->width() - 2*fw, bs.height());        case SC_SpinWidgetEditField:/*返回可编辑框的坐标信息*/            return QRect(fw, ly, widget->width() - 2*fw, ry);        case SC_SpinWidgetFrame:                //返回整个spinBox的坐标信息            return widget->rect();        default:            break;        }    }else{//其它部件的布局信息调用父类的函数来处理。                return QWindowsStyle::querySubControlMetrics(control,widget,sc,opt );    }    return QRect();}




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0