pyside6qt6

How to make a QT Popup close when clicking outside of it?


When I open a PySide6/Qt6 Popup Window the user can't click outside the popup to close it. The only way I found is to press ESC, clicks the window titlebar or switches to a different application, which isn't very intuitive and user friendly imho. Is there a way to make it close by clicking outside the popup? Or do I need to use a different flag, component or something?

The goal is to have a Textinput Field which shows some search results while the user types.

I made a small test implementation in python where the Popup opens by clicking on a button to show how the popup will close only when the user presses ESC, clicks the window titlebar or switches to a different application.

I tried PySide6 as shown below, but also tried Qt6 with the same result.

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton, QListView, QVBoxLayout, QWidget, QDialog
from PySide6.QtCore import Qt, QStringListModel
import sys


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Button Example")
        self.setGeometry(100, 100, 600, 600)

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        layout = QVBoxLayout(central_widget)

        button = QPushButton("Open List View")
        button.clicked.connect(self.show_popup)
        layout.addWidget(button)


    def show_popup(self):
        dialog = QDialog(self)
        dialog.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.Popup)
        dialog.setWindowTitle("List View Popup")
        dialog.setModal(True)
        dialog.resize(300, 400)

        layout = QVBoxLayout()
        list_view = QListView()
        
        model = QStringListModel()
        model.setStringList(["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"])
        list_view.setModel(model)
        
        layout.addWidget(list_view)
        dialog.setLayout(layout)
        dialog.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

Solution

  • It seems this is a bug in the macOS QT?

    Anyway I solved this by installing an eventFilter on the popup. This is the code that fixed it for me:

    def eventFilter(self, obj: QObject, event: QEvent) -> bool:
        logger.debug(f"[TagCompleterPopup] - eventFilter - Event type: {event.type()} - type: {type(event)}")
    
        if isinstance(event, QMouseEvent):
            mouse_event = QMouseEvent(event)
            if not self.rect().contains(mouse_event.pos()):
                self.hide()
                return True
            
        return super().eventFilter(obj, event)