Trucos QComboBox + QTreeView

En la práctica, a veces es necesario mostrar una estructura de datos en forma de árbol en QComboBox.

El componente estándar en Qt para dicha estructura de datos es QTreeView, además,
QComboBox puede mostrar este componente dentro de sí mismo, pero como siempre, hay pequeños espacios en la documentación, porque no solo necesita mostrar el árbol, sino también establecer el elemento actual seleccionado por el usuario.

Veamos cómo hacerlo bien.

Primero, cree el componente mismo, que mostrará los datos, para esto heredamos de QComboBox y le daremos las propiedades que necesitamos.

En la parte cerrada de la clase, declaramos que la variable m_view de la clase QTreeView, que mostrará el árbol en el QComboBox, redefine 2 funciones que son responsables del comportamiento del componente al abrir y cerrar:

  • anular showPopup () override; - ejecutado cuando el usuario expande la lista
  • anular hidePopup () override; - se realiza cuando el usuario selecciona un elemento haciendo clic en él

También agregamos la función hideColumn (int n), que ocultará las columnas que necesita en QTreeView, ya que si su modelo consta de varias columnas, QComboBox las mostrará todas (el componente estándar usa una lista), que se verá muy feo

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(); } 

En el constructor, configuramos el árbol que debemos buscar para que se vea "incrustado" en el QComboBox, elimine los encabezados, oculte los elementos de expansión y configúrelo como un elemento de visualización.

El truco para instalar correctamente un elemento seleccionado por el usuario en un QComboBox es las funciones showPopup () y hidePopup ().

Dado que QComboBox funciona con una vista de modelo "plana", no puede establecer el índice correcto del elemento seleccionado por el usuario en modelos de árbol, ya que utilizan el índice relativo al elemento principal para esto:
showPopup ()

elemento raíz: establecemos el índice raíz en un índice de modelo no válido para que QComboBox muestre todos los elementos del modelo.
hidePopup ()

elemento raíz: establecemos el índice del elemento primario del elemento modelo seleccionado por el usuario y luego, en relación con el elemento primario, establecemos el elemento del usuario seleccionado por índice.

Se usa todo de esta manera:

 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/es420977/


All Articles