【问题标题】:How to refresh a QFileSystemModel in a QTreeView after files change through another process?文件通过另一个进程更改后如何刷新 QTreeView 中的 QFileSystemModel?
【发布时间】:2014-02-28 00:43:38
【问题描述】:

我有一个QTreeView 和一个QFileSystemModel 作为模型。文件和目录加载正确。

在我的应用程序工作流程中,不同的进程复制并覆盖文件系统上的文件。

但是,我的QTreeView 不会更新被覆盖文件的项目/行(例如:文件的大小和 lastModified 值不会更新为新值)。

使用文件路径,我可以获得FileInfo,它确实具有更新的 lastModified 值。但是,使用该相同的路径获取行的 lastModified 值的 QModelIndex 会导致它返回旧值。

我尝试了一些方法(见下文),但均无济于事。

如果您知道如何解决此问题,请告诉我。非常感谢! :)

// ... at this point the file system has been updated and the file
// has new values for things like last modified date
QFileInfo *updatedFile = new QFileInfo( filePath );

QModelIndex indexOfFileName = myFileTreeView->myFileSystemModel->index( filePath );
QModelIndex indexOfLastModifiedDate = myFileTreeView->myFileSystemModel->index( filePath, lastModifiedColumnIndex );

// attempts to kick the QFileSystemModel and QTreeView to update the model values
// a collection from the internet :)
emit myFileTreeView->dataChanged( indexOfFileName, indexOfLastModifiedDate );
emit myFileTreeView->myFileSystemModel->dataChanged( indexOfFileName, indexOfLastModifiedDate );
myTreeView->repaint();
myTreeView->update( indexOfLastModifiedDate );
myTreeView->viewport()->update();

// looking to see if values changed
QModelIndex newIndexOfLastModifiedDate = myTreeView->myFileSystemModel->index( filePath, lastModifiedColumnIndex );

// this shows the correct row and column for the index, so the index looks correct
qDebug() << "newIndexOfLastModifiedDate: " << newIndexOfLastModifiedDate;

// does not have new value
qDebug() << "newIndexOfLastModifiedDate.data(): " << newIndexOfLastModifiedDate->data();

// has new value
qDebug() << "fileInfo.lastModified(): " << updatedFile->lastModified();

[编辑 - 添加步骤以模拟应用程序工作流程]

我认为以下是可以模仿该问题的步骤。

复制步骤:

  • 设置一个使用 QFileSystemModel 作为其模型的简单 QTreeView。

  • 将根路径设置为名为@9​​87654329@的目录

  • Root 目录内创建一个文本文件Test.txt

  • 加载应用程序并在其中观察Root 目录中Test.txt 文件的上次修改日期

  • 保持此应用程序窗口打开。

  • Test.txt复制到一个不同的目录,比如Temp

  • 修改文件并保存在Temp

  • 复制并替换 Test.txt 以覆盖Root 目录中的文件

  • 在应用程序窗口中观察上次修改日期

结果:上次修改日期没有更新

添加了 SAPMLE:

#include <QApplication>
#include <QFileSystemModel>
#include <QFile>
#include <QFileInfo>
#include <QTimer>
#include <QDebug>
#include <QTreeView>
#include <QDateTime>


// Globals
QFileSystemModel *model = NULL;
const QString name = "test.txt";
const int delayOffset = 1000;

// Interface
void onDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector< int >& roles );
void clean();
void doCreateFile();
void doUpdateFile();
void doTest();


// Implementation
int main( int argc, char *argv[] )
{
    QApplication a( argc, argv );
    int delay = 0;

    // Clean
    clean();

    // Init model
    const QString rootPath = QCoreApplication::applicationDirPath();
    model = new QFileSystemModel( &a );
    model->setRootPath( rootPath );
    QObject::connect( model, &QFileSystemModel::dataChanged, &onDataChanged );

    // Init file actions
    delay += delayOffset * 2;
    QTimer tCreate;
    tCreate.setSingleShot( true );
    tCreate.setInterval( delay );
    QObject::connect( &tCreate, &QTimer::timeout, &doCreateFile );

    delay += delayOffset * 4;
    QTimer tUpdate;
    tUpdate.setSingleShot( true );
    tUpdate.setInterval( delay );
    QObject::connect( &tUpdate, &QTimer::timeout, &doUpdateFile );

    // GUI
    QTreeView w;
    w.setModel( model );
    w.setRootIndex( model->index( rootPath ) );
    w.show();
    w.expandAll();

    qDebug() << "Start";
    tCreate.start();
    tUpdate.start();

    return a.exec();
}

void onDataChanged( const QModelIndex& topLeft, const QModelIndex& bottomRight, const QVector< int >& roles )
{
    qDebug() << "Model changed";
}

void clean()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( f.exists() )
        f.remove();
}

void doCreateFile()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( !f.open( QIODevice::WriteOnly ) )
    {
        qDebug() << "Could not create file";
        return ;
    }

    f.write( "Preved" );
    f.close();

    qDebug() << "File created";
    doTest();
}

void doUpdateFile()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFile f( path );

    if ( !f.open( QIODevice::Append ) )
    {
        qDebug() << "Could not open file for modification";
        return ;
    }

    f.write( " medved" );
    f.close();

    qDebug() << "File updated";
    doTest();
}

void doTest()
{
    const QString path = QString( "%1/%2" ).arg( QCoreApplication::applicationDirPath() ).arg( name );
    QFileInfo info( path );

    qDebug() << "Last modified (real):  " << info.lastModified().toString( "hh:mm:ss" );
    qDebug() << "Last modified (model): " << model->lastModified( model->index( path ) ).toString( "hh:mm:ss" );
}

【问题讨论】:

  • emit myFileTreeView-&gt;dataChanged 那是什么???
  • 这是我未受过教育的尝试,根据网络上类似但不同的帖子,我的自定义 QTreeView 模型中的特定行已更改其数据并需要更新。它没有达到我的预期。我把它放在那里,这样你就可以看到我的尝试了。
  • 添加了重现问题的代码示例。
  • 很好的发现。是的,这就是我想要的功能,但 QDirModel 自 2010 年 1 月以来已过时 (blog.qt.digia.com/blog/2010/01/08/…)。我想知道为什么refresh()方法没有在QFileSystemModel中实现。

标签: qt qtreeview qfilesystemmodel qfilesystemwatcher


【解决方案1】:

在需要更新模型时,您应该使用QFileSystemWatcher 跟踪每个文件的事件。

QFileSystemWatcher 由于性能问题不跟踪事件。这是known issue。因此,您可以创建自己的模型和/或使用建议的解决方法:

model.setRootPath("");
model.setRootPath("the_folder_you_want_to_update");

【讨论】:

  • 谢谢。我不想reset(),因为它丢失了用户扩展节点的状态。我确实拥有自己的QFileSystemModel,并将考虑实施QFileSystemWatcher
  • 我刚刚阅读了qt-project.org/doc/qt-5.0/qtwidgets/qfilesystemmodel.html - 有评论,QFileSystemModel 已经使用 QFileSystemWatcher。所以你的问题在另一个地方。
  • 是的,我也学到了。我要么需要我的自定义QFileSystemModel 来了解文件系统更改,要么我需要手动更新索引数据。我不知道该怎么做:/
  • 您不需要手动更新索引。你做错了什么。您能否提供重现您的问题的代码示例?
  • 根据您的要求添加了重现步骤。谢谢! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多