天天看點

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。
以上是我在開發過程中的總結,如果有更好的解決方法,請給我留言指教。謝謝。

繼續閱讀