天天看点

QT实现资源管理器总结

       项目中需要实现的资源管理器做完了,使用的是QT,实现TreeView与ListView数据统一显示文件。现在总结一下开发过程中遇到的一些问题以及我的解决方法。

1. TreeView与ListView显示文件

      Qt的QTreeWidget和QListWidget接口很简单易用。但是如果用来实现文件资源管理使用它们不是很方便。QT提供了model-view模式。使用model(QFileSystemModel)和view(QTreeView & QListView)来实现资源管理更为简单方便,可以轻松的实现QTreeView QListView同时更新。具体用法如下:

       m_dir_model.setRootPath(QDir::currentPath());

       m_dir_model.setReadOnly(true);    

       m_resource_tree->setModel(&m_dir_model);

       m_resource_tree->setRootIndex(m_dir_model.index(m_root_path));

       m_current_listview->setModel(&m_dir_model);

       m_current_listview->setRootIndex(m_dir_model.index(m_root_path));

       这样QTreeView和QListView就可以显示当前路径下文件和文件夹信息。

      还有个功能是点击QTreeView的某一个文件夹,更新QListView显示的内容。这个功能实现使用信号槽。

connect(m_resource_tree,        SIGNAL(clicked(QModelIndex)),    this, SLOT(UpdateCurrentTab(const QModelIndex&)));

      在UpdataCurrentTab(const QModelIndex&)槽中再次调用QListView::setRootIndex(const QModelIndex &index)函数,就可以更新QListView的内容。

注:

           QFileSystemModel  m_dir_model;

           QTreeView m_resource_tree;

           QListView m_current_listview;

2. ListView文件类型过滤

    资源管理器都有文件类型过滤的功能。对于model中每一项的过滤与排序,QT提供了QSortFilterProxyModel类作为扩展,提供了排序和过滤的功能。QSortFilterProxyModel用法如下:

                  QSortFilterProxyModel m_proxy_model;

                  m_proxy_model.setDynamicSortFilter(true);

                  m_proxy_model.setFilterRegExp(GetFilterRegExp());

                  m_proxy_model.setSourceModel(&m_file_model);

                  m_current_listview->setModel(&m_proxy_model);

                  m_current_listview->setRootIndex(

                  m_proxy_model.mapFromSource(m_file_model.index(m_root_path)));

      与直接使用QFileSystemModel的区别就是将QFileSystemModel设置成QSortFilterProxyModel的源模型(使用setSourceModel函数)。setFilterRegExp函数就是设置过滤用的正则表达式。在项目中我写了GetFilterRegExp函数来生成文件扩展名过滤用的正则表达式(是根据checkbox的选择结果来生成一个正则表达式)。在每次改变过滤内容后(比如选择了其他的check box)再次调用setFilterRegExp函数,并传递给它新的正则表达式,就可以自动刷新View的内容。

3. ListView的Icon模式与缩略图切换

       项目中要实现3D模型、特效、纹理等的缩略图显示,并且可以切换icon模式与缩略图模式。QT的model-view模式与使用简单的QTreeWidget不一样,不能每一项单独指定icon的资源。需要通过子类化QFileIconProvider,并且重写其QIcon icon(const QFileInfo &info) const;函数来实现。在QFileIconProvider::icon函数中通过当前资源管理器的选项(icon模式或者缩略图)来返回正确的QIcon(都是读文件的工作了,QIcon中加载资源文件可以查看文档,只是构造函数中的一个参数的设置)。

4. 3D资源预览窗口,以及生成资源缩略图

       预览窗口是继承了一个QWidget,并且设置定时器:

       QTimer *timer = new QTimer(this);

       connect(timer, SIGNAL(timeout()), this, SLOT(update()));

       timer->start();

       在第一次调用update函数中初始化D3D,非第一次的调用中进行Update以及Render的工作。值得注意的一点是,想要让QT的控件渲染D3D的内容需要设置:

       setAttribute(Qt::WA_NoBackground);

       setAttribute(Qt::WA_PaintOnScreen);

       缩略图的生成就是创建模型、特效等,然后使用渲染到纹理,并且保存成图片(为了让资源管理器不必每次都做以上工作,也可以不保存成图片,直接使用生成的纹理。)。

5. QT显示DDS文件

      QT中是不直接支持DDS文件的读取的,这里我使用DX来读取DDS文件,然后生成QPixmap。做法如下:

QPixmap LoadSpecialImage(const QString& special_file)

{

    render::IRenderer *renderer = EngineService().Instance().IRenderer();   

    render::ITexture *tex = renderer->CreateTexture(special_file.toAscii());

    unsinged char *data;

    int pitch;

    tex->GetData(&data, pitch);   

    QImage::Format format;

    Dword format_dword = tex->GetFormat();

    switch (format_dword)

    {

        case D3DFMT_R8G8B8 :

            format = QImage::Format_RGB16;

            break;

        case D3DFMT_X8R8G8B8 :

            format = QImage::Format_RGB32;

            break;

        case D3DFMT_A8R8G8B8 :

            format = QImage::Format_ARGB32;

            break;

        default:

            {

                tex->Release();

                format = QImage::Format_ARGB32;

                tex = renderer->CreateTextureEx(special_file.toAscii(), format, 256, 256);

                tex->GetData(&data, pitch);

                EngineService::Instance().ILog()->Write(0, 0, "QT is not suport the %d format, recreate texture use argb32", format_dword);

            }

            break;

    }

    IDirect3DTexture9 *tex_handle = (IDirect3DTexture9*)tex->GetD3DTexture();

    D3DSURFACE_DESC    desc;

    tex_handle->GetLevelDesc(0, &desc);

    QImage image(data, desc.Width, desc.Height, format);

    QPixmap pix = QPixmap::fromImage(image);

    tex->Release();   

    return pix;

}

其中关于渲染器以及纹理的部分代码是3D引擎封装的接口,可以直接改成D3D9的device以及texture。
以上是我在开发过程中的总结,如果有更好的解决方法,请给我留言指教。谢谢。