2020年8月25日 星期二

TreeView 的基本應用

TreeView 的基本應用

前言

  在許多遊戲編輯器都需要顯示樹狀資料結構,像是物件瀏覽器或是檔案瀏覽器,Qt 提供 TreeView 來顯示樹狀的資料結構,在此把學習的過程做個紀錄。

內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/TreeView/Basic,在 Qt Creator 開啟設計介面會看到以下
範例的設計介面

圖中左側有 TreeView 在工具箱的位置。執行結果如下
範例的執行結果

範例會加入兩個預設的節點,可以透過"Add root item"、"Add child item"與"Remove"三個按鈕來控制樹的節點。TreeView 不提供在設計介面裡編輯節點的功能,資料必須透過程式綁定資料才能使用。

  接著來看看程式的操作,先看到 MainWindow::MainWindow() ,程式碼如下
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //
  QStandardItemModel* pModel = new QStandardItemModel(ui->treeView);
  pModel->setHorizontalHeaderLabels( QStringList()<<QStringLiteral( "Name" )<<QStringLiteral( "Comment" ) );
  QStandardItem* pItemRoot1 = new QStandardItem( QStringLiteral( "root1" ) );
  //first
  pItemRoot1->setChild( 0 , 0 , new QStandardItem( QStringLiteral( "child" ) ) );
  pItemRoot1->setChild( 0 , 1 , new QStandardItem( QStringLiteral( "I'm child" ) ) );
  //second
  pItemRoot1->setChild( 1 , 0 , new QStandardItem( QStringLiteral( "child1" ) ) );
  //
  pModel->appendRow( pItemRoot1 );

  //
  QStandardItem* pItemRoot2 = new QStandardItem( QStringLiteral( "root2" ) );
  pItemRoot2->setChild( 0 , 0 , new QStandardItem( QStringLiteral( "child" ) ) );
  pItemRoot2->setChild( 0 , 1 , new QStandardItem( QStringLiteral( "I'm child" ) ) );
  //
  pModel->appendRow( pItemRoot2 );

  //
  ui->treeView->setModel( pModel );
  //event bind
  connect( ui->addRootItemButton , &QPushButton::clicked , this , &MainWindow::onAddRootItemButtonClicked );
  connect( ui->addChildItemButton , &QPushButton::clicked , this , &MainWindow::onAddChildItemButtonClicked );
  connect( ui->removeButton , &QPushButton::clicked , this , &MainWindow::onRemoveButtonClicked );
}

程式的開頭會產生"QStandardItemModel",這個類別負責儲存樹的節點資料,透過"setHorizontalHeaderLabels()"來新增欄位名稱,接著是新增節點,節點的類別是"QStandardItem",透過"setChild()"來新增子節點,最後透過"appendRow()"加到"QStandardItemModel "裡,"root2"節點如"root1"節點一樣就不再解釋,接著透過"setModel"將"QStandardItemModel "綁定到 TreeView ,最後是三個功能按鍵的事件綁定。
三個功能鍵的程式如下
void MainWindow::onAddRootItemButtonClicked( bool enabled )
{
  QStandardItemModel* pModel = (QStandardItemModel*)ui->treeView->model();
  pModel->appendRow( new QStandardItem( QStringLiteral( "add root item" ) ) );
}

void MainWindow::onAddChildItemButtonClicked( bool enabled )
{
  QModelIndex index = ui->treeView->currentIndex();
  QStandardItemModel* pModel = (QStandardItemModel*)ui->treeView->model();
  if( index.isValid() )
  {
    QStandardItem* pSelectedItem = pModel->itemFromIndex( index );
    pSelectedItem->appendRow( new QStandardItem( QStringLiteral( "add child item" ) ) );
  }
}

void MainWindow::onRemoveButtonClicked( bool enabled )
{
  QModelIndex index = ui->treeView->currentIndex();
  QStandardItemModel* pModel = (QStandardItemModel*)ui->treeView->model();
  if(index.isValid() )
  {
    pModel->removeRow( index.row() , index.parent() );
  }
}

先看到"Add root item"的部分, TreeView 可以透過"model()"來取得"QStandardItemModel",透過"appendRow()"就可以直接新增節點在根。"Add child item"的部分因為是在目前選取的節點下新增子節點,所以透過"currentIndex()"取得選擇的節點索引,但要考慮他可能是無效的!因為可能沒有選擇任何節點,只要透過"isValid()"就可以驗證,驗證有效後要透過這個索引來取得"QStandardItem",這個時候用"itemFromIndex()"就可以取得,取得後直接透過"appendRow()"來加到該節點的子節點,最後看到"Remove",和"Add child item"一樣是對當下所選取的節點做操作,取得並驗證有效的索引後可以直接用"removeRow()"來刪除節點。

參考資料

[ doc.qt.io ] QTreeView Class

相關文章與資料

[ GitLab ] HelloQt

沒有留言:

張貼留言