欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt重寫QTreeView自繪實現(xiàn)酷炫樣式

 更新時間:2023年08月18日 08:32:02   作者:師從名劍山  
QTreeView,顧名思義,就是一種樹形的控件,在我們需要做類似于文件列表的視圖時,是一個不錯的選擇,下面我們就來看看qt如何重寫QTreeView實現(xiàn)酷炫樣式,感興趣的可以了解一下

導(dǎo)語

Hi,各位讀者朋友,大家好。相信大家在日常的工作中,經(jīng)常會接觸到QTreeView這個控件吧!

QTreeView,顧名思義,就是一種樹形的控件,在我們需要做類似于文件列表的視圖時,是一個不錯的選擇。然而,僅通過設(shè)置樣式表,往往無法完全滿足我們的需求。迫不得已,我們只能選擇自實現(xiàn)QTreeView的繪制事件,通過畫筆,逐個繪制我們想要的效果。

關(guān)于QTreeView的樣式表部分,Qt官方給出了一些示例:Customizing QTreeView , 本文不作具體介紹,感興趣的讀者可以自行觀看。

接下來,咱們通過一下幾個步驟,逐個分析,怎么達到上圖的效果。

  • 整個控件的背景色
  • 單元格的效果
  • 單擊和雙擊選擇的效果

整個控件的背景色

話不多說,碼來!

void MyTreeView::paintEvent(QPaintEvent* event)
{
    int count = m_pModel->rowCount(this->rootIndex());
    QPainter painter(this->viewport());
    painter.setPen(Qt::NoPen);
    painter.setBrush(QColor(40, 44, 52));
    painter.drawRect(this->viewport()->rect());
    // 列表為空時,繪制空狀態(tài)
    if (count == 0) {
        QPoint startPos(this->width() / 2 - 72, this->height() / 2);
        QFont font("Microsoft YaHei UI");
        font.setPixelSize(12);
        painter.setFont(font);
        painter.setPen(QColor(153, 154, 161));
        painter.setBrush(Qt::NoBrush);
        painter.drawText(startPos.x(), startPos.y() + 64 + 8, 148, 32, Qt::AlignCenter | Qt::TextWordWrap, "文件夾為空");
        return;
    }
    QTreeView::paintEvent(event);
}

在paintEvent中,首先在整個QTreeView的區(qū)域,繪制了一個背景色。其次判斷model中是否沒有數(shù)據(jù),如果沒有數(shù)據(jù),則居中繪制一個空狀態(tài)。

單元格的效果

繪制單元格,我們通過drawRow去為每一個單元格繪制我們想要的效果。

void MyTreeView::drawRow(QPainter* painter, const QStyleOptionViewItem& options, const QModelIndex& index) const
{
    if (!index.isValid())
        return;
    painter->save();
    painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
    QString path = m_pModel->filePath(index);
    QFileInfo file(path);
    QRect rect = options.rect;
    painter->setPen(Qt::NoPen);
    //判斷狀態(tài)
    bool bNormal = false, bDClick = false, bClick = false;
    if (path == m_selectPath)
    {
        bDClick = true;
    } else if (index == currentIndex()) {
        bClick = true;
    } else {
        bNormal = true;
    }
    // 計算當前Index的目錄相對root目錄的層級
    int rootPathSize = m_pModel->rootPath().size();
    int indexPathSize = m_pModel->filePath(index).size();
    QString relativePath = m_pModel->filePath(index).mid(rootPathSize, indexPathSize - rootPathSize);
    int indexTier = relativePath.split('/').size() - 1;
    // 當前index的縮進
    int indexIndentation = (indexTier - 1) * TierIndentation + 26;
    //QString theme = theme_manager::Instance()->GetThemeName();
#pragma region 繪制底色
    if (bNormal)
    {
        QBrush brush = QBrush(QColor(40, 44, 52));
        painter->setBrush(brush);
        painter->drawRect(rect);
    }
#pragma endregion
#pragma region 繪制選中樣式
    if (!file.isDir() && bDClick)
    {
        QBrush brush = QBrush(QColor(50, 56, 66));
        painter->setBrush(brush);
        painter->drawRect(rect);
    }
#pragma endregion
#pragma region 繪制單擊樣式
    if (bClick)
    {
        QBrush brush = QBrush(QColor(44, 49, 58));
        painter->setBrush(brush);
        painter->drawRect(rect);
    }
#pragma endregion
#pragma region 繪制圖標
    // 畫圖標
    int iconWidth = file.isDir() ? FOLDER_WIDTH : ARROW_WIDTH;
    int iconHeight = file.isDir() ? FOLDER_HEIGHT : ARROW_HEIGHT;
    // (iconWidth - ARROW_HEIGHT)是繪制普通文件時,應(yīng)該多往右邊移動一點
    int xIcon = rect.x() + indexIndentation - (iconWidth - FOLDER_WIDTH);
    int yIcon = rect.y() + (SectionHeight - iconHeight) / 2;
    QRect iconRec(QPoint(xIcon, yIcon), QSize(iconWidth, iconHeight));
    if (file.isDir())
    {
        // 繪制文件夾展開與收起樣式
        isExpanded(index) ? painter->drawImage(iconRec, m_ImageTreeFolderExpand)
            : painter->drawImage(iconRec, m_ImageTreeFolder);
    } 
    else
    {
        QRect iconRec(QPoint(xIcon, yIcon), QSize(14, 14));
        painter->drawImage(iconRec, m_ImageCppFile);
    }
#pragma endregion
#pragma region 繪制文字
    QString text = index.data(Qt::DisplayRole).toString();
    // x坐標為當前層次縮進+圖標寬度(20)+文字與圖標間距(5)
    QRect leverRect(QPoint(rect.x() + indexIndentation + FOLDER_WIDTH + 4, rect.y()),
                    QSize(rect.width(), rect.height()));
    // 繪制文字
    QColor themeTextColor(204, 204, 204);
    painter->setFont(m_textFont);
    painter->setBrush(Qt::NoBrush);
    painter->setPen(QPen(themeTextColor));
    QFontMetrics fm(m_textFont);
    text = fm.elidedText(text, Qt::ElideRight, m_width);
    QRect boundingRect;
    painter->drawText(leverRect, Qt::AlignLeft | Qt::AlignVCenter, text, &boundingRect);
#pragma endregion
#pragma region 繪制箭頭
    //繪制箭頭
    bool bExpand = this->isExpanded(index);
    int xArrow = rect.x() + MARGIN_WIDTH;
    int yArrow = rect.topLeft().y() + (SectionHeight - 8) / 2;
    QRect border(xArrow, yArrow, 8, 8);
    bool bDir = file.isDir(), bEmpty = true;
    if (bDir)
    {
        QDir dir(path);
        bEmpty = dir.isEmpty();
    }
    if (bDir && !bExpand && !bEmpty)
    {
        painter->drawImage(border, m_ImageExpand);
    } else if (bDir && bExpand && !bEmpty)
    {
        painter->drawImage(border, m_ImageClose);
    }
#pragma endregion
    painter->restore();
}

