QComboBox + QTreeView Tricks

In der Praxis ist es manchmal erforderlich, eine baumartige Datenstruktur in QComboBox anzuzeigen.

Die Standardkomponente in Qt für eine solche Datenstruktur ist außerdem QTreeView.
QComboBox kann diese Komponente in sich selbst anzeigen, aber wie immer enthält die Dokumentation kleine Leerzeichen, da Sie nicht nur den Baum anzeigen, sondern auch das vom Benutzer ausgewählte aktuelle Element festlegen müssen.

Mal sehen, wie man es richtig macht.

Erstellen Sie zunächst die Komponente selbst, in der die Daten angezeigt werden. Dazu erben wir sie von QComboBox und geben ihr die Eigenschaften, die wir benötigen.

Im geschlossenen Teil der Klasse deklarieren wir die Variable m_view der QTreeView-Klasse, die den Baum in der QComboBox anzeigt. Definieren Sie zwei Funktionen neu, die für das Verhalten der Komponente beim Öffnen und Schließen verantwortlich sind:

  • void showPopup () override; - Wird ausgeführt, wenn der Benutzer die Liste erweitert
  • void hidePopup () override; - Wird ausgeführt, wenn der Benutzer ein Element durch Klicken darauf auswählt

Wir fügen auch die Funktion hideColumn (int n) hinzu, mit der die in QTreeView benötigten Spalten ausgeblendet werden. Wenn Ihr Modell aus mehreren Spalten besteht, zeigt QComboBox alle an (die Standardkomponente verwendet eine Liste), die sehr hässlich aussieht

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

Im Konstruktor legen wir den Baum, den wir suchen müssen, so fest, dass er in die QComboBox „eingebettet“ aussieht, entfernen die Überschriften, verbergen die Erweiterungselemente und legen ihn als Anzeigeelement fest.

Der Trick, um ein vom Benutzer ausgewähltes Element ordnungsgemäß in einer QComboBox zu installieren, sind die Funktionen showPopup () und hidePopup ().

Da QComboBox mit einer "flachen" Modellansicht arbeitet, kann es nicht den korrekten Index des vom Benutzer ausgewählten Elements in Baummodellen festlegen, da sie den Index relativ zum übergeordneten Element verwenden:
showPopup ()

Wurzelelement - Wir setzen den Wurzelindex auf einen ungültigen Modellindex, damit QComboBox alle Elemente des Modells anzeigt.
hidePopup ()

Stammelement - Wir legen den Index des übergeordneten Elements des vom Benutzer ausgewählten Modellelements und dann relativ zum übergeordneten Element das ausgewählte Benutzerelement anhand des Index fest.

Es wird alles so verwendet:

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


All Articles