Qt QTreeWidget 固定第一列

Qt 有一个demo "Frozen Column Example"是QTableView固定第一列,我仿照着写了一个QTreeWidget固定第一列。

头文件 “QFrozenTreeWidget.h”
 
   
#ifndef QFROZENTREEWIDGET_H
#define QFROZENTREEWIDGET_H

#include 
#include 
#include 
 
   
//定位结构体,用来存储 展合、勾选 的item位置
struct structIndex
{
    int m_index;
    structIndex *m_pChildIndex;
    structIndex()
    {
        m_index = -1;
        m_pChildIndex = NULL;
    }
};
 
   
class QFrozenTreeWidget : public QTreeWidget
{
    Q_OBJECT
 
   
public:
    QFrozenTreeWidget(QWidget *parent = 0);
    ~QFrozenTreeWidget();
 
   
    //接口
public:
    void SetFrozenColumnHeader(const QString &strHeader);
    void CreateNewItem(QTreeWidgetItem *item);
 
   
protected:
    void resizeEvent(QResizeEvent *event);
    QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers);
    void scrollTo(const QModelIndex &index, ScrollHint hint);
 
   
private:
    void Init();
    void UpdateFrozenTreeGeometry();
 
   
    /*
     * 用来  固定列和本树 找对应的item
     * 比如 固定列某个item展开,要找到本树的对应位置item让其展开,实现同步
     * 下面是递归方法
     * 可能还有简单方法,比如:
     * 可以根据 鼠标位置 找到对应item,用itemAt(QPoint);
     * 可以根据 item 对应的QModelIndex 里row() 采用加法找到对应item,有兴趣的可以实现试试
     */
    structIndex *GetItemIndex(QTreeWidgetItem *targetItem, QTreeWidgetItem *sourceItem);
    QTreeWidgetItem *GetItemFromIndex(QTreeWidgetItem *item, structIndex *index);
    QTreeWidgetItem *GetItemFromItem(QTreeWidget *targetTree, QTreeWidgetItem *souceItem);
 
   
 
   
    /*
     * 下面实现同步勾选
     */
    void SetParentCheckState(QTreeWidgetItem *parentItem);
    void SetChildCheckState(QTreeWidgetItem *selfItem);
    void SetItemChecked(QTreeWidgetItem *item);
 
   
private slots:
    void OnItemCollapsed(QTreeWidgetItem *item);
    void OnItemExpanded(QTreeWidgetItem *item);
    void OnItemChanged(QTreeWidgetItem *item, int column);
    void UpdateSectionWidthSlot(int logicalIndex, int, int newSize);
 
   
private:
    QTreeWidget *m_pFrozenTreeWidget;   //固定的第一列,覆盖在本树第一列位置,实现第一列保持不动
};
 
   
#endif // QFROZENTREEWIDGET_H