繪制的順序,需要根據(jù)各個部分實際所在的圖層順序去繪制,比如說先要繪制底色,再去繪制上面的內(nèi)容。

單擊選擇和雙擊選擇

這一個部分,我們通過重載 mouseDoubleClickEvent 和 mousePressEvent 來監(jiān)控鼠標的事件。

void MyTreeView::mousePressEvent(QMouseEvent* event)
{
    QTreeView::mousePressEvent(event);
    QModelIndex index = indexAt(event->pos());
    if (!index.isValid())
        return;
    //是否為文件夾
    const auto& path = m_pModel->filePath(index);
    QFileInfo info(path);
    if (!info.isDir())
        return;
    //是否在箭頭區(qū)域
    QPoint point = event->pos();
    int  width = this->viewport()->width();
    QRect rect(width - MARGIN_WIDTH - ARROW_WIDTH, SectionHeight - MARGIN_HEIGHT - ARROW_HEIGHT, ARROW_WIDTH, ARROW_HEIGHT);
    bool bContain = rect.contains(QPoint(event->pos().x(), event->pos().y() % SectionHeight));
    if (!bContain)
        return;
    // 如果目錄為空,不觸發(fā)箭頭交互效果
    QDir tmpDir(path);
    if (tmpDir.isEmpty())
        return;
    //展開收縮節(jié)點
    this->isExpanded(index) ? this->collapse(index)
        : this->expand(index);
}
void MyTreeView::mouseDoubleClickEvent(QMouseEvent* event)
{
    QModelIndex index = this->indexAt(event->pos());
    if (index != this->currentIndex())
        return;
    // 處理普通文件
    QString path = m_pModel->filePath(index);
    if (!m_pModel->isDir(index)) {
        m_selectPath = path;
    }
    update();
    QTreeView::mouseDoubleClickEvent(event);
}

通過上面的幾個函數(shù),我們就可以實現(xiàn)自定義繪制QTreeView的需求,如果還需要繪制更多的東西,則只要自己往上面添加繪制的區(qū)域即可。

一些碎碎念

本來覺得繪制一個QTreeView比較麻煩,包括在這篇博客的時候仍然是這種感覺,但是通過輸出這篇博客,發(fā)現(xiàn)其實也很簡單(當然,不考慮繪制效率的情況下)。就像我剛開始接觸Qt時,總覺得自繪是一件很麻煩、很困難的事,想著全部都要自己去畫。

等到后面真正接觸到的時候,更慌了。但沒辦法,任務(wù)來了,怎么辦?硬著頭皮上唄,一頓捯飭之后,我發(fā)現(xiàn),其實也沒那么難。

所以說,剛接觸Qt的同學(xué),如果樣式表達不到自己需求,就勇敢的去嘗試自繪吧!

到此這篇關(guān)于Qt重寫QTreeView自繪實現(xiàn)酷炫樣式的文章就介紹到這了,更多相關(guān)Qt QTreeView內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論