国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

QTabWidget的tabbar不同方向顯示 文字方向設(shè)置 圖標(biāo)跟隨變化 實現(xiàn)方式 qt控件繪制原理

這篇具有很好參考價值的文章主要介紹了QTabWidget的tabbar不同方向顯示 文字方向設(shè)置 圖標(biāo)跟隨變化 實現(xiàn)方式 qt控件繪制原理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

先來看結(jié)果圖:(參考博客:QTabWidget中tab頁文本水平或垂直設(shè)置_pyqt tab_widget.settabposition(qtabwidget.west) 字體-CSDN博客)

qt tabwidget標(biāo)簽豎直,文字水平,qt,開發(fā)語言,qtabwidget,qtabbar

從圖中可知,"普通"是qt自己的樣式,但是很明顯,在垂直方向tab時候,字體也跟著垂直了,不太利于閱讀,而第3個tab,則是將文字給正著顯示過來了,第5個圖,更是直接將文字也水平放置過來了,都是做了改進(jìn)。但是仍然存在個問題,例如tab3,圖標(biāo)卻仍然是反著的,不太好看,所以,如何解決這個問題?效果圖如下:

qt tabwidget標(biāo)簽豎直,文字水平,qt,開發(fā)語言,qtabwidget,qtabbar

我們需要來研究一下QTabBar繪制的原理,然后編寫相關(guān)代碼進(jìn)行實現(xiàn)。

QTabBar繪制原理

QTabBar繪制過程,函數(shù)調(diào)用層級大概如下:

說明:一般的繪制簡單控件,線條,路徑,圖片啥的,就是在paintEvent函數(shù)里直接調(diào)用painter的drawText函數(shù),drawPixmap函數(shù)等,?繪制就可以了,但是繪制復(fù)雜一些的qt自己的控件,是通過創(chuàng)建一個QStylePainter 繪制控件專用對象,QStylePainter stylePainter里有個drawControl成員函數(shù)進(jìn)行繪制的,而該函數(shù)需要傳入繪制的控件類型(也叫element,例如tab頭、pushbutton、listview等),然后里面調(diào)用 其擁有的成員QStyle對象 的 專用繪制方法void drawControl(QStyle::ControlElement element, const QStyleOption *option,? ?QPainter *painter, const QWidget *widget = nullptr) const;進(jìn)行繪制。

這里面就有幾個是虛函數(shù),即我們可以子類化這些類重寫這些函數(shù),實現(xiàn)定制化功能:

  1. 子類化該控件類,重寫?paintEvent(QPaintEvent * painter)函數(shù)
  2. 子類化QStyle,重寫drawControl函數(shù)

paintEvent(QPaintEvent * painter)?

  1. QStylePainter stylePainter(this);

  2. QStyleOptionTab opt;

  3. initStyleOption(&opt,i); //初始化,將opt賦值為繪制時候所需要的信息,例如文本內(nèi)容,線寬,尺寸大小等信息
  4. 這里可以設(shè)置一下畫筆stylePainter的一些屬性,例如繪制位置,旋轉(zhuǎn)情況,顏色等
  5. stylePainter.drawControl(QStyle::CE_TabBarTabLabel,opt); //指定繪制對應(yīng)的元素(tab文字和圖標(biāo)內(nèi)容),以及繪制需要的細(xì)節(jié)信息
  6. stylePainter.drawControl(QStyle::CE_TabBarTabShape, opt);//指定繪制對應(yīng)的元素(tab形狀),以及繪制需要的細(xì)節(jié)信息

所以有了以上繪制原理的認(rèn)識,接下來就是如何實現(xiàn)tabbar不同方向時,圖標(biāo)和文字同樣能正著顯示了。此外,qt其它控件的繪制,也是同樣道理,以后我們都可以定制化實現(xiàn)或者魔改已有的控件了。

注:QStyle在qt中,已經(jīng)有各種現(xiàn)成的子類了,QStyle <-?QCommonStyle <-?QProxyStyle

代碼實現(xiàn)

這里僅僅舉幾個例子,因為原理明白了,就可以自己定制化實現(xiàn)了。

例1:實現(xiàn)圖5:tab在左側(cè),但是tab文字水平

注:設(shè)置tab的方向,可以在UI設(shè)計時候直接設(shè)置了,也可以tabwidget的設(shè)置tab方向函數(shù)進(jìn)行設(shè)置,然后tab頭就是改變方向了的。

