如何恢复QTreeView上次扩展状态?

mos*_*osg 18 qt qt4 qtreeview

是)我有的:

  1. QTreeView 带有表数据的类
  2. 和连接的QAbstractTableModel模型

问题:如何保存扩展的物品状态?有人已经完成了解决方案吗?

PS:我知道,我可以自己做这个代码,但是我没有太多时间,这不是我们项目的主要问题,但我们仍然需要它,因为app包含很多这样的表,并且每次扩展树项都是烦恼的过程...

mos*_*osg 13

首先,感谢拉齐persistentIndexListisExpanded方式.

其次,这是对我有用的代码就好了:-)

dialog.h文件:

class Dialog : public QDialog
{
    Q_OBJECT;

    TreeModel *model;
    TreeView *view;

public:
    Dialog(QWidget *parent = 0);
    ~Dialog(void);

    void reload(void);

protected:
    void createGUI(void);
    void closeEvent(QCloseEvent *);
    void saveState(void);
    void restoreState(void);
};
Run Code Online (Sandbox Code Playgroud)

dialog.cpp文件:

Dialog::Dialog(QWidget *parent)
{
    createGUI();
    reload();
}

Dialog::~Dialog(void) {};

void Dialog::reload(void)
{
    restoreState();
}

void Dialog::createGUI(void)
{
    QFile file(":/Resources/default.txt");
    file.open(QIODevice::ReadOnly);
    model = new TreeModel(file.readAll());
    file.close();

    view = new TreeView(this);
    view->setModel(model);

    QVBoxLayout *mainVLayout = new QVBoxLayout;
    mainVLayout->addWidget(view);

    setLayout(mainVLayout);
}

void Dialog::closeEvent(QCloseEvent *event_)
{
    saveState();
}

void Dialog::saveState(void)
{
    QStringList List;

    // prepare list
    // PS: getPersistentIndexList() function is a simple `return this->persistentIndexList()` from TreeModel model class
    foreach (QModelIndex index, model->getPersistentIndexList())
    {
        if (view->isExpanded(index))
        {
            List << index.data(Qt::DisplayRole).toString();
        }
    }

    // save list
    QSettings settings("settings.ini", QSettings::IniFormat);
    settings.beginGroup("MainWindow");
    settings.setValue("ExpandedItems", QVariant::fromValue(List));
    settings.endGroup();
}

void Dialog::restoreState(void)
{
    QStringList List;

    // get list
    QSettings settings("settings.ini", QSettings::IniFormat);
    settings.beginGroup("MainWindow");
    List = settings.value("ExpandedItems").toStringList();
    settings.endGroup();

    foreach (QString item, List)
    {
        // search `item` text in model
        QModelIndexList Items = model->match(model->index(0, 0), Qt::DisplayRole, QVariant::fromValue(item));
        if (!Items.isEmpty())
        {
            // Information: with this code, expands ONLY first level in QTreeView
            view->setExpanded(Items.first(), true);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

祝你今天愉快!)


PS:这个例子基于C:\Qt\4.6.3\examples\itemviews\simpletreemodel代码.


ifo*_*e2d 8

感谢Razi和mosg我能够让这个工作.我让它以递归方式恢复扩展状态,所以我想我会分享那部分.

void applyExpandState_sub(QStringList& expandedItems,
                          QTreeView* treeView,
                          QAbstractItemModel* model,
                          QModelIndex startIndex)
{
    foreach (QString item, expandedItems) 
    {
        QModelIndexList matches = model->match( startIndex, Qt::UserRole, item );
        foreach (QModelIndex index, matches) 
        {
            treeView->setExpanded( index, true );
            applyExpandState_sub(expandedItems, 
                                 treeView,
                                 model,
                                 model->index( 0, 0, index ) );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用像:

void myclass::applyExpandState() 
{
    m_treeView->setUpdatesEnabled(false);

    applyExpandState_sub( m_expandedItems,
                          m_treeView,
                          m_model,
                          m_model->index( 0, 0, QModelIndex() ) );

    m_treeView->setUpdatesEnabled(true);
}
Run Code Online (Sandbox Code Playgroud)

我在这里使用Qt :: UserRole,因为我的模型中的多个项目可能具有相同的显示名称,这会破坏展开状态恢复,因此UserRole为每个项目提供唯一标识符以避免该问题.


S. *_*azi 7

这两个函数通过使用循环应该为您做到这一点:

QModelIndexList QAbstractItemModel::persistentIndexList () const
bool isExpanded ( const QModelIndex & index ) const
Run Code Online (Sandbox Code Playgroud)


Bas*_*ond 6

这是一种适用于任何基于 QTreeView 的小部件的通用方法,它使用某种 ID 系统来识别元素(我假设 ID 是一个 int,它存储在 中Qt::UserRole):

void MyWidget::saveExpandedState()
{
    for(int row = 0; row < tree_view_->model()->rowCount(); ++row)
        saveExpandedOnLevel(tree_view_->model()->index(row,0));
}

void Widget::restoreExpandedState()
{
    tree_view_->setUpdatesEnabled(false);

    for(int row = 0; row < tree_view_->model()->rowCount(); ++row)
        restoreExpandedOnLevel(tree_view_->model()->index(row,0));

    tree_view_->setUpdatesEnabled(true);
}

void MyWidget::saveExpandedOnLevel(const QModelIndex& index)
{
    if(tree_view_->isExpanded(index)) {
        if(index.isValid())
            expanded_ids_.insert(index.data(Qt::UserRole).toInt());
        for(int row = 0; row < tree_view_->model()->rowCount(index); ++row)
            saveExpandedOnLevel(index.child(row,0));
    }
}

void MyWidget::restoreExpandedOnLevel(const QModelIndex& index)
{
    if(expanded_ids_.contains(index.data(Qt::UserRole).toInt())) {
        tree_view_->setExpanded(index, true);
        for(int row = 0; row < tree_view_->model()->rowCount(index); ++row)
            restoreExpandedOnLevel(index.child(row,0));
    }
}
Run Code Online (Sandbox Code Playgroud)

而不是MyWidget::saveExpandedState()andMyWidget::saveExpandedState()也可以直接调用MyWidget::saveExpandedOnLevel(tree_view_->rootIndex())and MyWidget::restoreExpandedOnLevel(tree_view_->rootIndex())。我只使用了上面的实现,因为无论如何都会调用 for 循环,MyWidget::saveExpandedState()并且MyWidget::saveExpandedState()使用我的 SIGNAL 和 SLOT 设计看起来更干净。