Truques QComboBox + QTreeView

Na prática, às vezes é necessário exibir uma estrutura de dados semelhante a uma árvore no QComboBox.

O componente padrão no Qt para essa estrutura de dados é o QTreeView, além disso,
O QComboBox pode exibir esse componente dentro de si, mas como sempre, há pequenos espaços na documentação, porque você precisa não apenas exibir a árvore, mas também definir o elemento atual selecionado pelo usuário.

Vamos ver como fazê-lo corretamente.

Primeiro, crie o próprio componente que exibirá os dados, para isso herdamos do QComboBox e fornecemos as propriedades necessárias.

Na parte fechada da classe, declaramos a variável m_view da classe QTreeView, que exibirá a árvore no QComboBox, redefinirá 2 funções responsáveis ​​pelo comportamento do componente ao abrir e fechar:

  • substituição de showPopup (); - executado quando o usuário expande a lista
  • substituição de hidePopup (); - realizada quando o usuário seleciona um item clicando nele

Também adicionamos a função hideColumn (int n), que oculta as colunas necessárias no QTreeView, pois se o seu modelo consiste em várias colunas, o QComboBox mostrará todas elas (o componente padrão usa uma lista), que ficará muito feia

treecombobox.h

#ifndef TREECOMBOBOX_H #define TREECOMBOBOX_H #include <QtWidgets/QComboBox> #include <QtWidgets/QTreeView> class TreeComboBox final : public QComboBox { public: TreeComboBox(); void showPopup() override; void hidePopup() override; void hideColumn(int n); void expandAll(); void selectIndex(const QModelIndex &index); private: QTreeView *m_view = nullptr; }; #endif //TREECOMBOBOX_H 

treecombobox.cpp

 TreeComboBox::TreeComboBox() { m_view = new QTreeView; m_view->setFrameShape(QFrame::NoFrame); m_view->setEditTriggers(QTreeView::NoEditTriggers); m_view->setAlternatingRowColors(true); m_view->setSelectionBehavior(QTreeView::SelectRows); m_view->setRootIsDecorated(false); m_view->setWordWrap(true); m_view->setAllColumnsShowFocus(true); m_view->setItemsExpandable(false); setView(m_view); m_view->header()->setVisible(false); } void TreeComboBox::hideColumn(int n) { m_view->hideColumn(n); } void TreeComboBox::expandAll() { m_view->expandAll(); } void TreeComboBox::selectIndex(const QModelIndex &index) { setRootModelIndex(index.parent()); setCurrentIndex(index.row()); m_view->setCurrentIndex( index ); } void TreeComboBox::showPopup() { setRootModelIndex(QModelIndex()); QComboBox::showPopup(); } void TreeComboBox::hidePopup() { setRootModelIndex(m_view->currentIndex().parent()); setCurrentIndex( m_view->currentIndex().row()); QComboBox::hidePopup(); } 

No construtor, configuramos a árvore que precisamos procurar para que fique “incorporada” no QComboBox, removem os cabeçalhos, ocultam os elementos de expansão e a definimos como um elemento de exibição.

O truque para instalar corretamente um item selecionado pelo usuário em um QComboBox são as funções showPopup () e hidePopup ().

Como o QComboBox trabalha com uma visualização de modelo "plana", ele não pode definir o índice correto do elemento selecionado pelo usuário em modelos de árvore, pois eles usam o índice relativo ao elemento pai para isso:
showPopup ()

elemento raiz - definimos o índice raiz como um índice de modelo inválido para que o QComboBox exiba todos os elementos do modelo.
hidePopup ()

elemento raiz - configuramos o índice do pai do elemento de modelo selecionado pelo usuário e, em seguida, em relação ao elemento pai, configuramos o elemento de usuário selecionado pelo índice.

É usado assim:

 int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget w; QStandardItemModel model; QStandardItem *parentItem = model.invisibleRootItem(); for (int i = 0; i < 4; ++i) { QStandardItem *item = new QStandardItem(QString("item %0").arg(i)); parentItem->appendRow(item); parentItem = item; } TreeComboBox t; t.setModel(&model); t.expandAll(); auto lay = new QVBoxLayout; lay->addWidget( &t); w.setLayout(lay); w.show(); return a.exec(); } 

Source: https://habr.com/ru/post/pt420977/


All Articles