這個有兩種實現(xiàn)方法

  1. 子類化?QTabBar ,重寫?paintEvent(QPaintEvent *) 函數(shù),里面調(diào)用?drawControl 前,修改掉?stylePainter 的方向為旋轉(zhuǎn)90度即可(因為默認(rèn)的drawControl(QStyle::CE_TabBarTabLabel,opt)函數(shù)里面會再次旋轉(zhuǎn)90讀的),此外,重寫tabSizeHint(int index),返回該tab的大小也要跟著旋轉(zhuǎn)一下的,即?QSize.transpose(); 可以參考博客:Qt tabWidget設(shè)置tab左右顯示時 文字橫向顯示_qtabwidget標(biāo)簽文字橫向-CSDN博客
  2. 子類化QStyle,重寫drawControl函數(shù)。因為,控件的實際繪制是交給QStyle來完成的,所以我們就重寫它的drawControl函數(shù)即可。然后把子類化的QStyle對象設(shè)置到目標(biāo)控件中去即可(setStyle()函數(shù)實現(xiàn))。可以參考最開始那個博客:(就是將每個字符后面加一個\n 換行符,從而實現(xiàn)一個垂直的qstring,然后畫筆將文本直接正著畫上去即可)QTabWidget中tab頁文本水平或垂直設(shè)置_pyqt tab_widget.settabposition(qtabwidget.west) 字體-CSDN博客

備注:QSize sizeFromContents函數(shù)是內(nèi)容顯示的尺寸控制功能,比如我們可以額外增加一些size加進(jìn)去,但是可以的。void drawItemText函數(shù)是繪制文本的集成化函數(shù),我們也可以重新實現(xiàn)它,實現(xiàn)

例2:實現(xiàn)目標(biāo)效果圖:tab在左側(cè),tab文字垂直正著的,且圖標(biāo)也是正著的(也就是我們目標(biāo)效果圖)

唯一方法,子類化QStyle,重寫drawControl函數(shù)。因為此時需要文字方向是豎直的,但是又是正的,是沒法通過旋轉(zhuǎn)畫筆的方式直接來繪制實現(xiàn)。所以只能是重寫QStyle的drawControl函數(shù)。

原理:文本的每一個字符后面加一個換行符,從而實現(xiàn)豎直方向的字符串。但是需要先繪制icon,然后y方向平移一下畫筆,繼續(xù)繪制處理好的字符串即可。

