• <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>

            zhonghua

            C++博客 首頁 新隨筆 聯系 聚合 管理
              72 Posts :: 1 Stories :: 4 Comments :: 0 Trackbacks

            #

            Qt提供了一個絕妙的屬性系統。跟那些由編譯器提供的屬性差不多。然而,作為一個獨立于編譯器和平臺的庫,Qt不依賴于非標準的編譯特性,比如 __property 或[property]。Qt可以在任何平臺上的標準編譯器下編譯。Qt屬性系統基于元數據對象系統--就是那個提供了對象內置信號和槽通訊機制的家伙。


            聲明屬性需要什么


            要聲明一個屬性,需在繼承自QObject的類中使用Q_PROPERTY()宏。
            Q_PROPERTY(type name
               READ getFunction
               [WRITE setFunction]
               [RESET resetFunction]
               [NOTIFY notifySignal]
               [DESIGNABLE bool]
               [SCRIPTABLE bool]
               [STORED bool]
               [USER bool]
               [CONSTANT]
               [FINAL])

            下面是一些典型的聲明屬性的示例:

            1. Q_PROPERTY(bool focus READ hasFocus)  
            2. Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)  
            3. Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)  
            • 一個屬性的行為就像類的數據成員,但是它還具有附加的特性,這些特性可以被元數據對象系統操作。這些特性是:
              需要一個READ訪問器函數。用于讀屬性的值。理想情況下,有一個不變的函數用于此目的,并且它必須返回屬性的類型的值或指針或引用。例如,QWidget::focus是一個只讀的屬性,它對應一個讀函數:QWidget::hasFocus()。
            • 一 個可選的WRITE訪問器函數。它用于設置屬性的值。它必須返回空并且至少具有一個參數,參數是屬性類型的值或指針或引用。例 如:QWidget::enabled具有WRITE函數QWidget::setEnable()。只讀屬性不需要寫函數。例 如,QWidget::focus沒有對應的寫函數。
            • 一個可選的RESET函數。用于設置屬性的值到它的默認值。例 如:QWidget::cursor具有典型的READ和WRITE函數,QWidget::cursor()和 QWidget::setCursor(),并且它也具有一個RESET函數,QWidget::unsetCursor()。RESET函數必須返回 void并且不帶有任何參數。
            • 一個可選的NOTIFY信號。如果被定義了,信號將在屬性的值改變時發出。信號必須帶有一個參數,這個參數的類型必須與屬性相同;參數保存的是屬性的新值。
            • 一個DESIGNABLE變量表明此屬性是否在界面設計器的屬性編輯器中出現。大多數屬性是可見的,除了為這個變量傳入true或false,你還可以指定一個bool型的成員函數。
            • SCRIPTABLE變量表明這個屬性是否可以被一個腳本引擎操作(默認是true)。你也可以賦予它true或false或bool型函數。
            • STORED 變量表明了屬性是否被認為是獨立存在還是依賴于其它的值而存在。它也表明是否在保存對象狀態時保存此屬性的值。大多數屬性都是需要保存的,但是,如 QWidget::minimumWidth()就是不被保存的,因為它的值是從另一個屬性QWidget::minimumSize()得來的。
            • USER變量表明屬性是否被設計為面向用戶的或用戶可修改的類屬性。通常,每個類只有一個USER屬性。例如,QAbstractButton::checked是按鈕類的用戶可修改屬性。注意QItemDelegate獲取和設置widget的USER屬性。
            • CONSTANT的出現表明屬性的值是不變的。對于一個object實例,常量屬性的READ方法在每次被調用時必須返回相同的值。此常量值可能在不同的object實例中不相同。一個常量屬性不能具有WRITE方法或NOYIFY信號。
            • FINAL變量的出現表明屬性不能被派生類所重寫。有些情況下,這可以用于效率優化,但不是被moc強制的。程序員必須永遠注意不能重寫一個FINAL屬性。

            READ,WRITE和RESET函數都可以被繼承。它們也可以是虛函數。當它們在被多重繼承中被繼承時,它們必須出現在第一個被繼承的類中。

            屬性的類型可以是被QVariant支持的所有類型,也可以是用戶定義的類型。在下面的例子中,類QDate被當作用戶自定義類型。
            Q_PROPERTY(QDate data READ getDate WRITE setDate)
            因為QDate是用戶定義的,你必須包含<QDate>頭文件。

            對 于QMap,QList和QValueList屬性,屬性的值是一個QVariant,它包含整個list或map。注意Q_PROPERTY字符串不能 包含逗號,因為逗號會劃分宏的參數。因此,你必須使用QMap作為屬性的類型而不是QMap<QString,QVariant>。為了保持 一致性,也需要用QList和QValueList而不是QList<QVariant>和 QValueList<QVariant>。


            通過元數據對象系統讀寫屬性

            一 個屬性可以使用常規函數QObject::property()和QObject::setProperty()進行讀寫,不用知道屬性所在類的任何細 節,除了屬性的名字。在下面的小代碼片段中,調用QAbstractButton::setDown()和QObject::setProperty() 都把屬性設置為“down”。

            1. QPushButton *button = new QPushButton;  
            2. QObject *object = button;  
            3. button->setDown(true);  
            4. object->setProperty("down", true);  

            通 過WRITE操作器來操作一個屬性是上面兩者中更好的,因為它快并且在編譯時給于更好的診斷幫助,但是以這種方式設置屬性要求你必須在編譯時了解其類。通 過名字來操作屬性使你可以操作在編譯器你不了解的類。你可以在運行時發現一個類的屬性們,通過查詢它的QObject,QMetaObject和 QMetaProerties。

            1. QObject *object = ...  
            2. const QMetaObject *metaobject = object->metaObject();  
            3. int count = metaobject->propertyCount();  
            4. for (int i=0; i<count; ++i) {  
            5.     QMetaProperty metaproperty = metaobject->property(i);  
            6.     const char *name = metaproperty.name();  
            7.     QVariant value = object->property(name);  
            8.     ...  
            9. }  

            在上面的代碼片段中,QMetaObject::property()被用于獲取未知類中的屬性的metadata。從metadata中獲取屬性名然后傳給QObject::property()來獲取

            一個簡單例子


            假 設我們有一個類MyClass,它從QObject派生并且在它的private區使用 了Q_OBJECT宏。我們想在MyClass類中聲明一個屬性來持續追蹤一個Priorty值。屬性的值叫做priority,并且它的類型是一個在類 MyClass中定義的叫做Priority的枚舉。

            我們在類的private區使用Q_PROPERTY()來聲明屬性。READ函數 叫做priority,并且我們包含一個WRITE函數叫做setPriority。枚舉類型必須使用Q_ENUMS()注冊到元數據對象系統中。注冊一 個枚舉類型使得枚舉的名字可以在調用QObject::setProperty()時使用。我們還必須為READ和WRITE函數提供我們自己的聲明。 MyClass的聲明看起來應該是這樣的:

            1. class MyClass : public QObject  
            2. {  
            3.     Q_OBJECT  
            4.     Q_PROPERTY(Priority priority READ priority WRITE setPriority)  
            5.     Q_ENUMS(Priority)  
            6. public:  
            7.     MyClass(QObject *parent = 0);  
            8.     ~MyClass();  
            9.     enum Priority { High, Low, VeryHigh, VeryLow };  
            10.     void setPriority(Priority priority);  
            11.     Priority priority() const;  
            12. };  

            READ函數是const的并且返回屬性的類型。WRITE函數返回void并且具有一個屬性類型的參數。元數據對象編譯器強制做這些事情。

            在有了一個指向MyClass實例的指針時,我們有兩種方法來設置priority屬性:

            1. MyClass *myinstance = new MyClass;  
            2.  QObject *object = myinstance;  
            3.  myinstance->setPriority(MyClass::VeryHigh);  
            4.  object->setProperty("priority", "VeryHigh");  

            在 此例子中,枚舉類型在MyClass中聲明并被使用Q_ENUMS()注冊到元數據對象系統中。這使得枚舉值可以在調用setProperty()時做為 字符串使用。如果枚舉類型是在其它類中聲明的,那么我們就需要用枚舉的全名(如OtherClass::Priority),并且這個其它類也必須從 QObject中派生并且也要注冊枚舉類型。
            另一個簡單的Q_FLAGS()也是可用的。就像Q_ENUMS(),它注冊一個枚舉類型,但是它把 枚舉類型作為一個flag的集合,也就是,值可以用OR操作來合并。一個I/O類可能具有枚舉值Read和Write并且 QObject::setProperty()可以接受 Read|Write。此時應使用Q_FLAGS()來注冊枚舉值。

            動態屬性

            Qobject::setProperty() 也可以用來在運行時向一個類的實例添加新的屬性。當使用一個名字和值調用它時,如果一個對應的屬性已經存在,并且如果值的類型與屬性的類型兼容,那么值就 被存儲到屬性中,然后返回true。如果值類型不兼容,屬性的值就不會發生改變,就會返回false。但是如果對應名字的屬性不存在,那么一個新的屬性就 誕生了,以傳入的名字為名,以傳入的值為值,但是依然會返回false。這表示返回值不能用于確定一個屬性是否被設置值,除非你已經知道這個屬性已經存在 于QObject中了。
            注意動態屬性被添加到單個實現的基礎中,也就是,被添加到QObject,而不是QMetaObject。一個屬性可以從 一個實例中刪除,通過傳入屬性的名字和非法的QVariant值給QObject::setProperty()。默認的QVariant構造器構造一個 非法的QVariant。
            動態屬性可用QObject::property()來查詢,就行使用Q_PROPERTY()聲明的屬性一樣。

            屬性和自定義類型

            被屬性使用的自定義類型需要使用Q_DECLARE_METATYPE()宏注冊,以使它們的值能被保存在QVariant對象中。這使得它們可以用于被Q_PROPERTY()聲明的靜態類型中,也可以被用于動態類型中。

            posted @ 2013-06-05 09:53 米米 閱讀(1027) | 評論 (0)編輯 收藏

            QGraphicsItem類是視圖框架的一部分,是在一個QGraphicsScene中最基本的圖形類,它為繪制你
             
             
             
            自己的item提供了一個輕量級的窗口,包括聲明item的位置,碰撞檢測,繪制重載和item之間的相
             
             
             
            互作用通過事件處理
             
            Qt提供了一系列標準的items對一些常見的圖像,非常的方便,有下面這些:
             
            QGraphicsEllipseItem  提供一個橢圓item
             
            QGraphicsLineItem     提供一條線的item
             
            QGraphicsPathItem     提供一個任意的路徑item
             
            QGraphicsPixmapItem   提供一個圖形item
             
            QGraphicsPolygonItem  提供一個多邊形item
             
            QGraphicsRectItem     提供一個矩形item
             
            QGraphicsSimpleTextItem 提供一個簡單的文本item
             
            QGraphicsTextItem     提供一個文本瀏覽item
             
            item 的所有幾何位置信息都建立在本地坐標系統上,item的位置,使用pos()獲得,是唯一一個不再本地item中實現的。它返回的是item在父親坐標系 統中的位置,關于坐標系統可以詳細參看 The Graphics View Coordinate System
             
             
             
            通 過調用哪個setVisible(),可以設置item是否可見,隱藏一個item同時也隱藏了他的孩子,相似的,你可以通過調用 setEnabled()來是指item是否可用。如果禁用了item,那么它所有的孩子都不可用。默認的,items都是可見和可用的。來開關一個 item是否被選擇,首先通過設置itemsSelectable flag來使能選擇。然后調用setSelect(),通常,是否可被選擇的開關時打開的
             
             
             
            寫自己的item圖形,首先應該繼承QGraphicsItem,然后重寫他的兩個純虛公共函數,

            boundingRect()和paint(),第一個函數返回繪制item大概的區域,第二個函數用來繪制item內容
             
             
             


            boundingRect() 函數有很多用處,場景在boundingRect()來建立它的item的index,視圖view使用它來剪切可見的item,在重新繪制item時 候,來決定相互重疊的部分,此外,item的碰撞檢測機制也使用的boundingRect()來提供一個高效的定點,在 collidesWithItem()更好的碰撞算法建立在調用函數shape(),shape()函數以QpainterPath類型返回item的精 準的輪廓。
             
            一般的,場景不希望item的boundingRect()和shape()變化,除非該item被通告,如果想通過一些方法改變item的形狀,首先應該調用QgraphicsScene()來允許場景QgraphicsScene來刷新它的item記錄。
             
             
             
            碰撞檢測可以通過下面兩種方法來完成
             
            1、重寫shape()函數來返回item的精準輪廓,依靠默認的collidesWithItem()來做外形交集。如果item輪廓和復雜時候,這個消耗是很大的
             
            2、重寫collidesWithItem(),提供一個自己的item和輪廓碰撞的算法
             
             
             
            Contains()函數可以調用,用來決定一個item是否包含一個點。這個函數也可以重寫,contains()函數默認的方法是通過調用shape()來完成的。
             
            Items中也可以包含其他的items,也可以被別的items包含,所有的items可以有一個父親item和一串孩子items,除非一個item沒有父親,否則它的位置是在父親坐標中,父親items遺傳他的位置和轉換給孩子item
             
            轉換
             
            QgraphicsItem 支持投射轉換,有很多方法來改變item的轉換,對于簡單的轉換,可以調用函數setRotation()或者setScale(),可以傳遞一個轉換矩 陣給函數setTransform(),對于一些更復雜的轉換,可以通過調用函數setTransformations()來設置一系列組合的轉換。
             
            Item 轉換從父親到孩子進行聚集,因此如果一個父親和孩子item都旋轉90度,那么孩子就旋轉了180度,相似的,如果父親item放大了2X倍,那么孩子 item就被方法4X倍,一個item的轉換不影響他的外觀,所有和外觀有關的函數(例如contains(),update()和所有的映射 mapping函數)將會在本地坐標中操作,更方便的,QgraphicsItem提供函數sceneTransform(),將會返回item所有的轉 換矩陣,scenePos()將會返回item在場景坐標中的位置,重新設置item的矩陣,調用函數resetTransform()
             
            一 般的轉換回產生一個不同的結果,這取決于轉換應用的順序,例如,如果你放大一個轉換,然后再旋轉它,可能和你先旋轉它得到的結果不一樣,你設置轉換屬性的 順序并不影響轉換的結果,(也就是仍舊會按照你的轉換命令去轉換,只是最后得到的圖形不一樣而已),QgraphicsItem經常應用一個合適的順序如 下:
             


            繪圖painting
             
            paint()函數被QgrapicsView類調用來繪制item的 內容,item默認是沒有背景或者填充顏色的。在函數中沒有被繪制的所有區域都將會發亮,可以調用update()來重繪item,可以選擇傳遞需要重繪 的矩形區域(不是必須的)。取決于item在view中是否可見,item可能會也可能不會重繪,QgraphicsItem里面沒有和 Qwidget::repaint()函數等價的
             
            item通過view來繪制,從父items開始,然后是自items,以上升的棧的 順序,可以通過調用setZValue()設置item的棧順序,通過zValue()來測試,具有低z-values的item比具有高z-value 的item先繪制,棧順序應用于兄弟items,父items總是比子items更早繪制。
             
             
             
            排序sort
             
            所有的items都按照一個已經聲明的,穩定的順序來繪制,這個順序也決定了當你在場景中點擊鼠標時候,哪個items最先接受鼠標的輸入。一般的,你不需要擔心排序問題,因為所有的items都按照一個在場景中聲明的自然的順序
             


            在一個棧中,子item在父item的上面,兄弟item按照插入場景的順序來入棧,如果你先添加了item A ,然后是item B,然后是item C ,這樣棧中的順序從下往上就是A,B,C
             
            Drag and Drop Robot例子中展示了該robot的棧順序,軀干順序是根item(其他所有的item都是軀干item的子item或者后代item),然后是頭 item被繪制,由于它是軀干item的子item列表中的第一個item,然后是左臂膀上面的那部分item,下面那個臂膀item是上面臂膀item 的子item,所以會在和3號item同等級的兄弟item繪制完后被繪制,接著就是右邊上面的的臂膀item,就是5號item。
             
             。可以調用setZvalue()來設置一個item的相對亦另一個向上,向下或者兄弟棧順序。默認的Z值是0,具有同樣的Z值的item會按照插入的順序來入棧。
             
            。可以調用stackBefore()來備份孩子item的列表,這可以直接更正item的順序。
             
            。如果想讓孩子item在父item的后面,也就是先繪制孩子item,然后在繪制父item,怎么辦呢?可以設置ItemStacksBehindParent屬性給這個item,利用函數setFlag();
             
            兩個兄弟item的順序也決定了他們的子item 和后代item的順序,如果一個父item的在兩個父item的后面,那么他所有的孩子items都在另一個父item的孩子items后面。
             
             
             
            事件Event
             
            QgraphicsItem從場景中通過sceneEvent()函數來接受事件,這個函數通過一些方便的操作分散大部分事件
             
            ContextMenuEvent()函數接受上下文菜單事件
             
            FocusInEvent()和focusOutEvent()函數接受焦點進出事件
             
            hoverEnterEvent(), hoverMoveEvent(), and hoverLeaveEvent() 接受鼠標懸浮 移動和離開事件
             
            inputMethodEvent()函數處理輸入法事件,
             
            keyPressEvent() and keyReleaseEvent()事件處理鍵盤按下和松開事件
             
            mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and mouseDoubleClickEvent()處理鼠標按下,移動,松開,雙擊事件
             
            也 可以為一些item過濾一些事件通過安裝過濾器,這個和QT一般的事件過濾器不一樣,一般的過濾器只工作在Qobject和它的子類,通過調用 installSceneEventFilter()為item安裝了過濾器后,被過濾的事件將會被虛函數sceneEventFilter().捕捉 到,可以通過調用函數removeSceneEventFilter().來去除掉事件過濾器
             
             
             
            Custom Data數據
             
            有 些時候為item注冊一些數值很有用,做一個普通的item或者標準的item,可以調用setData()來為任一個item設置值,這個值使用 key-value對,(key是整形,value是變種數據Qvarient)來得到item的數據,通過調用data(),
             
             
             
             
             
             
             
             
             
             
             
            1、QVariant QGraphicsItem::itemChange ( GraphicsItemChange change, const QVariant & value )   [virtual protected]
             
            這個函數被QGraphicsItem調用用來標明items的一些狀態改變了,通過重載這個函數,可以對自己定義事件響應,在一些情況下,可以做一些調整。
             
            參數change是改變的那個item的改變狀態參數,value是一個新的數據,他的類型取決于change,
             
             
             
            change是QGraphicsItem::GraphicsItemChange的枚舉變量
             
            enum      GraphicsItemChange { ItemEnabledChange, ItemEnabledHasChanged,

             
             
            ItemMatrixChange, ItemPositionChange, ..., ItemScenePositionHasChanged }
             
            例如:
             
             QVariant Component::itemChange(GraphicsItemChange change, const QVariant &value)
             
             {
             
                 if (change == ItemPositionChange && scene()) {
             
                     // value is the new position.
             
                     QPointF newPos = value.toPointF();
             
                     QRectF rect = scene()->sceneRect();
             
                     if (!rect.contains(newPos)) {
             
                         // Keep the item inside the scene rect.
             
                         newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left())));
             
                         newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top())));
             
                         return newPos;
             
                     }
             
                 }
             
                 return QGraphicsItem::itemChange(change, value);
             
             }
             
            默認的函數什么都不做,只返回value
             
            注 意:在使用這個函數時候,在函數內部調用函數時候要小心,因為這可能導致一些意想不到的結果,例如:你不能再這個函數里面調用setPos()在 change是ItemPositionChange時候,由于setPos()函數將會再次調用 itemChange(ItemPositionChange),如此就一直循環下去了。
             
            2、void QGraphicsItem::setFlag ( GraphicsItemFlag flag, bool enabled = true )
             
            void QGraphicsItem::setFlags ( GraphicsItemFlags flags )
             
            把flags設置為item的屬性,如果item獲得了光標,但是flags沒有使能ItemsFocusable,這個item
             
             
             
            將會丟失光標,同樣的,當item被選擇到,但是沒有使能ItemsSelectable,這個item會自動的失去
             
             
             
            選擇。
             
            默認的,所有的flags都是不可用的。(QGraphicsWidget 為了獲得位置變化默認使能了
             
             
             
            ItemSendsGeometryChanges)
             
            相近的函數
             
            GraphicsItemFlags QGraphicsItem::flags () const
             
            返回item的所有使能的flags,例如,如果flags里面包含了ItemIsFocusable,這個item可以接受
             
             
             
            輸入光標
             
            3、QPainterPath QGraphicsItem::shape () const   [virtual]
             
            以QPainterPath返回item在local坐標中的形狀,這個形狀可以用來做很多事情,包括碰撞偵測,
             
             
             
            打擊測試,還有用來 QGraphicsScene::items() 函數
             
            默認的函數調用boundingRect()返回一個簡單的矩形形狀,但是子類可以重載這個函數,為非矩形
             
             
             
            的item返回一個更加精準的形狀,例如一個圓形的item可以選擇返回一個橢圓形,用來獲得更好的
             
             
             
            碰撞偵測效果。代碼:
             
            QPainterPath RoundItem::shape() const
             
             {
             
                 QPainterPath path;
             
                 path.addEllipse(boundingRect());
             
                 return path;
             
             }
             
            形狀的輪廓線可以通過繪制時候的pen來變化
             
            4、QRectF QGraphicsItem::boundingRect () const   [pure virtual]
             
            這個純虛函數用矩形聲明了item的邊界輪廓,所有的繪制都必須限定在item的矩形邊框內。
             
             
             
            QGraphicsView使用這個方法來決定item是否需要重繪
             
            盡管item的形狀可以是任意的,但是邊框一直都是矩形,不影響items的變換
             
            如果想改變items的邊框,應該首先調用prepareGeometryChange(),這將通知場景scene即將發生的變化,這樣場景可以刷新item的位置下標。否則,場景將不會察覺到item的變化,結果也未知。
             
            如果要重繪item時候,重載這個函數來讓QGraphicsView來決定item的邊界區域,
             
            注意:由于繪制邊界時候的邊界輪廓線,在這個矩形區域內包含畫筆pen寬度的一半很重要,不需
             
             
             
            要補償畫圖走樣  例如
             
             QRectF CircleItem::boundingRect() const
             
             {
             
                 qreal penWidth = 1;
             
                 return QRectF(-radius - penWidth / 2, -radius - penWidth / 2,
             
                               diameter + penWidth, diameter + penWidth);
             
             }
             
             
             
            同樣的一個返回item輪廓的函數
             
            QRegion QGraphicsItem::boundingRegion ( const QTransform & itemToDeviceTransform ) const
             
            返回該item的輪廓區域,返回的區域的坐標系統依賴于參數itemToDeviceTransform,如果你傳遞一個Qtransform對象作為參數,那么函數將返回本地坐標系統區域
             
            返回的區域是item內容可見的一個大概的輪廓,盡管計算起來很浪費空間和時間,但是比boundingRect()更精準,而且當重繪時候,它還能避免不必要的重繪。對像線或者簡單的多邊形來說非常有效。
             
            也可以調節輪廓區域的粒度通過調用setBoundingRegionGranularity(),默認的粒度是0,這時候item的區域和輪廓矩形一樣的。
             
            itemToDeviceTransform是從item坐標系統到設備坐標系統的一個轉換。如果你想讓這個函數返回一個場景坐標區域,可以用函數sceneTransform()作為參數。
             
             
             
            相關函數qreal QGraphicsItem::boundingRegionGranularity () const
             
            返回item的輪廓區域粒度
             
             
             
            5、void QGraphicsItem::setPos ( const QPointF & pos )
             
            在父對象坐標系統中設置item的位置為pos,對沒有父對象的items,pos使用的場景的坐標系統,
             
            6、QPointF QGraphicsItem::scenePos () const
             
            返回該item在場景中的坐標點,等價于調用函數mapToScene(0, 0).
             
            7、QPointF QGraphicsItem::pos () const
             
            返回item在父坐標系中的位置,如果沒有父坐標系,那么返回在場景坐標系中的位置,此時等價于調用scenePos (),可以直接調用scenePos ()來獲取該item在場景中的位置,從而忽略其父對象。
             
             
             
            8、enum QGraphicsItem::CacheMode
            設置繪圖的緩沖模式,默認是沒有緩沖,如果使用緩沖區的話,在重繪時候,非常快
             
            設置緩沖模式使用函數QGraphicsItem::setCacheMode().
             
             
             
            9、bool QGraphicsItem::acceptDrops () const
             
            如果item能夠接受拖拽事件,就返回真,否則返回假,默認的不能接受拖拽事件
             
             同類函數
             
            void QGraphicsItem::setAcceptDrops ( bool on )
             
            如果On是真的話,就設置item可以接受拖拽事件,否則對拖拽事件是透明的,也就是不能響應拖拽,默認是不響應的。
             
            10、bool QGraphicsItem::acceptHoverEvents () const
             
            如果可以接受鼠標懸浮在他上面的事件,就返回真,否則返回假。默認也是不接受該事件的。
             
            同樣的用于設置是否接受該事件的函數
             
            void QGraphicsItem::setAcceptHoverEvents ( bool enabled )
             
            如果enabled為真,就接受,否則就不接受。
             
            11、Qt::MouseButtons QGraphicsItem::acceptedMouseButtons () const
             
            返回這個item所能接受的鼠標事件的鼠標鍵,默認的是所有的鼠標鍵事件都能接受。
             
            同 樣的使用函數void QGraphicsItem:: setAcceptedMouseButtons ( Qt::MouseButtons buttons )來設置接受的鼠標鍵事件,如果想忽略某個鼠標鍵事件,可以用setAcceptedMouseButtons(0)
             
            12、void QGraphicsItem::advance ( int phase )   [virtual]
             
            這 個虛函數被QGraphicsScene::advance()調用兩次,第一次調用,所有的items都調用,使用參數phase=0,表示場景中所有 的items都將advance(前進),然后所有的items都將調用,使用參數phase=1,重寫這個函數,可以來刷新你的item,如果你需要簡 單的場景控制動畫。
             
            默認的該函數什么事都不做
             
            如果想寫動畫,可以使用兩種方法,一個使用 QGraphicsItemAnimation,,或多重繼承Qobject和QgraphicsItem,然后使用 QObject::startTimer() 和 QObject::timerEvent().來使item成動畫。
             
             
             
            13、QList<QGraphicsItem *> QGraphicsItem::childItems () const
             
            返回孩子item的一個鏈表,這些items按照棧順序排列,考慮了item的插入順序和Z-values
             
            14、QRectF QGraphicsItem::childrenBoundingRect () const
             
            返回這個item的所有子孫items的本地坐標系統輪廓矩形。這個矩形包括了這個item所有的子孫item,如果這個item不含有子孫item,這個函數將返回一個空的矩形。
             
            返回的矩形不包括item本身的輪廓矩形,只返回子孫item的矩形輪廓,如果你想包含item本身的矩形區域,可以使用QRectF::operator|()把boundingRect()和hildrenBoundingRect()或起來。
             
            這個函數很復雜,它決定了返回輪廓的大小通過重復所有子孫item
             
             
             
            15、void QGraphicsItem::clearFocus ()
             
            去除item的光標,如果原來有光標焦點,當焦點失去時候,事件focus out event會發送給這個item,提示他將會失去焦點。
             
            Item只有設置了ItemsFocusable屬性,或者widget設置了合適的焦點策略,才能接受鍵盤焦點。
             
             
             
             
             
            16、 bool QGraphicsItem::collidesWithItem ( const QGraphicsItem * other, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const   [virtual]
             
            如 果這個item和另一個item碰撞就返回真,mode是應用于其他item的,默認是Qt::IntersectsItemShape,如果其他的 item和這個item相互影響或者包含,被包含于這個item的形狀(詳見Qt::ItemSelectionMode)。
             
            默認的函 數是就基于外形相互影響,它調用兩個item的shape()函數,這將會花費很大時間,你可以在QgraphicsItem子類中重寫這個函數,提供一 個簡單的算法。這樣你可以使用自己item的一些參數,這樣可以提高碰撞偵測的效果。例如,兩個完全沒有轉換的圓item的碰撞可以通過對比他們的圓心位 置和半徑
             
             
             
            17、bool QGraphicsItem::collidesWithPath ( const QPainterPath & path, Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const   [virtual]
             
            如果item按照path碰撞就返回真,
             
             
             
            18、QList<QGraphicsItem *> QGraphicsItem::collidingItems ( Qt::ItemSelectionMode mode = Qt::IntersectsItemShape ) const
             
            返回和這個item相互碰撞的item的鏈表
             
            碰撞偵測模式取決于mode,
             
             
             
            19\ QGraphicsItem * QGraphicsItem::commonAncestorItem ( const QGraphicsItem * other ) const
             
            返回item最近的祖先item,如果other為0,或者沒有祖先item,就返回0
             
             
             
            20、bool QGraphicsItem::contains ( const QPointF & point ) const   [virtual]
             
            如果item包含了點point就返回TRUE,否則返回FALSE,最常用的是在QgraphicsView中調用,來判斷這個item是否在光標下面,如果要重寫這個函數,那就盡可能的簡單。默認的這個函數調用的shape()函數
             
             
             
            21、void QGraphicsItem::contextMenuEvent ( QGraphicsSceneContextMenuEvent * event )   [virtual protected]
             
            右鍵菜單事件,可以在子類中重寫這個函數,event里面包含了事件要具體處理的數據。
             
            如果忽略這個事件,調用函數QEvent::ignore(),事件event將會被傳播到任何在該item之下的items,如果沒有item響應這個事件,那么場景就忽略這個事件,傳遞給view視圖
             
            通常是響應該事件打開一個右鍵菜單,例如
             
            void CustomItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)  {      QMenu menu;      QAction *removeAction = menu.addAction("Remove");      QAction *markAction = menu.addAction("Mark");      QAction *selectedAction = menu.exec(event->screenPos());      // ...  }
             
             
            默認是忽略該事件。
             
             
             
             
             
            22、QVariant QGraphicsItem::data ( int key ) const
             
            以Qvariant的格式返回item中的數據,當前的item數據對存儲任意數據很有用,例如
             
            static const int ObjectName = 0;    QGraphicsItem *item = scene.itemAt(100, 50);  if (item->data(ObjectName).toString().isEmpty()) {      if (qgraphicsitem_cast<ButtonItem *>(item))          item->setData(ObjectName, "Button");  }
            void QGraphicsItem::setData ( int key, const QVariant & value )
             
            用來設置item的數據
             
            23、QTransform QGraphicsItem::deviceTransform ( const QTransform & viewportTransform ) const
             
            返回item設備的轉換矩陣,使用viewportTransform來從場景到設備影射坐標,這個矩陣可以用來從這個item本地坐標到視圖口坐標系統映射坐標或者幾何圖形,如果要映射視圖口坐標到本地坐標,首先應該轉換返回的這個矩陣。
             
            QGraphicsRectItem rect;  rect.setPos(100, 100);    rect.deviceTransform(view->viewportTransform()).map(QPointF(0, 0));  // returns the item's (0, 0) point in view's viewport coordinates    rect.deviceTransform(view->viewportTransform()).inverted().map(QPointF(100, 100));  // returns view's viewport's (100, 100) coordinate in item coordinates
            這個函數是結合了到場景的轉換和到視圖的轉換,設備轉換可以用來對那些沒有進行轉換坐標的item計算碰撞。
             
            24、拖拽類函數
             
            void QGraphicsItem::dragEnterEvent ( QGraphicsSceneDragDropEvent * event )   [virtual protected]
             
            void QGraphicsItem::dragLeaveEvent ( QGraphicsSceneDragDropEvent * event )   [virtual protected]
             
            void QGraphicsItem::dragMoveEvent ( QGraphicsSceneDragDropEvent * event )   [virtual protected]
             
            void QGraphicsItem::dropEvent ( QGraphicsSceneDragDropEvent * event )   [virtual protected]
             
             
             
            25、qreal QGraphicsItem::effectiveOpacity () const
             
            返回item的有效透明度,這個數值在0.0~~1.0之間
             
            同樣的可以用函數void QGraphicsItem::setOpacity ( qreal opacity )來設置透明度,
             
            默認的子item繼承父item的透明度
             
            同樣可以設置item的屬性QGraphicsItem::ItemIgnoresParentOpacity 來忽略父item的透明度對自己的影響
             
            設置子item的屬性QGraphicsItem::ItemIgnoresTransformations來忽略視圖轉換(放大,縮小)等操作對自己的影響,在顯示文本時候很有用。
             
             
             
            26、void QGraphicsItem::hoverEnterEvent ( QGraphicsSceneHoverEvent * event )   [virtual protected]
             
            void QGraphicsItem::hoverLeaveEvent ( QGraphicsSceneHoverEvent * event )   [virtual protected]
             
            void QGraphicsItem::hoverMoveEvent ( QGraphicsSceneHoverEvent * event )   [virtual protected]
             
            鼠標懸浮事件
             
             
             
            27、void QGraphicsItem::mouseDoubleClickEvent ( QGraphicsSceneMouseEvent * event )   [virtual protected]
             
            void QGraphicsItem::mouseMoveEvent ( QGraphicsSceneMouseEvent * event )   [virtual protected]
             
            void QGraphicsItem::mousePressEvent ( QGraphicsSceneMouseEvent * event )   [virtual protected]
             
            void QGraphicsItem::mouseReleaseEvent ( QGraphicsSceneMouseEvent * event )   [virtual protected]
             
            鼠標雙擊,移動,釋放的事件
             
             
             
             
             
             
             
            28、QPointF QGraphicsItem::mapFromItem ( const QGraphicsItem * item, const QPointF & point ) const
             
            QPolygonF QGraphicsItem::mapFromItem ( const QGraphicsItem * item, const QRectF & rect ) const
             
            QPainterPath QGraphicsItem::mapFromItem ( const QGraphicsItem * item, const QPainterPath & path ) const
             
            QPolygonF QGraphicsItem::mapFromItem ( const QGraphicsItem * item, qreal x, qreal y, qreal w, qreal h ) const
             
            QPointF QGraphicsItem::mapFromItem ( const QGraphicsItem * item, qreal x, qreal y ) const
             
            QPointF QGraphicsItem::mapFromParent ( const QPointF & point ) const
             
            QPolygonF QGraphicsItem::mapFromParent ( const QRectF & rect ) const
             
            QPolygonF QGraphicsItem::mapFromParent ( const QPolygonF & polygon ) const
             
            QPainterPath QGraphicsItem::mapFromParent ( const QPainterPath & path ) const
             
            QPolygonF QGraphicsItem::mapFromParent ( qreal x, qreal y, qreal w, qreal h ) const
             
            QPointF QGraphicsItem::mapFromParent ( qreal x, qreal y ) const
             
            QPointF QGraphicsItem::mapFromScene ( const QPointF & point ) const
             
            QPolygonF QGraphicsItem::mapFromScene ( const QRectF & rect ) const
             
            QPolygonF QGraphicsItem::mapFromScene ( const QPolygonF & polygon ) const
             
            QPainterPath QGraphicsItem::mapFromScene ( const QPainterPath & path ) const
             
            QPolygonF QGraphicsItem::mapFromScene ( qreal x, qreal y, qreal w, qreal h ) const
             
            QPointF QGraphicsItem::mapFromScene ( qreal x, qreal y ) const
             
            QRectF QGraphicsItem::mapRectFromItem ( const QGraphicsItem * item, const QRectF & rect ) const
             
            QRectF QGraphicsItem::mapRectFromItem ( const QGraphicsItem * item, qreal x, qreal y, qreal w, qreal h ) const
             
            。。。。。。。。。。太多了
             
            轉換矩陣函數
             
             
             
             
             
            29、void QGraphicsItem::moveBy ( qreal dx, qreal dy )
             
            向x,y方向上移動dx,dy的距離,等價于調用setPos(pos()+QpointF(dx,dy))
             
             
             
             
             
            30\最重要的一個函數
             
            void QGraphicsItem::paint ( QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0 )   [pure virtual]
             
            這個函數通常被view調用,然后再本地坐標系統中繪制item的內容
             
             
             
            31、qreal QGraphicsItem::rotation () const
             
            返回item的旋轉度,
             
            設置旋轉度函數使用setRotation(),
             
             
             
            32、qreal QGraphicsItem::scale () const
             
            返回縮放系數
             
            設置縮放使用setScale()
             
             
             
            33、bool QGraphicsItem::sceneEvent ( QEvent * event )   [virtual protected]
             
            截獲事件,在事件沒有分發給各個具體的事件處理函數之前。
             
            相當于bool QObject::event ( QEvent * e )   [virtual]
             
             
             
            34、void QGraphicsItem::scroll ( qreal dx, qreal dy, const QRectF & rect = QRectF() )
             
            滾動item
             
             
             
            35、在使item能響應一些事件之前,需要先使能這個功能,例如
             
            void QGraphicsItem::setAcceptDrops ( bool on ) 

            如果on為真,那么就使能拖拽,否則將會忽略拖拽事件。默認是不接受的
             
            void QGraphicsItem::setAcceptHoverEvents ( bool enabled )
             
            如果on為真,使能鼠標懸浮事件。默認不接受該事件。
             
            void QGraphicsItem::setAcceptTouchEvents ( bool enabled )
             
            在一些支持觸摸的設備上,這個函數將使能觸摸事件。
             
             
             
            36、void QGraphicsItem::setEnabled ( bool enabled )
             
            使該item有效,如果enabled為假,則該item不能用了
             
             
             
            37、void QGraphicsItem::setGraphicsEffect ( QGraphicsEffect * effect )、
             
            設置item的效果,可以用模糊效果,印象效果,給定顏色繪制效果,透明效果等
             
            詳細的可以參見QgraphicsEffect類
             
             
             
            38、const int QGraphicsItem::Type
             
            返回該item的類型值,這個值是自己通過定義Type的值,然后使用type()虛函數來返回的,看例子
             
            class QGraphicsPathItem : public QAbstractGraphicsShapeItem  {   public:    enum { Type = 2 };      int type() const { return Type; }    ...  };
             
             
            39、T qgraphicsitem_cast ( QGraphicsItem * item )
             
            如果item是T類型的,把item轉換成T類型的item,如果失敗,則返回0
             
            如果想讓他正確的工作,需要重新實現函數type()來進行判斷

            posted @ 2013-05-24 11:08 米米 閱讀(4157) | 評論 (0)編輯 收藏

            一:qt plugin 介紹

                  Qt Plugin和其他類型的插件一樣,是一種計算機應用程序,它和主應用程序(host application)互相交互,以提供特定的功能。應用程序支持Plugin有許多原因,一些主要原因包括:使得第三方開發者有能力擴展應用程序,以提供無法先期預料的特色;減小應用程序的大小;由于軟件版權之間的不兼容性將源代碼和應用程序分享。Qt Plugin 分動態插件和靜態插件兩種。

            二:qt plugin 創建和使用方法

            Qt有兩種與插件有關的API。一種用來擴展Qt本身的功能,如自定義數據庫驅動,圖像格式,文本編解碼,自定義分格,等等,稱為Higher-Level API。另一種用于應用程序的功能擴展,稱為Lower-Level API。前一種是建立在后一種的基礎之上的。這里討論的是后一種,即用來擴展應用程序的Lower-level API

            讓應用程序支持插件擴展的步驟:

             1. 定義一個接口集(只有純虛函數的類),用來與插件交流。

             2. 用宏Q_DECLARE_INTERFACE()將該接口告訴Qt元對象系統。

             Q_DECLARE_INTERFACE(BrushInterface,"com.trolltech.PlugAndPaint.BrushInterface/1.0")

             3. 應用程序中用QPluginLoader來裝載插件。

             4. 用宏qobject_cast()來確定一個插件是否實現了接口。

             QObject *obj = new QTimer; 

             QTimer *timer = qobject_cast<QTimer *>(obj);

            寫一個插件的步驟:

             1. 聲明插件類,該類從QObject和該插件希望實現的接口繼承而來。

             2. 用宏Q_INTERFACES()將該接口告訴Qt元對象系統。

              class BasicToolsPlugin : public QObject,

                                        public BrushInterface,

                                        public ShapeInterface,

                                        public FilterInterface

              {

                   Q_OBJECT

                   Q_INTERFACES(BrushInterface ShapeInterface FilterInterface)

              public:

                   ...

               };

             3. 用宏Q_EXPORT_PLUGIN2()導出插件。

              Q_EXPORT_PLUGIN2 ( PluginName, ClassName )

             4. 用適當的.pro文件構建插件。

            下面的代碼聲明了一個接口類:

             

            class FilterInterface

             {

             public:

                    virtual ~FilterInterface() {}

                    virtual QStringList filters() const = 0;

                    virtual QImage filterImage(const QString &filter, const QImage &image, QWidget* parent)=0;

              };

            Q_DECLARE_INTERFACE(FilterInterface, "com.trolltech.PlugAndPaint.FilterInterface/1.0")

            這里是實現該接口的插件類的定義:

             

             #include <QObject>

             #include <QStringList>

             #include <QImage>

             #include <plugandpaint/interfaces.h>

             class ExtraFiltersPlugin : public QObject, public FilterInterface

             {

             Q_OBJECT

             Q_INTERFACES(FilterInterface)

             public:

                 QStringList filters() const;

                 QImage filterImage(const QString &filter, const QImage &image,

                 QWidget *parent);

             };

            根據插件的類型不同,pro文件中配置上有不同。下面是pro文件分析:

            TEMPLATE      = lib                                  // 聲明為lib,動態和靜態插件一樣。

            CONFIG       += plugin static                // 聲明為plugin,帶static表面為靜態,否則為動態。

            INCLUDEPATH += ../..

            HEADERS       = basictoolsplugin.h

            SOURCES       = basictoolsplugin.cpp

            TARGET        = $$qtLibraryTarget(pnp_basictools)           // 指明插件的名稱

            DESTDIR       = ../../plugandpaint/plugins

            加載插件的主應用程序默認在當前目錄下的plugins文件夾中尋找可用插件,如果是動態插件,則直接放在plugins文件夾中便可,如果是靜態,則需要在主應用程序的main函數的開始的地方用宏:Q_IMPORT_PLUGIN(pluginname(和pro文件中聲明的一致))聲明需要加載的插件并在工程配置中指明插件的lib位置。

            三:基于qt plugin 技術的框架結構設想

            1.      愿景

            由于我們目前系統功能多,模塊多,缺乏系統的整體性。我們想借助Qt Plugin技術,把各個獨立的功能模塊實現為一個個插件,統一在主體框架中,并能根據不同地方的用戶的不同需求,在主框架中加載不同的功能模塊,以實現整個系統的功能集中,體現出系統的整體性。

            2.      plugin 接口

            通過技術驗證得出,目前我們采用動態插件,各個功能的插件實現定義的統一接口,具體功能放在插件界面中實現,此部分就像開發獨立的應用程序,只是需要注意的是:

            功能部分的主界面需要繼承至插件界面基類:PluginWidget,插件接口中用具體的實現類指針給插件界面基類指針賦值,在加載插件的主框架中通過插件接口中定義的基類指針統一調用,利用C++動態技術動態識別具體指向的實現類。

            插件界面類必須實現基類的虛函數:CreateActions()用于創建Action

            創建Action需要使用基類的方法newAction創建,在此函數中加入了保存創建的Action功能。

            插件接口定義如下:

            class QPluginInterface

            {

            public:

                // 析構函數

                virtual ~QPluginInterface() {}

               

                // 插件名稱

                virtual    QString    PluginName() = 0;

               

                // 插件顯示在主框架中的圖標文件路徑

                virtual    QString PluginIconurl() = 0;

               

                // 插件提供的對外操作接口集

                virtual QList<QAction*>* Actions() = 0;

             

                // 創建插件提供的操作方法

                virtual    void CreateActions()=0;

             

                // 插件的主界面

                virtual QWidget* Widget() = 0;

            protected:

                // 插件的主界面基類

                PluginWidget *pluginWidget;

            };

            插件界面基類定義如下:

            class PluginWidget :public QMainWindow

            {

                Q_OBJECT

            public:

                PluginWidget(QWidget*parent=0);

                ~PluginWidget();

                QList<QAction*>* Actions();

                virtual void      CreateActions(){}

                QActionnewAction(const QIcon &icon,const QString &text,QObject*parent);

                QAction *         newAction(const QString &text,QObject*parent);

                void       AppendAction(QAction*act);

            protected:

                // action鏈表

                QList<QAction*> *m_actlist;

            };

            下圖是一個實現案例中各類之間的關系圖:

            基于QT Plugin框架結構  - yleesun - 與青春有關的日子...

            3.      插件調用

            插件在主框架中動態加載,目前考慮主框架基本結構是繼承至QMainWindow,工具欄上顯示當前加載的插件的功能鍵,并留有返回鍵可以回退到上一級。主工作區是一個QStackWidget,保存插件的界面,并把插件序號和插件對應的界面建立映射,保存在QMap<int,QWidget>中。通過序號到QStackWidget中切換界面。

            下圖是把DBManager做成插件加載到主框架的運行界面:

            基于QT Plugin框架結構  - yleesun - 與青春有關的日子...

            下圖是把一個簡單的繪圖程序做成了插件,加載到主框架的運行界面:

            基于QT Plugin框架結構  - yleesun - 與青春有關的日子...

            四:總結

                   目前只是通過實現兩個動態插件在主框架中運行,基本算是功能性的驗證,離具體實施還有很多工作需要進一步的研究,比如主框架的風格,插件的管理等等。由于本人的能力有限,可能有很多認識不夠的地方,請指正。

            posted @ 2013-02-22 15:10 米米 閱讀(751) | 評論 (0)編輯 收藏

            概念

            名稱 含義
            View 視圖 視覺化一個場景
            Scene 場景 用于管理圖形項
            Item 圖形項 具體的圖形對象

             

            QT的圖形視圖架構采用Model-View模型,Scence里面包含多個Item,可以用多個View以不同的方式觀察一個Scence

            功能
            Scene(QGraphicsScene)

            • 添加,刪除,查詢圖項

            • 事件分發

            • 管理圖項的選擇狀態和焦點

            View (QGraphicsView)

            • 為Scene提供一個視圖接口
            • 接收鼠標鍵盤事件,轉換后發給Scene
            • 負責View和Scence之間的坐標變換 

            可以為View設置不同的ViewPort控件,比如QGLWidget來支持OpenGL,Read More!

            Item (QGraphicsItem)

             

            圖形項的基類是QGraphicItem

            基礎的Feature包括:

            • 處理鼠標鍵盤事件
            • 拖放
            • 分組
            • 碰撞檢測

            每個圖形項都有自己的本例坐標系統,并提供它和場景坐標的轉換函數。所以可以單獨旋轉或縮放某個一圖形項


            除了pos等很少的幾個函數,圖形項的多數函數所處理的坐標都是它的本地坐標(例如bounding rect)

            坐標系統

            如上所述視圖體系采用三種坐標系統:

            • 視口坐標: 對應物理坐標/設備坐標
            • 場景坐標: 對應邏輯坐標
            • 項坐標: 本地坐標

            window-viewport概念

            window指定了邏輯坐標的矩形范圍,viewport指定了設備坐標的矩形范圍,和WorldTransform(世界轉換矩陣)一起,決定了邏輯坐標和設備坐標之間的轉換

             

            可以使用QGraphicsItemAnimation來動畫一個Item,使用QTimeLine來控制時間進度

             

            其它特性

            Animation動畫

            一個Item只能有效的和一個Animation對象關聯(by QGraphicsItemAnimation::setItem),因為Animation對象設置圖項Item的轉換矩陣時,會替換對象現有的矩陣。 所以你不能通過綁定多個Animation對象來做多重動畫,但是你可以在一個Animation對象中設置多種變換效果(或者用分組的方法,分級控 制?)


            QGraphicsItemAnimation直接繼承自QObject,和普通的QAbstractAnimation沒有關系,所以沒法只用用QAnimationGroup來組裝,然后串行/并行使用多個動畫。

             

            圖形控件和布局管理

            QGraphicsWidget的目的是在圖形對象的功能基礎上提供類似QWidget的功能。(從QGraphicsObject和 QGraphicsLayoutItem繼承來),從而可以使用完整的Widget控件屬性,設置字體,Style,提供size hints,以及信號槽機制等。

             

            QGraphicsLayout是專門用來布局QGraphicsWidget的布局控件。你可以通過多重繼承QGraphicsLayoutItem來定制QGraphicsItem使其能被QGraphicsLayout所管理

            嵌入普通控件

            你可以通過QGraphicsScene::addWidget來將一個普通QWidget嵌入到視圖體系中來使用,本質是通過創建一個代理控件 (QGraphicsProxyWidget)來在QWidget和QGraphicsItem之間傳遞事件。需要注意的是,這只是一個特殊的實現方式, 對性能有要求的程序不宜使用這個機制。(沒有太看出哪里對性能有很大影響)

             

            QGraphicsProxyWidget能夠處理復雜的控件嵌套,甚至能自動對被嵌套控件的子Popup Window控件創建代理控件。
             

            QGraphicsView本身也是一個普通QWidget控件,所以可以被添加到Scene中,創建復雜的嵌套視圖體系

            posted @ 2013-02-06 10:38 米米 閱讀(2030) | 評論 (0)編輯 收藏

             QRect rectWorkArea = qApp->desktop()->availableGeometry();
             QPoint ptLeftTop = geometry().topRight() + QPoint(2, 0);
             QSize sizeSettingsWindow = m_pSettingsWindow->size();
             if(ptLeftTop.x() + sizeSettingsWindow.width() > rectWorkArea.right())
              ptLeftTop.setX(rectWorkArea.right() - sizeSettingsWindow.width());
             m_pSettingsWindow->move(ptLeftTop);
            posted @ 2013-02-06 10:00 米米 閱讀(331) | 評論 (0)編輯 收藏

            看《C++必知必會》比看《C++編程思想》編程思想有趣多了,《C++編程思想》是為C程序員寫的,而我基本上一來就直接學的C++,因而《C++編程思想》并不適合我。而《C++必知必會》是直接從實際出發,直接點出來在編程中遇到的各種問題,因而很是實用,深得我心。  
            1.數據結構 
            摘要:為類型選擇一個描述性名字。如果難以為這個類型命名,那就說明你還不知道你想要實現什么。 
            評:很是精辟,每當我想到了這個類的名字,我就知道了如何去做和做些什么。摘要:列舉類型所能執行的操作。......要避免在實現時簡單地為數據成員提供一串get/set操作——那不叫做數據抽象而是懶惰且缺乏想象力的表現。 
            評:不太明白,在我看來,C++中的類型僅僅是把數據按照一定的規律(類型)進行封裝,其目的就是為了進行數據之間的交換。我的確不僅僅是用了一串get/set操作,但不是的操作也僅僅比get/set有一點延伸,比如按照某個條件來get/set一個或一組數據。 
             2.多態 
            摘要:基類可以不知道除自身以外的任何事物。 
            評:很是恰當,基類可以看成派生類的接口,派生類可以看成是基類的實現。 
             3.設計模式 
            摘要:一旦設計完成后,甚至你的經理都能夠理解完整的設計方案,只要他具備一些必需的模式方面的知識。 
            評:以前我一直沒有看過關于設計模式方面的書,也不理解什么是設計模式和為什么需要設計模式。現在,通俗的話說設計模式是程序員之間的“黑話”,它與使用的平臺、語言毫無關系,它指的是你在制作程序時的一種構想或方法,而這些構造方法都是大家熟知的、經過驗證的、有效的、高效率的。  
            4.STL  
            摘要:STL包含三大組件:容器、算法和迭代器。......STL的優秀思想體現在:容器與在容器上執行的算法之間無需彼此了解,這種戲法是通過迭代器實現的。 
            評:上面已經很好的解釋了什么是STL了,而且還道出了C++中的精髓,無需彼此了解,不是侵入式的設計,還象那個基類、派生類。 
             5.引用 
            評:我只會把引用用在函數形參上,一般還給它加上一個const,其他的地方么,我一般使用指針。 
             6.數組形參 
            摘要:數組在傳入時,實質上只傳入指向其首元素的指針。 
            評:要小心!書中用一個準確的詞“退化“來描述這種狀況。不過自從我使用了vector后也就找不出什么理由使用數組了。我很高興是這樣的結果。什么,你說你一定要用多維數組,那么我說,你去死吧,我一般用一維代替多維,或者使用vector進行鑲套。  
            7.產量指針和指向產量的指針 
            評:我背下了一個簡單的方法來區別這兩個。我把*和它前面的作為一組,*后面的作為一組,如const T *ptr,讀后面的部分,ptr是指針,指向const T,又如T *const ptr,讀為一個const指針,指向T類型。不過話說回來,我一直沒有用過,也還沒有想到使用的理由。  
            8.指向指針的指針 
            評:對這一點我一直提不起興趣,討厭這么復雜的冬冬。不過在實際中漸漸明白。如 vector my_circle; vector::iterator p=my_circle.begin(); for(;p!=my_circle.end();p++) {(*p)->draw();}  
            9.新式轉型操作符 
            摘要:更丑陋,更難用,并且威力較小。 
            評:看到了這一章,我心里面咯噔了一下。我的程序里面還有那么野蠻的、不講理的轉換。我得盡快用這種更丑陋的方式去改過來,以減少錯誤的可能性。要注意static_const和dynamic_cast;  
            10.常量成員函數含義 
            摘要: 
            class X{  
            Public: void modify_buffer(int index,int val) const //不德!!!!!! { Buffer[index] = val;} Private: int *buffer; };  
            評:的確是不道德的,const的函數偷偷的改了一個數據,沒有發現因為沒有修改class X中的對象。我得小心了,不干這種事情。 
             11.編譯器會在類中放東西 
            摘要:如果一個類聲明了一個或多個虛函數,那么編譯器將會為該類的每一個對象插入一個指向虛函數表的指針。 
            摘要:如果使用了虛擬繼承,對象將會通過嵌入的指針、嵌入的偏移或其他的信息來保持對其虛基類子對象位置的跟蹤。 
            摘要:一個POD(“plain old data”)非常重要。比如int、double、C struct、union都是POD。摘要:如果希望復制一個類對象,那么永遠都不要使用memcpy這樣的標準內存塊復制函數。......相反,應該使用對象的初始化或者賦值操作。 
            評:看到最后這條我才明白為何有這章。看來對于高層的東西要使用高層的操作。  
            12.賦值和初始化并不相同 
            摘要:直截了當的說,賦值發生于當你賦值時,除此之外遇到的所有其他的復制情況均為初始化,包括聲明,函數返回,參數傳遞以及捕俘描述異常中的初始化。 
            評:突然想起鼻祖書中的話,賦值是對一個結構良好的存儲區去做,而初始化是對一個未定義的存儲區去做。如果要賦值,那么就確立一下賦值的對象是否還是磁盤上的荒蕪地帶。  
            13.復制操作  
            摘要:復制構造和復制賦值是兩種不同的操作。  
            14.函數指針 
            摘要:將一個函數的地址初始化或賦值給一個指向函數的指針時,無需顯示的取得函數地址。 
            例子:void (*fp)(int);  
            extern void h(int);  
            fp = h; //OK  
            fp = &h; //OK  
            摘要:為了調用函數指針所指向的函數,而對指針進行解引用操作也是不必要的。 
            例子:(*fp)(12); //顯示調用  
            fp(12); //隱式調用 
            摘要:函數指針的一個傳統用途是實現回調(callback)。 
            評:一個很好的例子就是windows中對左右手的變化,如果改變了就只需要交換一下函數指針就OK了。  
            15.指向類成員的指針并非指針 
            摘要:“指向類成員的指針”即不包含地址,行為也不像指針。通常看作一個偏移量。 
            摘要:指向數據成員的指針對于描述“逆變性”的概念很方便。 
            摘要:存在指向基類成員的指針到指向公有派生類成員的指針隱式轉換,反之不行。 
            評:明白了它的作用卻不知道哪里有用,完全可以換個方式使用,即使是為了上一章的回調。如果要得到類中的成員,完全可以用類的對象或指向類對象的指針獲得,這個可能是為了C程序員吧。 
             tip:不能想著指向static成員,它們并不是存在于所有類對象的一個偏移量。使用的方式和普通的數據一樣。  
            16.指向成員函數的指針并非指針  
            摘要:NULL  
            17.處理函數和數組聲明 
            摘要: 
            int *f1(); //一個返回值為int *的函數 
             int (*fp1)(); //一個指針,指向一個返回值為int的函數  
            int *a1[N]; //一個具有N個int *元素的數組  
            int (*ap1)[N]; //一個指針,指向一個具有N個int元素的數組 
            評:夠復雜吧,不過看了下面的就要。。。。。。  
            摘要: int(*af2[N])(); //一個具有N個元素的數組  
            //其元素類型指向返回值為int的函數指針 
            評:夠嚇人的,雖然有解決法子可我沒在意。因為老早就決定不用數組了。 
             18.函數對象 
            摘要:函數對象也是一個普通的類對象,通過重載函數調用操作符()來創建類似于函數指針的東西。 
            評:這可是個好東西,在泛型算法中作為謂詞。 
             19.Command模式與好萊塢法則 
            摘要:好萊塢法則即“不要call我們,我們會call你”。 
            摘要:將一個函數對象于好萊塢法則相結合,即為Command模式的一個實例。 
            摘要:好處是,函數對象可以封裝數據,另一個好處是函數對象可以通過虛擬成員表現出動態行為,第三個好處是處理類層次結構而不是較為原始的,缺乏靈活性的結構(例如函數指針)。  
            20.STL函數參數 
             摘要:NULL 
             21.重載與重寫并不相同 
            摘要:重載發生于同一個作用域內有兩個或更多個函數具有相同的名字但簽名不同時。 
            摘要:重寫發生于派生類函數和基類有相同的的名字和簽名時。  
            22.Template Method 模式 
            摘要: Template Method(模板方式)模式和C++模板一點關系都沒有。實際上,它是基類設計者為派生類設計者提供清晰指示的一種方式,這個指示就是“應該如何實現基類所規定的契約”。 
            摘要:一個基類的成員函數是否應該為非虛擬的、虛擬的或純虛擬的,這樣的決策主要是基于該函數的行為如何被派生類定制。 
            摘要:如果基類成員是非虛擬的,那么基類設計者就是以該基類為所確立的層次結構指明了一個不變式。派生類不應該用同名的派生類成員去隱藏基類非虛函數。 
            摘要:虛函數和純虛函數指定的操作,其實現可以由派生類通過重寫機制定制。一個非純虛函數提供了一個默認實現,并不強迫派生類一定要重寫它,而一個純虛函數則必須在具體派生類中進行重寫。 
            評:這一章對于我們如何定義基類有了一個很好的說明。函數是具體的實現,而我們確定如何具體的實現函數。 
             Tip:另外有一種派生類作為基類接口的形式,那里的法則就不太一樣了。基類是實現,派生類是為了給其他用戶的接口。  
            23.名字空間  
            摘要:本質上,名字空間是對全局作用域的細分。 
            摘要:許多C++程序員建議將using指令放在全局作用域中,這是個餿注意。 
            評:一定要很好的區分什么是using指令和using聲明。  
            Using namespace namespace_name //是指令  
            Using anamespace_name::名字空間聲明的的東西 //是聲明 
            如果在全局作用域中使用using指令那等于去掉了名字空間的作用域。這里一般指的是程序員自己定義的名字空間,不是默認的std。  
            24.成員函數查找 
            摘要:調用一個成員函數時,涉及三個步驟:第一步,編譯器查找函數的名字;第二步,從可用候選者中選取最佳匹配函數;第三步,檢查是否具有訪問該匹配函數是權限; 
            評:這里面隱含的說了一個冬冬,如果編譯器找到了函數的名字,它是不會再去找的了。如果無權限范圍該函數,那么就會在第三步出現編譯錯誤。  
            25.實參相依的查找 
            摘要:ADL(實參相依的查找)指的是,當查找一個函數調用表達式中的函數名字時,編譯器也會到“包含函數調用實參的類型”的名字空間查找。 
            評:我卻好像記得不止是名字空間,也包括class,因為class其實也是一種特殊的名字空間。回頭還得再看一遍鼻祖的書,那里面其實都有,只是沒有重點標出來而已。  
            26.操作符函數查找 
            摘要:當使用函數調用語法時,應用的是普通的查找規則(ADL)。而對重載操作符的中綴調用的處理機制不同。 
            例子: 
            class X{ X operator%(const X&)const;};  
            X x,y;  
            x % y; //中綴調用 
             x.operator%(y); //成員函數調用 
            摘要:對于中綴操作符調用來說,編譯器不僅會考慮成員操作符,也會考慮非成員操作符。 
            評:說的有點讓人迷糊。我想主要注意使用.operator時,記得有個默認的*this實參。  
            27.能力查詢 
            摘要:能力查詢只是偶爾需要,但它們往往被過渡使用。它們通常是糟糕設計的“指示器”。最好避免對一個對象的能力進行運行期查詢。 
            評:能力查詢指的是對一個類對象進行dynamic_cast,來知道它是否是另外的類型,通常,是橫向轉換而不是普通的向上或者向下。  
            28.指針比較的含義 
            摘要:指針比較不是關于地址的問題,而是關于對象同一性的問題。 
            摘要:一個非常重要的經驗,處理指向對象的引用或指針時,必須小心避免丟失類型信息(如把指針賦值給void*指針)。 
            評:一個基類的指針是與其派生類的指針==的,并不是因為地址相同而是類型相同,因為派生類就是基類,就像班長就是學生一樣。這里比較的是基類的類型。  
            29.虛構造函數與Prototype模式 
            評:構造函數是不能虛的,而這里指的是具有這樣功能的函數。如在一個類中,我們使用一個成員函數clone來調用復制構造函數new X(*this),我的經驗無法告訴我為何需要,不過有一點是很明確的,這個例子證明了軟件設計的“不知情”模式。  
            30.Factory Method模式 
            評:一個沉重的打擊,我在28、29看見了什么是比較高級的構架,也讓我想起了別來call我,需要時我來call你的好萊塢模式。每個類都明白自己做什么,而你只是在問它們一個很大眾的問題,而不是很私人的問題。重點推薦,我得好好看看,認真感受。如果能很明確的使用,我的認識將能夠上一個檔次。  
            31.協變返回類型 
            摘要:協變的優勢在于,總是可以在適當程度的抽象層工作。如果我們是處理Shape,獲得一個抽象的ShapeEditor;如果在處理某種具體的形狀類型,比如Circle,我們就可以直接獲得CircleEditor。協變機制使得我們可以不使用類型轉換操作來“重新”提供類型信息,而這種信息是一開始就不應該丟掉的。  
            32.禁止復制 
            摘要:訪問修飾符(public、protect、private)可以用于表達和執行高級約束技術,指明一個類可以被怎樣使用。這些技術中最常見的一種是不接受對象的復制操作,這是通過將其復制操作聲明為private同時不為之提供定義而做到的。 
            評:有時候我們應該把所有不想給其他人使用的函數全部放進private。 
             (因為后面的比較深,暫時作罷。勉強看也只能懂個浮淺的東西。未完待續)  
            posted @ 2013-01-21 17:22 米米 閱讀(308) | 評論 (0)編輯 收藏

            一個正則表達式就是由普通字符(例如字符 a 到 z)以及特殊字符(稱為元字符)組成的文字模式。該模式描述在查找文字主體時待匹配的一個或多個字符串。正則表達式作為一個模板,將某個字符模式與所搜索的字符串進行匹配。

            這里有一些可能會遇到的正則表達式示例:

            Visual Basic Scripting Edition VBScript 匹配
            /^\[ \t]*$/ "^\[ \t]*$" 匹配一個空白行。
            /\d{2}-\d{5}/ "\d{2}-\d{5}" 驗證一個ID 號碼是否由一個2位數字,一個連字符以及一個5位數字組成。
            /<(.*)>.*<\/\1>/ "<(.*)>.*<\/\1>" 匹配一個 HTML 標記。

            下表是元字符及其在正則表達式上下文中的行為的一個完整列表:

            字符 描述
            \ 將下一個字符標記為一個特殊字符、或一個原義字符、或一個 后向引用、或一個八進制轉義符。例如,'n' 匹配字符 "n"。'\n' 匹配一個換行符。序列 '\\' 匹配 "\" 而 "\(" 則匹配 "("。
            ^ 匹配輸入字符串的開始位置。如果設置了 RegExp 對象的 Multiline 屬性,^ 也匹配 '\n' 或 '\r' 之后的位置。
            $ 匹配輸入字符串的結束位置。如果設置了RegExp 對象的 Multiline 屬性,$ 也匹配 '\n' 或 '\r' 之前的位置。
            * 匹配前面的子表達式零次或多次。例如,zo* 能匹配 "z" 以及 "zoo"。 * 等價于{0,}。
            + 匹配前面的子表達式一次或多次。例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等價于 {1,}。
            ? 匹配前面的子表達式零次或一次。例如,"do(es)?" 可以匹配 "do" 或 "does" 中的"do" 。? 等價于 {0,1}。
            {n} n 是一個非負整數。匹配確定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的兩個 o。
            {n,} n 是一個非負整數。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等價于 'o+'。'o{0,}' 則等價于 'o*'。
            {n,m} mn 均為非負整數,其中n <= m。最少匹配 n 次且最多匹配 m 次。劉, "o{1,3}" 將匹配 "fooooood" 中的前三個 o。'o{0,1}' 等價于 'o?'。請注意在逗號和兩個數之間不能有空格。
            ? 當該字符緊跟在任何一個其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面時,匹配模式是非貪婪的。非貪婪模式盡可能少的匹配所搜索的字符串,而默認的貪婪模式則盡可能多的匹配所搜索的字符串。例如,對于字符串 "oooo",'o+?' 將匹配單個 "o",而 'o+' 將匹配所有 'o'。
            . 匹配除 "\n" 之外的任何單個字符。要匹配包括 '\n' 在內的任何字符,請使用象 '[.\n]' 的模式。
            (pattern) 匹配pattern 并獲取這一匹配。所獲取的匹配可以從產生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在Visual Basic Scripting Edition 中則使用 $0$9 屬性。要匹配圓括號字符,請使用 '\(' 或 '\)'。
            (?:pattern) 匹配 pattern 但不獲取匹配結果,也就是說這是一個非獲取匹配,不進行存儲供以后使用。這在使用 "或" 字符 (|) 來組合一個模式的各個部分是很有用。例如, 'industr(?:y|ies) 就是一個比 'industry|industries' 更簡略的表達式。
            (?=pattern) 正向預查,在任何匹配 pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如, 'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始。
            (?!pattern) 負向預查,在任何不匹配Negative lookahead matches the search string at any point where a string not matching pattern 的字符串開始處匹配查找字符串。這是一個非獲取匹配,也就是說,該匹配不需要獲取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。預查不消耗字符,也就是說,在一個匹配發生后,在最后一次匹配之后立即開始下一次匹配的搜索,而不是從包含預查的字符之后開始
            x|y 匹配 xy。例如,'z|food' 能匹配 "z" 或 "food"。'(z|f)ood' 則匹配 "zood" 或 "food"。
            [xyz] 字符集合。匹配所包含的任意一個字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。
            [^xyz] 負值字符集合。匹配未包含的任意字符。例如, '[^abc]' 可以匹配 "plain" 中的'p'。
            [a-z] 字符范圍。匹配指定范圍內的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范圍內的任意小寫字母字符。
            [^a-z] 負值字符范圍。匹配任何不在指定范圍內的任意字符。例如,'[^a-z]' 可以匹配任何不在 'a' 到 'z' 范圍內的任意字符。
            \b 匹配一個單詞邊界,也就是指單詞和空格間的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。
            \B 匹配非單詞邊界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。
            \cx 匹配由x指明的控制字符。例如, \cM 匹配一個 Control-M 或回車符。 x 的值必須為 A-Z 或 a-z 之一。否則,將 c 視為一個原義的 'c' 字符。
            \d 匹配一個數字字符。等價于 [0-9]。
            \D 匹配一個非數字字符。等價于 [^0-9]。
            \f 匹配一個換頁符。等價于 \x0c 和 \cL。
            \n 匹配一個換行符。等價于 \x0a 和 \cJ。
            \r 匹配一個回車符。等價于 \x0d 和 \cM。
            \s 匹配任何空白字符,包括空格、制表符、換頁符等等。等價于 [ \f\n\r\t\v]。
            \S 匹配任何非空白字符。等價于 [^ \f\n\r\t\v]。
            \t 匹配一個制表符。等價于 \x09 和 \cI。
            \v 匹配一個垂直制表符。等價于 \x0b 和 \cK。
            \w 匹配包括下劃線的任何單詞字符。等價于'[A-Za-z0-9_]'。
            \W 匹配任何非單詞字符。等價于 '[^A-Za-z0-9_]'。
            \xn 匹配 n,其中 n 為十六進制轉義值。十六進制轉義值必須為確定的兩個數字長。例如, '\x41' 匹配 "A"。'\x041' 則等價于 '\x04' & "1"。正則表達式中可以使用 ASCII 編碼。.
            \num 匹配 num,其中 num 是一個正整數。對所獲取的匹配的引用。例如,'(.)\1' 匹配兩個連續的相同字符。
            \n 標識一個八進制轉義值或一個后向引用。如果 \n 之前至少 n 個獲取的子表達式,則 n 為后向引用。否則,如果 n 為八進制數字 (0-7),則 n 為一個八進制轉義值。
            \nm 標識一個八進制轉義值或一個后向引用。如果 \nm 之前至少有is preceded by at least nm 個獲取得子表達式,則 nm 為后向引用。如果 \nm 之前至少有 n 個獲取,則 n 為一個后跟文字 m 的后向引用。如果前面的條件都不滿足,若  nm 均為八進制數字 (0-7),則 \nm 將匹配八進制轉義值 nm
            \nml 如果 n 為八進制數字 (0-3),且 ml 均為八進制數字 (0-7),則匹配八進制轉義值 nml。
            \un 匹配 n,其中 n 是一個用四個十六進制數字表示的 Unicode 字符。例如, \u00A9 匹配版權符號 (?)。
            posted @ 2012-10-23 11:03 米米 閱讀(300) | 評論 (0)編輯 收藏

            this->tableView->horizontalHeader()->setStyleSheet("QHeaderView::section {background-color:darkcyan;"
                                                                   "color: black;padding-left: 4px;border: 1px solid #6c6c6c;}");


            this->tableView->verticalHeader()->setStyleSheet("QHeaderView::section {background-color:darkcyan;"
                                                                 "color: black;padding-left: 4px;border: 1px solid #6c6c6c;}");

             

            以下好看的樣式來自于http://blog.csdn.net/zenwanxin/article/details/6524559

            tableView->horizontalHeader()->setStyleSheet

            ("QHeaderView::section {background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,"

            "stop:0 #616161, stop: 0.5 yellow,stop: 0.6 green, stop:1 cyan);"
            "color: white;padding-left: 4px;border: 1px solid #6c6c6c;}"
            "QHeaderView::section:checked{background-color: red;}"
            "QHeaderView::down-arrow {image: url(down_arrow.png);}"
            "QHeaderView::up-arrow {image: url(up_arrow.png);}");

            posted @ 2012-09-05 21:36 米米 閱讀(5613) | 評論 (0)編輯 收藏

                 摘要: 一、基礎 1、說明:創建數據庫 CREATE DATABASE database-name 2、說明:刪除數據庫 drop database dbname 3、說明:備份sql server --- 創建 備份數據的 device USE master EXEC sp_addumpdevice 'disk', 'testBack', 'c:\mssql7backup\MyNwind_1.dat...  閱讀全文
            posted @ 2012-08-30 09:43 米米 閱讀(306) | 評論 (0)編輯 收藏

            方案一:使用paintEvent
            C/C++ code
            void Widget::paintEvent(QPaintEvent *e)
            { QPainter painter(this);
             painter.drawPixmap(0,0,this->width(),this->height(),QPixmap(":/xxx.png"));
             }


            方案二:使用setStyleSheet
            C/C++ code
            widget->setStyleSheet("border-image: url(:/xxx.png)");
            posted @ 2012-08-28 10:56 米米 閱讀(1845) | 評論 (0)編輯 收藏

            僅列出標題
            共8頁: 1 2 3 4 5 6 7 8 
            99久久精品国产一区二区蜜芽| 日韩精品无码久久一区二区三| 精品伊人久久久| 精品久久久久成人码免费动漫| 久久久久久久久久久| 国产精品久久久久久久| 99久久国产综合精品成人影院| 久久精品免费全国观看国产| 久久久99精品成人片中文字幕| 欧美精品一区二区久久| 久久精品国产久精国产思思| 国产叼嘿久久精品久久| 亚洲国产精品高清久久久| 久久国产精品成人免费| 国内精品久久久久久久久电影网| 亚洲国产精品婷婷久久| 亚洲色大成网站WWW久久九九| 久久久精品国产亚洲成人满18免费网站| 久久无码国产专区精品| 久久精品免费大片国产大片| 97久久超碰成人精品网站| 亚洲中文字幕久久精品无码喷水 | 久久99热这里只有精品66| 久久国产精品99精品国产987| 77777亚洲午夜久久多喷| 久久精品国产WWW456C0M| 亚洲国产精品一区二区久久| 久久99精品国产麻豆| 久久天天躁狠狠躁夜夜96流白浆 | 久久亚洲中文字幕精品一区| 国产亚洲成人久久| 99久久无码一区人妻a黑| 午夜精品久久久久久99热| 亚洲午夜久久久| 九九精品久久久久久噜噜| 久久99热这里只频精品6| 亚洲精品久久久www| 久久亚洲精品成人无码网站| yy6080久久| 久久久精品人妻一区二区三区蜜桃 | 色8激情欧美成人久久综合电|