• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            逛奔的蝸牛

            我不聰明,但我會(huì)很努力

               ::  :: 新隨筆 ::  ::  :: 管理 ::
            轉(zhuǎn)貼: http://hi.baidu.com/yjj2008/blog/item/6cd4a1892ef0d4b60f2444a5.html
            本文介紹了如何使用qt提供的接口來設(shè)計(jì)自己的GUI風(fēng)格(look and feel),并通過一個(gè)具體的例子(使QSpinBox垂直顯示)來詳細(xì)說明過程。運(yùn)行環(huán)境:redhat 9.0,qt-x11-free-3

            1.Qt的風(fēng)格

            a) Qt簡(jiǎn)介 
            Qt是一個(gè)跨平臺(tái)的C++圖形用戶界面應(yīng)用程序開發(fā)庫,使用Qt可以開發(fā)出高質(zhì)量的圖形用戶接口,它是完全面向?qū)ο蟮?、易于擴(kuò)展且允許真正的組件編程。Qt獲得了很大的成功,特別是它的信號(hào)-槽機(jī)制是非常值得研究的通信機(jī)制,它也是Linux發(fā)行版標(biāo)準(zhǔn)組件KDE(K Desktop Enviroment)的基礎(chǔ)。

            b) 風(fēng)格機(jī)制 
            Qt的風(fēng)格機(jī)制實(shí)現(xiàn)了不同平臺(tái)上的圖形用戶接口(GUI)的觀感(look and feel),例如Windows平臺(tái)上通常使用Windows或Windows-xp風(fēng)格,而Unix平臺(tái)上通常使用Motif、CDE風(fēng)格。

            下圖顯示了Qt中與風(fēng)格相關(guān)的類的繼承關(guān)系


             

            QStyle是所有風(fēng)格類的基類,它控制著所有的部件(widget即windows編程中的控件)的界面風(fēng)格或觀感,它定義了大量的枚舉類型和十幾個(gè)函數(shù)。枚舉類型表示界面上的不同元素(如組合框中的按鈕,按鈕的邊框等);函數(shù)控制圖形用戶界面的繪制,但大多數(shù)函數(shù)基本上只是一些聲明而沒有函數(shù)實(shí)現(xiàn),他們的實(shí)現(xiàn)在QCommonStyle、QWindowStyle、QMotifStyle及其子類中。QStyle只實(shí)現(xiàn)了3個(gè)函數(shù)drawItem(), itemRect(), visualRect()。

            drawItem(): 負(fù)責(zé)繪制文本和象素圖。 
            itemRect(): 返回文本或圖像所占的區(qū)域。 
            visualRect(): 返回邏輯坐標(biāo),這個(gè)函數(shù)使Qt實(shí)現(xiàn)right-to-left風(fēng)格(阿文、維文傳統(tǒng)是文本從右向左顯示,因此控件布局也是從右向左)。如下圖所示:


             

            可以看到菜單、工具條是右對(duì)齊、單選框的按鈕在右邊

            c) 創(chuàng)建新風(fēng)格的步驟 
            在Qt中實(shí)現(xiàn)一種新風(fēng)格的步驟很簡(jiǎn)單:只需選擇一個(gè)風(fēng)格類(如QCommonStyle或QStyle)作為父類,然后實(shí)現(xiàn)感興趣的函數(shù)即可。難點(diǎn)在于函數(shù)的實(shí)現(xiàn)。

            選擇父類:可以選擇QStyle, QCommonStyle, QWindowStyle, QMotifStyle以及他們的子類的任意一個(gè)作為父類。通??梢赃x擇QWindowsStyle或QMotifStyle,也可以選擇QCommonStyle甚至是QStyle,但是工作量會(huì)比較大,因?yàn)楹芏嘟缑娴募?xì)節(jié)需要自己實(shí)現(xiàn)。

            重新實(shí)現(xiàn)必要的函數(shù):想修改界面風(fēng)格的哪部分,就重新實(shí)現(xiàn)與繪制那部分相關(guān)的函數(shù),下面解釋一下我們要重載的QStyle中的幾個(gè)函數(shù),這幾個(gè)函數(shù)控制著圖形用戶界面上不同元素的布局和觀感。

            1)void drawPrimitive( PrimitiveElement pe,
                                  QPainter *p,
                                    const QRect & r,
                                    const QColorGroup & cg,
                                    SFlags flags = Style_Default,
                                    const QStyleOption &opt = QStyleOption::Default ) ;

            功能:繪制基本圖形元素,如QSpinBox中的帶箭頭的按鈕 等。

            參數(shù): PrimitiveElement pe: 這個(gè)枚舉型變量表示將要繪制的基本圖形界面元素(這里說的基本圖形用戶界面元素指GUI中不可再分的一個(gè)原子元素,如組合框


             
            中的這個(gè)繪有黑色三角形的按鈕,spinBox中的按鈕 
             

            QPainter *p:指向QPainter類的指針,Qt中的所有繪制操作不管是繪制文本、圖形還是圖像都由這個(gè)類來處理。 
            QRect &r: 表示一個(gè)矩形區(qū)域,Qt在這個(gè)區(qū)域中繪制基本界面元素(PrimitiveElement). 
            QColorGroup &cg: QColorGroup表示一個(gè)部件(widget)的顏色組(color group),color group含有部件繪制自己時(shí)使用的各種顏色,譬如前景色背景色等。下圖展示了color group中的各種顏色屬性 
             

            SFlags flags: 控制如何繪制圖形界面元素的標(biāo)志。 
            QStyleOption &opt: 繪制不同的部件(widget)時(shí)會(huì)需要不同的參數(shù),如繪制面板(panel)可能需要線寬作為額外參數(shù)而繪制焦點(diǎn)矩形(focus rect)可能需要背景色作為額外參數(shù),所以Qt專門提供了一個(gè)類QStyleOption來封裝不同的widget可能需要的不同的參數(shù),opt指向這樣一個(gè)類的對(duì)象。

            2)void drawComplexControl(  ComplexControl control,
               QPainter *p,
               const QWidget *widget,
               const QRect &r,
               const QColorGroup &cg,
               SFlags flags = Style_Default,
               SCFlags controls = QStyle::SC_All,
               SCFlags active = QStyle::SC_None,
               const QStyleOption& opt = QStyleOption::Default)

            功能:繪制復(fù)雜控制部件(widget)如SpinWidget,comboBox,slider,listView等

            參數(shù):

            ComplexControl control:是一個(gè)枚舉量,表示將要繪制的復(fù)雜控制部件(widget)如組合框、列表框等。 
            QPainter *p:指向QPainter的指針,Qt中的所有繪制操作不管是繪制文本、圖形還是圖像都由這個(gè)類來處理。 
            QWidget *widget:指向QWdget或其子類的指針,可以根據(jù)上面control的值轉(zhuǎn)變(cast)成合適的類型,例如如果要繪制QSpinWidget,那么control取值為CC_SpinWidget,而widget指向一個(gè)QSpinWidget(QWidget的子類)的實(shí)例(instance)。使用這個(gè)變量可以訪問QSpinWidget的成員函數(shù)和成員變量,譬如可以調(diào)用QSpinWidget的sizeHint函數(shù)獲得這個(gè)部件的缺省大?。ㄒ粋€(gè)矩形空間)。 
            QRect &r: 表示一個(gè)矩形區(qū)域,Qt在這個(gè)區(qū)域中繪制控件或其子部件。 
            QColorGroup &cg: QColorGroup表示一個(gè)部件(widget)的顏色組(color group),color group含有部件繪制自己時(shí)使用的各種顏色,譬如前景色背景色等。 
            SFlags flags: 控制如何繪制圖形界面元素的標(biāo)志 
            SCFlags controls表示繪制復(fù)雜控制部件control的哪個(gè)子部件,缺省為SC_All,即繪制整個(gè)control而不是其某個(gè)子部件(注意control, controls是兩個(gè)不同的參數(shù)) 
            QStyleOption &opt: 在繪制不同的部件時(shí)可能需要不同的額外的參數(shù),這個(gè)變量在繪制不同的widget時(shí)提供不同的信息。

            3) QRect querySubControlMetrics(ComplexControl control,
                        const QWidget* widget,
                     SubControl sc,
                     const QStyleOption&
                      = QStyleOption::Default)

            功能:獲取子部件的坐標(biāo)和尺寸信息。這個(gè)函數(shù)控制著一個(gè)復(fù)雜控件的布局,重載這個(gè)函數(shù)可以使的組合框的下拉按鈕繪制在左邊 而不是默認(rèn)的右邊。

            參數(shù): 
            ComplexControl control: 枚舉量,表示將要繪制的復(fù)雜控制部件(widget)如組合框、列表框等。 
            QWidget *widget:指向QWidget或其子類的指針,可以根據(jù)上面control的值轉(zhuǎn)變(cast)成合適的類型,例如如果要繪制QSpinWidget,那么control取值為CC_SpinWidget,而widget指向一個(gè)QSpinWidget(QWidget的子類)的實(shí)例。使用這個(gè)變量可以訪問QSpinWidget的成員函數(shù)和成員變量,譬如可以調(diào)用QSpinWidget的sizeHint函數(shù)獲得這個(gè)部件的缺省大?。ㄒ粋€(gè)矩形空間)。 
            SubControl sc:枚舉量,一個(gè)復(fù)雜部件可能由多個(gè)的子部件組成,使用sc變量說明要獲取那個(gè)子部件的坐標(biāo)和尺寸信息。 
            QStyleOption &opt: 計(jì)算不同部件的尺寸時(shí)可能需要不同的額外信息,QStyleOption封裝了這些信息。




            回頁首


            2.創(chuàng)建新風(fēng)格

            下面用一個(gè)例子來介紹一下創(chuàng)建新風(fēng)格的整個(gè)過程,在編程之前,先看一下最終的結(jié)果是什么樣的。(在Qt內(nèi)部QSpinBox類是通過QSpinWidget實(shí)現(xiàn)的)

            默認(rèn)風(fēng)格的效果: 使用新風(fēng)格的效果: 

            可以看到在新風(fēng)格中我們的SpinBox有了垂直顯示的效果。下面我們按上面說明的步驟來創(chuàng)建一種新的風(fēng)格。

            1)選擇基類:我們選擇QWindowsStyle類作為我們新風(fēng)格類的基類,當(dāng)然也可以選擇QMotifStyle,在這個(gè)例子種也可以選擇QCommonStyle。一般不建議選擇QCommonStyle作為基類,因?yàn)镼CommonStyle只實(shí)現(xiàn)了一部分界面部件,如果要實(shí)現(xiàn)一個(gè)完整的風(fēng)格類,我們需要重新寫很多代碼。

            2)重載相關(guān)的函數(shù):在這個(gè)例程中我們只修改了spinBox的風(fēng)格,實(shí)現(xiàn)這個(gè)部件(widget)只與QStyle類的三個(gè)函數(shù)drawPrimitive, drawComplexControl, qureySubControlMerics相關(guān),所以我們只需重載這三個(gè)函數(shù)的相關(guān)部分代碼.下面對(duì)代碼中的關(guān)鍵部分做一下注釋,不重要的部分省略了。詳細(xì)的代碼可以從后面下載。

            繪制spinbox中按鈕的函數(shù):

            void CustomStyle::drawPrimitive( PrimitiveElement pe,
                                     QPainter * p,
                                        const QRect & r,
                                        const QColorGroup & cg,
                                        SFlags flags,
                                        const QStyleOption & opt ) const
            {
            /*PE_SpinWidgetUp,PE_SpinWidgetDown表示spinBox中的下按鈕和上按鈕,
            下面的代碼使得這兩個(gè)按鈕中的三角形分別向左和向右*/
            if ((pe == PE_SpinWidgetUp) || (pe == PE_SpinWidgetDown)){
              int fw = pixelMetric( PM_DefaultFrameWidth, 0 );//fw表示邊框?qū)挾龋J(rèn)為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;
            /* 設(shè)置三角形的三個(gè)點(diǎn)的坐標(biāo),修改這三個(gè)點(diǎn)可以使得QSpinBox上按鈕里的三角型呈現(xiàn)任意的形狀,
            下面的設(shè)置使得三角形表示的箭頭分別向左和向右。*/
              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{ 
            /*對(duì)于其他基本圖形元素(PrimitiveElement)的繪制我們不作處理只是簡(jiǎn)單的調(diào)用父類的函數(shù)。*/
              QWindowsStyle::drawPrimitive( pe, p, r, cg, flags, opt);
                }
            }

            繪制整個(gè)spinBox的函數(shù):

            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呈現(xiàn)垂直顯示的風(fēng)格而不是通常的水平顯示
            if (control == CC_SpinWidget) {
              const QSpinWidget * sw = (const QSpinWidget *) widget;
              //繪制向上按鈕部分,controls默認(rèn)為SC_All,即繪制整個(gè)spinwidget
              if ( controls & SC_SpinWidgetUp ) {
               
                  if ( sw->buttonSymbols() == QSpinWidget::PlusMinus )
                pe = PE_SpinWidgetPlus;  // 使用加減號(hào)


             
            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之外的其他復(fù)雜控制部件,調(diào)用父類函數(shù)處理
            QWindowsStyle::drawComplexControl(control, p, widget, r, cg, flags, controls, active, opt);
                }
            }

            獲取部件(widget)中各個(gè)子部件布局信息的函數(shù),這個(gè)函數(shù)控制著一個(gè)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 定義二維對(duì)象的大小,也就是寬和高. 坐標(biāo)類型是QCOORD定義為int)*/
              QSize bs;  //此處bs表示每個(gè)按鈕的大小,因?yàn)橛袃蓚€(gè)按鈕所以下面除以2.
              bs.setWidth(widget->width()/2 -fw);
              if(bs.width() < 8) bs.setWidth(8);
              /*按鈕高度設(shè)置為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的各個(gè)子部件的坐標(biāo)位置.
             switch ( sc ) {
             case SC_SpinWidgetUp:
              //返回向右按鈕的坐標(biāo)信息
                 return QRect(x + bs.width(), y, bs.width(), bs.height());
             case SC_SpinWidgetDown:
              //返回向左按鈕的坐標(biāo)信息
                 return QRect(x, y, bs.width(), bs.height());
             case SC_SpinWidgetButtonField:
              //返回兩個(gè)按鈕的總區(qū)域大小
                 return QRect(x, y, widget->width() - 2*fw, bs.height());
             case SC_SpinWidgetEditField:
            /*返回可編輯框的坐標(biāo)信息*/
                 return QRect(fw, ly, widget->width() - 2*fw, ry);
             case SC_SpinWidgetFrame:
              //返回整個(gè)spinBox的坐標(biāo)信息
                 return widget->rect();
             default:
                 break;
             }
                }else{//其它部件的布局信息調(diào)用父類的函數(shù)來處理。
              return QWindowsStyle::querySubControlMetrics(control,widget,sc,opt );
                }
                return QRect();
            }




            回頁首


            3.使用新風(fēng)格

            有兩種方法使用新風(fēng)格,一種是作為插件,一種是在應(yīng)用程序里直接使用。作為插件的風(fēng)格可以在不用修改代碼、不用重新編譯的情況下使用新風(fēng)格。由于本文著重介紹如何創(chuàng)建風(fēng)格所以我們使用第一種方法。這種方法很簡(jiǎn)單,只需在應(yīng)用程序中包含相應(yīng)風(fēng)格類的頭文件,然后把main()函數(shù)第一句可執(zhí)行代碼設(shè)置為QApplication::setStyle(new MyStyle())即可。

            下面我們用一個(gè)小例子來看看效果。

            #include <qapplication.h>
            #include <qspinbox.h>
            #include "customstyle.h"
            int main( int argc, char **argv )
            {
                QApplication::setStyle(new CustomStyle()); //使用新風(fēng)格類來繪制界面。
                QApplication a( argc, argv );
                QSpinBox spin( 0, 15 );
                spin.resize( 20, 100 );
                a.setMainWidget( &spin );
                spin.show();
                return a.exec();
            }

            然后編譯運(yùn)行即可看到效果。

            Ps. qt中編譯使用qmake,步驟為

            • 創(chuàng)建源程序
            • 同一目錄下運(yùn)行qmake -project
            • qmake
            • make
            • 運(yùn)行可執(zhí)行程序。



            回頁首


            4.進(jìn)一步工作

            1)默認(rèn)大?。杭?xì)心的朋友可能看到上面的代碼中有一句:spin.resize( 20, 100 ),這一句設(shè)置spinbox的長(zhǎng)度為20象素,寬度為100個(gè)象素。如果沒有這一句的話,顯示的結(jié)果會(huì)一團(tuán)糟,兩個(gè)按鈕幾乎看不到


             

            ,因?yàn)閝t默認(rèn)的顯示是水平顯示而根本沒有考慮垂直顯示的情況。

            如果想讓spinbox在默認(rèn)情況下看起來長(zhǎng)度窄而寬度高需要修改QSpinBox類中的sizeHint函數(shù),這個(gè)函數(shù)功能是設(shè)置部件(widget)的默認(rèn)尺寸。在qt中幾乎每個(gè)GUI部件類都有sizeHint這個(gè)函數(shù)來設(shè)置它自己的默認(rèn)的長(zhǎng)和寬。

            文本垂直顯示:在此例中雖然控件spinbox達(dá)到了垂直顯示的效果,但是文本仍舊是水平顯示的,因此要達(dá)到真正的垂直顯示需要了解qt的文本顯示機(jī)制。

            posted on 2009-04-26 11:16 逛奔的蝸牛 閱讀(7110) 評(píng)論(2)  編輯 收藏 引用 所屬分類: Qt

            評(píng)論

            # re: Qt: 用QT創(chuàng)建新風(fēng)格: QStyle[未登錄] 2014-06-27 16:17 Roc
            你好,我想請(qǐng)教一下。我在用QT的qmake 時(shí),能把制作出來的計(jì)算機(jī)小程序運(yùn)行出來,但是當(dāng)我在用tmake的時(shí)候,當(dāng)我執(zhí)行make命令時(shí)卻出現(xiàn)一堆錯(cuò)誤。錯(cuò)誤提示如下:Link' is not a member of type `QColorGroup'。請(qǐng)問是什么意思呢??該怎么解決?  回復(fù)  更多評(píng)論
              

            # re: Qt: 用QT創(chuàng)建新風(fēng)格: QStyle 2014-10-10 19:19 三狗
            二狗哥哥我來看你了  回復(fù)  更多評(píng)論
              

            久久精品国产亚洲Aⅴ蜜臀色欲| 一本久久综合亚洲鲁鲁五月天亚洲欧美一区二区| 色综合久久天天综线观看| 亚洲精品国精品久久99热| 久久国产精品成人片免费| 午夜不卡888久久| 国内精品久久久久影院薰衣草| 久久精品国产亚洲av麻豆色欲 | 久久国产精品无码网站| 久久精品中文无码资源站| 久久免费小视频| 亚洲AV日韩AV天堂久久| 亚洲国产成人精品久久久国产成人一区二区三区综 | 99久久精品免费| 99久久精品国产一区二区| 国产精品女同一区二区久久| 人妻无码αv中文字幕久久琪琪布| 色综合久久88色综合天天 | 成人免费网站久久久| 久久久久亚洲av成人网人人软件 | 久久人人爽人人爽人人av东京热| 国产精品成人99久久久久| 99久久99久久| 丰满少妇高潮惨叫久久久| 7777精品久久久大香线蕉 | 久久精品中文字幕有码| 91久久精品国产成人久久| 国产精品久久久久影院嫩草| 久久免费看黄a级毛片| 伊人久久大香线蕉综合网站| 久久人人超碰精品CAOPOREN | 狠狠色婷婷久久一区二区三区| 影音先锋女人AV鲁色资源网久久| 久久久久香蕉视频| 精品久久久久久无码中文野结衣| 久久香蕉综合色一综合色88| 国产日产久久高清欧美一区| 久久久精品午夜免费不卡| 99久久免费国产精品| 久久久久久无码国产精品中文字幕 | 中文字幕精品久久久久人妻|