cpp文件 "QFrozenTreeWidget.cpp"
#include 
#include 
#include "QFrozenTreeWidget.h"
 
   
QFrozenTreeWidget::QFrozenTreeWidget(QWidget *parent)
    : QTreeWidget(parent)
{
    Init();
}
 
   
QFrozenTreeWidget::~QFrozenTreeWidget()
{
 
   
}
 
   
void QFrozenTreeWidget::SetFrozenColumnHeader(const QString &strHeader)
{
    m_pFrozenTreeWidget->setHeaderLabel(strHeader);
}
 
   
void QFrozenTreeWidget::resizeEvent(QResizeEvent *event)
{
    QTreeWidget::resizeEvent(event);
    UpdateFrozenTreeGeometry();
}
 
   
QModelIndex QFrozenTreeWidget::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
{
    QModelIndex current = QTreeWidget::moveCursor(cursorAction, modifiers);
 
   
    if (cursorAction == MoveLeft && current.column() > 0
            && visualRect(current).topLeft().x() < m_pFrozenTreeWidget->columnWidth(0))
    {
        const int newValue = horizontalScrollBar()->value() + visualRect(current).topLeft().x()
                - m_pFrozenTreeWidget->columnWidth(0);
        horizontalScrollBar()->setValue(newValue);
    }
 
   
    return current;
}
 
   
void QFrozenTreeWidget::scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint)
{
    if (index.column() > 0)
    {
        QTreeWidget::scrollTo(index, hint);
    }
}
 
   
void QFrozenTreeWidget::Init()
{
    m_pFrozenTreeWidget = new QTreeWidget(this);
    m_pFrozenTreeWidget->setFocusPolicy(Qt::NoFocus);
    //让固定列宽度不能手动调整大小,而跟随本树第一列大小来改变
    m_pFrozenTreeWidget->header()->setSectionResizeMode(QHeaderView::Fixed);
 
   
    //让浮在本树上边而不是下边
    viewport()->stackUnder(m_pFrozenTreeWidget);
 
   
    //设置第一列背景颜色好显示效果
    m_pFrozenTreeWidget->setStyleSheet("QTreeView { border: none;"
                                       "background-color: #8ede21;"
                                       "selection-background-color: #999 }");
 
   
    //设置选择模式一样
    m_pFrozenTreeWidget->setSelectionModel(selectionModel());
 
   
    //设置第一列宽度一样
    m_pFrozenTreeWidget->setColumnWidth(0, columnWidth(0));
 
   
    //固定列不需要水平垂直滚动条,用本列的来控制
    m_pFrozenTreeWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    m_pFrozenTreeWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
   
    m_pFrozenTreeWidget->show();
 
   
    //设置滚动条模式按像素为单位滚动
    setHorizontalScrollMode(ScrollPerPixel);
    setVerticalScrollMode(ScrollPerPixel);
    m_pFrozenTreeWidget->setVerticalScrollMode(ScrollPerPixel);
 
   
 
   
    connect(header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(UpdateSectionWidthSlot(int,int,int)));
 
   
    //连接垂直滚动条的信号槽实现同步滚动
    connect(m_pFrozenTreeWidget->verticalScrollBar(), SIGNAL(valueChanged(int)), verticalScrollBar(), SLOT(setValue(int)));
    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), m_pFrozenTreeWidget->verticalScrollBar(), SLOT(setValue(int)));
 
   
    //item 展合
    connect(m_pFrozenTreeWidget, SIGNAL(itemCollapsed(QTreeWidgetItem*)), this, SLOT(OnItemCollapsed(QTreeWidgetItem*)));
    connect(m_pFrozenTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), this, SLOT(OnItemExpanded(QTreeWidgetItem*)));
 
   
    //第一列item勾选
    connect(m_pFrozenTreeWidget, SIGNAL(itemChanged(QTreeWidgetItem*,int)), this, SLOT(OnItemChanged(QTreeWidgetItem*,int)));
}
 
   
void QFrozenTreeWidget::UpdateFrozenTreeGeometry()
{
    m_pFrozenTreeWidget->setGeometry(frameWidth(), frameWidth(), columnWidth(0), viewport()->height() + header()->height());
}
 
   
structIndex *QFrozenTreeWidget::GetItemIndex(QTreeWidgetItem *targetItem, QTreeWidgetItem *sourceItem)
{
    if (targetItem == sourceItem)
    {
        return new structIndex;
    }
 
   
    for (int i = 0; i < targetItem->childCount(); ++i)
    {
        structIndex *pChildStructIndex = GetItemIndex(targetItem->child(i), sourceItem);
 
   
        if (pChildStructIndex != NULL)
        {
            structIndex *pStructIndex = new structIndex;
            pStructIndex->m_pChildIndex = pChildStructIndex;
            pStructIndex->m_index = i;
 
   
            return pStructIndex;
        }
    }
 
   
    return NULL;
}
 
   
QTreeWidgetItem *QFrozenTreeWidget::GetItemFromIndex(QTreeWidgetItem *item, structIndex *index)
{
    if (index->m_index == -1)
    {
        return item;
    }
 
   
    QTreeWidgetItem *targetItem = GetItemFromIndex(item->child(index->m_index), index->m_pChildIndex);
 
   
    if (index->m_pChildIndex != NULL)
    {
        delete index->m_pChildIndex;
        index->m_pChildIndex = NULL;
    }
 
   
    return targetItem;
}
 
   
QTreeWidgetItem *QFrozenTreeWidget::GetItemFromItem(QTreeWidget *targetTree, QTreeWidgetItem *souceItem)
{
    structIndex *pStructIndex = GetItemIndex(souceItem->treeWidget()->invisibleRootItem(), souceItem);
    QTreeWidgetItem *item = GetItemFromIndex(targetTree->invisibleRootItem(), pStructIndex);
    delete pStructIndex;
 
   
    return item;
}
 
   
void QFrozenTreeWidget::SetParentCheckState(QTreeWidgetItem *parentItem)
{
    if (parentItem == NULL)
    {
        return;
    }
 
   
    int count = 0;
 
   
    for (int i = 0; i < parentItem->childCount(); ++i)
    {
        if (parentItem->child(i)->checkState(0) == Qt::Checked)
        {
            count++;
        }
    }
 
   
    if (count == parentItem->childCount())
    {
        parentItem->setCheckState(0, Qt::Checked);
    }
    else
    {
        parentItem->setCheckState(0, Qt::Unchecked);
    }
 
   
    GetItemFromItem(this, parentItem)->setCheckState(0, parentItem->checkState(0));
    SetParentCheckState(parentItem->parent());
}
 
   
void QFrozenTreeWidget::SetChildCheckState(QTreeWidgetItem *selfItem)
{
    for (int i = 0; i < selfItem->childCount(); ++i)
    {
        selfItem->child(i)->setCheckState(0, selfItem->checkState(0));
        GetItemFromItem(this, selfItem->child(i))->setCheckState(0, selfItem->checkState(0));
        SetChildCheckState(selfItem->child(i));
    }
}
 
   
void QFrozenTreeWidget::SetItemChecked(QTreeWidgetItem *item)
{
    QTreeWidgetItem *targetItem = GetItemFromItem(m_pFrozenTreeWidget, item);
 
   
    targetItem->setCheckState(0, item->checkState(0));
}
 
   
void QFrozenTreeWidget::CreateNewItem(QTreeWidgetItem *item)
{
    QTreeWidgetItem *newItem = NULL;
 
   
    if (item->parent() == NULL)
    {
        newItem = new QTreeWidgetItem(GetItemFromItem(m_pFrozenTreeWidget, m_pFrozenTreeWidget->invisibleRootItem()));
    }
    else
    {
        newItem = new QTreeWidgetItem(GetItemFromItem(m_pFrozenTreeWidget, item->parent()));
    }
 
   
    newItem->setCheckState(0, Qt::Unchecked);
 
   
    newItem->setText(0, item->text(0));
}
 
   
void QFrozenTreeWidget::OnItemCollapsed(QTreeWidgetItem *item)
{
    collapseItem(GetItemFromItem(this, item));
}
 
   
void QFrozenTreeWidget::OnItemExpanded(QTreeWidgetItem *item)
{
    expandItem(GetItemFromItem(this, item));
}
 
   
void QFrozenTreeWidget::OnItemChanged(QTreeWidgetItem *item, int column)
{
    GetItemFromItem(this, item)->setCheckState(column, item->checkState(column));
 
   
    m_pFrozenTreeWidget->blockSignals(true);
    SetChildCheckState(item);
    SetParentCheckState(item->parent());
    m_pFrozenTreeWidget->blockSignals(false);
}
 
   
void QFrozenTreeWidget::UpdateSectionWidthSlot(int logicalIndex, int, int newSize)
{
    if (logicalIndex == 0)
    {
        m_pFrozenTreeWidget->setColumnWidth(0, newSize);
        UpdateFrozenTreeGeometry();
    }
}
 
   

