如何防止点击QTreeView元素时QComboBox下拉视图自动收起?
Hey there, I’ve run into this exact frustrating issue before when embedding a QTreeView into a QComboBox—total buzzkill when you can’t even expand child nodes without the dropdown collapsing immediately. Let’s fix this step by step.
The Root Cause
QComboBox has a default behavior where clicking anywhere inside its dropdown popup triggers hidePopup(), including when you click the expand/collapse arrow on the QTreeView. That’s why your tree nodes won’t stay open long enough to select items.
The Fix: Customize QComboBox to Ignore Indicator Clicks
We’ll create a custom QComboBox subclass that overrides the hidePopup() method. The goal is to check if the user clicked on the TreeView’s expand/collapse indicator—if so, we’ll skip hiding the popup. For all other clicks (like selecting an item), we’ll keep the default behavior.
Here’s the code:
First, import the required modules:
from PyQt5.QtWidgets import QComboBox, QTreeView, QApplication from PyQt5.QtCore import Qt, QPoint from PyQt5.QtGui import QStandardItemModel, QStandardItem
Then define the custom combo box:
class TreeComboBox(QComboBox): def __init__(self, parent=None): super().__init__(parent) # Set up the embedded TreeView self.tree_view = QTreeView(self) self.setView(self.tree_view) # Enable expandable nodes (default might be off) self.tree_view.setRootIsDecorated(True) self.tree_view.setItemsExpandable(True) def hidePopup(self): # Convert global mouse position to coordinates relative to the TreeView's viewport mouse_pos = self.tree_view.viewport().mapFromGlobal(QApplication.instance().mousePos()) # Get the model index at the clicked position clicked_index = self.tree_view.indexAt(mouse_pos) # Check if we clicked on an expand/collapse indicator if clicked_index.isValid() and (clicked_index.flags() & Qt.ItemIsExpandable): # Calculate the rectangle of the indicator area (left side of the item) indicator_rect = self.tree_view.visualRect(clicked_index).adjusted(0, 0, self.tree_view.indentation(), 0) if indicator_rect.contains(mouse_pos): # Don't hide the popup if we clicked the indicator return # For all other clicks, use the default hide behavior super().hidePopup()
How to Use It
Here’s a quick example to test the custom combo box with a sample tree structure:
if __name__ == "__main__": app = QApplication([]) combo = TreeComboBox() # Create a sample tree model model = QStandardItemModel() root = model.invisibleRootItem() # Add parent and child items parent_item = QStandardItem("Parent Node") child1 = QStandardItem("Child Item 1") child2 = QStandardItem("Child Item 2") parent_item.appendRow([child1, child2]) root.appendRow(parent_item) root.appendRow(QStandardItem("Standalone Item")) combo.tree_view.setModel(model) combo.setMinimumWidth(250) combo.show() app.exec_()
Notes
- If you’re using a custom delegate or style for your TreeView, you might need to adjust the
indicator_rectcalculation to match your UI’s indicator position. - This solution preserves all default QComboBox behavior except when clicking the TreeView’s expand/collapse arrows—so selecting items will still close the popup as expected.
内容的提问来源于stack exchange,提问作者Sergey Maslov