這里有幾個要點:

  1. 傳入的const QStyleOption *opt?,可以強(qiáng)轉(zhuǎn)為?const QStyleOptionTab *tab,然后就能獲得tab->rect,tab->text,tab->shape等信息,而tab->shape是能知道當(dāng)前tab是水平的還是垂直的了。(查看qt的QTabBar控件源碼得知,所以不知道怎么實現(xiàn)時候可以去看看qt的源碼,很多問題就一目了然了
  2. 具體實現(xiàn)該函數(shù)時,直接從qt源碼實現(xiàn)里拷貝過來吧,然后自己修改指定地方,實現(xiàn)自己功能即可。

核心代碼如下:(在第一個博客基礎(chǔ)上,替換掉TabBarStyle.cpp文件內(nèi)容即可編譯運行?QTabWidget中tab頁文本水平或垂直設(shè)置_pyqt tab_widget.settabposition(qtabwidget.west) 字體-CSDN博客)文章來源地址http://www.zghlxwxcb.cn/news/detail-852261.html

#include "TabBarStyle.h"
#include <QPainter>
#include <QStyleOptionTab>
#include <QDebug>

//拷貝的qt源碼,不然下面有的函數(shù)調(diào)用該函數(shù)會報錯
static QWindow *qt_getWindow(const QWidget *widget)
{
    return widget ? widget->window()->windowHandle() : nullptr;
}

TabBarStyle::TabBarStyle()
    : QProxyStyle()
{
    // m_orientation = orientation;
}

//拷貝的qt源碼,不然下面有的函數(shù)調(diào)用該函數(shù)會報錯
void TabBarStyle::tabLayout(const QStyleOptionTab *opt, const QWidget *widget, QRect *textRect, QRect *iconRect) const
{
    Q_ASSERT(textRect);
    Q_ASSERT(iconRect);
    QRect tr = opt->rect;
    bool verticalTabs = opt->shape == QTabBar::RoundedEast
                        || opt->shape == QTabBar::RoundedWest
                        || opt->shape == QTabBar::TriangularEast
                        || opt->shape == QTabBar::TriangularWest;
    if (verticalTabs)
        tr.setRect(0, 0, tr.height(), tr.width()); // 0, 0 as we will have a translate transform
    
    int verticalShift = pixelMetric(QStyle::PM_TabBarTabShiftVertical, opt, widget);
    int horizontalShift = pixelMetric(QStyle::PM_TabBarTabShiftHorizontal, opt, widget);
    int hpadding = pixelMetric(QStyle::PM_TabBarTabHSpace, opt, widget) / 2;
    int vpadding = pixelMetric(QStyle::PM_TabBarTabVSpace, opt, widget) / 2;
    if (opt->shape == QTabBar::RoundedSouth || opt->shape == QTabBar::TriangularSouth)
        verticalShift = -verticalShift;
    tr.adjust(hpadding, verticalShift - vpadding, horizontalShift - hpadding, vpadding);
    bool selected = opt->state & QStyle::State_Selected;
    if (selected) {
        tr.setTop(tr.top() - verticalShift);
        tr.setRight(tr.right() - horizontalShift);
    }
    
    // left widget
    if (!opt->leftButtonSize.isEmpty()) {
        tr.setLeft(tr.left() + 4 +
                   (verticalTabs ? opt->leftButtonSize.height() : opt->leftButtonSize.width()));
    }
    // right widget
    if (!opt->rightButtonSize.isEmpty()) {
        tr.setRight(tr.right() - 4 -
                    (verticalTabs ? opt->rightButtonSize.height() : opt->rightButtonSize.width()));
    }
    
    // icon
    if (!opt->icon.isNull()) {
        QSize iconSize = opt->iconSize;
        if (!iconSize.isValid()) {
            int iconExtent = pixelMetric(QStyle::PM_SmallIconSize, opt);
            iconSize = QSize(iconExtent, iconExtent);
        }
        QSize tabIconSize = opt->icon.actualSize(iconSize,
                                                 (opt->state & QStyle::State_Enabled) ? QIcon::Normal : QIcon::Disabled,
                                                 (opt->state & QStyle::State_Selected) ? QIcon::On : QIcon::Off);
        // High-dpi icons do not need adjustment; make sure tabIconSize is not larger than iconSize
        tabIconSize = QSize(qMin(tabIconSize.width(), iconSize.width()), qMin(tabIconSize.height(), iconSize.height()));
        
        const int offsetX = (iconSize.width() - tabIconSize.width()) / 2;
        *iconRect = QRect(tr.left() + offsetX, tr.center().y() - tabIconSize.height() / 2,
                          tabIconSize.width(), tabIconSize.height());
        if (!verticalTabs)
            *iconRect = QStyle::visualRect(opt->direction, opt->rect, *iconRect);
        tr.setLeft(tr.left() + tabIconSize.width() + 4);
    }
    
    if (!verticalTabs)
        tr = QStyle::visualRect(opt->direction, opt->rect, tr);
    
    *textRect = tr;
}


TabBarStyle::~TabBarStyle()
{
}

void TabBarStyle::drawControl(ControlElement element, const QStyleOption *opt,
                              QPainter *p, const QWidget *widget) const
{
    // 步驟一:調(diào)用父類的繪制 tab 的其它控件,即其它空間都按照默認(rèn)繪制即可
    if (element != CE_TabBarTabLabel)
        QProxyStyle::drawControl(element, opt, p, widget);

#if 1
    // 步驟二:定制化 繪制tab標(biāo)簽頁文本,以及圖標(biāo)
    if (element == CE_TabBarTabLabel)
    {
        if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
            QRect tr = tab->rect;
            bool verticalTabs = tab->shape == QTabBar::RoundedEast
                                || tab->shape == QTabBar::RoundedWest
                                || tab->shape == QTabBar::TriangularEast
                                || tab->shape == QTabBar::TriangularWest;
            
            int alignment = Qt::AlignCenter | Qt::TextShowMnemonic;
            if (!proxy()->styleHint(SH_UnderlineShortcut, opt, widget))
                alignment |= Qt::TextHideMnemonic;
            
            if (verticalTabs) {
                p->save();
                
                QTransform m1 = QTransform::fromTranslate(tr.x()-8, tr.y()+5);
                p->setTransform(m1);
            }
            
            //自己控制繪制tab的 文本,icon
            //原本:west:文本(上方)+icon(下方),且文字和ico方向不對。east:icon(上方)+文本(下方),且文字和ico方向不對
            //目標(biāo):west:icon(上方)+文本(下方),且文字和ico方向正確。east:同理
            QRect iconRect;
            tabLayout(tab, widget, &tr, &iconRect);
            tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget); //we compute tr twice because the style may override subElementRect
            
            if (!tab->icon.isNull()) {
                QPixmap tabIcon = tab->icon.pixmap(qt_getWindow(widget), tab->iconSize,
                                                   (tab->state & State_Enabled) ? QIcon::Normal
                                                                                : QIcon::Disabled,
                                                   (tab->state & State_Selected) ? QIcon::On
                                                                                 : QIcon::Off);
                p->drawPixmap(iconRect.x(), iconRect.y(), tabIcon);
            }
            
            if (verticalTabs)
                p->restore();
            
            QString tabText;
            if (verticalTabs)
            {
                if (verticalTabs)
                    p->save();
                
                p->resetTransform();
                QTransform m1 = QTransform::fromTranslate(0, 5);
                p->setTransform(m1);
                
                // 將文本字符串換行處理
                for (int i = 0; i < tab->text.length(); i++)
                {
                    tabText.append(tab->text.at(i));
                    tabText.append('\n');
                }
                if (tabText.length() > 1)
                    tabText = tabText.mid(0, tabText.length() - 1);
            }
            else
                tabText = tab->text;
            
            if(verticalTabs)
                //注:這里傳入的繪制區(qū)域,寫的是 tab->rect,正確來說,不應(yīng)該是這個區(qū)域,而是tr,即上面subElementRect(SE_TabBarTabText)
                //但是用tr顯示不了,tr旋轉(zhuǎn)一下也顯示不了,當(dāng)然,直接用tab->rect也就可以搞定的,但是其對齊方式作用就是
                //從tab最頂部開始算的,這里還存在一丁點問題,但是也沒有什么明顯問題了,不再繼續(xù)研究了,這個不重要了
                proxy()->drawItemText(p, tab->rect, alignment, tab->palette, tab->state & State_Enabled, tabText, QPalette::WindowText);
            else
                proxy()->drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tabText, QPalette::WindowText);
                
            
            if (verticalTabs)
                p->restore();
            
            
            //qt本身源碼
            if (tab->state & State_HasFocus) {
                const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth);
                
                int x1, x2;
                x1 = tab->rect.left();
                x2 = tab->rect.right() - 1;
                
                QStyleOptionFocusRect fropt;
                fropt.QStyleOption::operator=(*tab);
                fropt.rect.setRect(x1 + 1 + OFFSET, tab->rect.y() + OFFSET,
                                   x2 - x1 - 2*OFFSET, tab->rect.height() - 2*OFFSET);
                drawPrimitive(PE_FrameFocusRect, &fropt, p, widget);
            }
        }
    }

#endif
}


QSize TabBarStyle::sizeFromContents(QStyle::ContentsType type, const QStyleOption *opt, const QSize &contentsSize, const QWidget *widget /*= nullptr*/) const
{
    if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt))
    {
        bool verticalTabs = tab->shape == QTabBar::RoundedEast
                            || tab->shape == QTabBar::RoundedWest
                            || tab->shape == QTabBar::TriangularEast
                            || tab->shape == QTabBar::TriangularWest;
        
        QString text = tab->text;
        int cnt = text.length()-1;
        
        QSize size = contentsSize;
        if (type == CT_TabBarTab)
        {
            if (verticalTabs)
            {
                size.rheight() += cnt*7;    //這是因為文本每個字符后加了換行符后,和水平擺放占據(jù)長度空間不一樣了
            }
        }
        
        // size.setWidth(size.width()-20);
        return size;
    }
    else
        return QProxyStyle::sizeFromContents(type, opt, contentsSize, widget);
}

到了這里,關(guān)于QTabWidget的tabbar不同方向顯示 文字方向設(shè)置 圖標(biāo)跟隨變化 實現(xiàn)方式 qt控件繪制原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包