"main.cpp"
#include "QFrozenTreeWidget.h"
#include 
 
   
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QFrozenTreeWidget w;
 
   
    w.setColumnCount(5);
    w.setHeaderLabels(QStringList() << "A" << "B" << "C" << "D" << "E");
    w.SetFrozenColumnHeader("A");
 
   
    for (int i = 0; i < 5; ++i)
    {
        QTreeWidgetItem *parent = new QTreeWidgetItem(w.invisibleRootItem(), QStringList() << QString("%1a").arg(i) << QString("%1b").arg(i) << QString("%1c").arg(i) << QString("%1d").arg(i) << QString("%1e").arg(i));
        w.CreateNewItem(parent);
 
   
        for (int j = 0; j < 5; ++j)
        {
            QTreeWidgetItem *child = new QTreeWidgetItem(parent,
                                        QStringList() << QString("a%1%2").arg(i).arg(j)
                                        << QString("b%1%2").arg(i).arg(j)
                                        << QString("c%1%2").arg(i).arg(j)
                                        << QString("d%1%2").arg(i).arg(j)
                                        << QString("e%1%2").arg(i).arg(j));
 
   
            w.CreateNewItem(child);
        }
    }
 
   
    w.resize(400, 300);
    w.setColumnWidth(0, 100);
 
   
    w.show();
 
   
    return a.exec();
}
 
   
 
  

你可能感兴趣的:(Qt)