如何在点击外部关闭 QDialog 并在点击子小部件时关闭?

Posted

技术标签:

【中文标题】如何在点击外部关闭 QDialog 并在点击子小部件时关闭?【英文标题】:How to close a QDialog at click outside and close at click a sub-widget? 【发布时间】:2017-01-19 20:27:37 【问题描述】:

我有一个小问题。当我按下 QPushButton(child) 或在 QDialog 外部单击时,我正在尝试关闭 QDialog。 我不想在按钮的功能中关闭连接。我想在 QDialog 检测到孩子点击时关闭。

对不起我的英语。

非常感谢。

对话框.py

# coding=utf-8
from PyQt4.QtCore import Qt
from PyQt4.QtGui import *


class SimpleDialog(QDialog):

    def __init__(self, title=None):
        QDialog.__init__(self)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool)
        self.setMinimumWidth(280)

        self.__inWidget = []
        self.__textColor = "#212121"

        font = QFont()
        font.setFamily("Roboto Medium")
        font.setPixelSize(20)

        self.__title = QLabel()
        self.__title.setFont(font)
        self.__title.setWordWrap(True)
        self.__title.hide()
        if title:
            self.setTitle(title)

        self.__vLayout = QVBoxLayout()

        textLayout = QVBoxLayout()
        textLayout.setAlignment(Qt.AlignTop)
        textLayout.addWidget(self.__title)

        contentLayout = QVBoxLayout()
        contentLayout.addLayout(textLayout)
        contentLayout.addLayout(self.__vLayout)

        widget = QWidget()
        widget.setLayout(contentLayout)

        main = QVBoxLayout()
        main.addWidget(widget)

        backBoard = QHBoxLayout()
        backBoard.addLayout(main)
        self.setLayout(backBoard)

    def focusOutEvent(self, *args, **kwargs):
        self.close()

    def addItem(self, simpleDialogItem):
        """ SimpleDialog.addItem(SimpleDialogItem)
        Agrega un item al SimpleDialog
        """
        if type(simpleDialogItem) == SimpleDialogItem:
            self.__vLayout.addWidget(simpleDialogItem)
            self.__inWidget.append(simpleDialogItem)
        else:
            raise TypeError("Se espera un SimpleDialogItem y se recibio: " + type(simpleDialogItem))

    def setTitle(self, title):
        """ SimpleDialog.setTitle(str)
        Establece el titulo del SimpleDialog
        """
        self.__title.setText(title)
        self.__title.show()


class SimpleDialogItem(QPushButton):
    def __init__(self, icon=None, text=None):
        """ SimpleDialogItem(icon=path, text=str)
        Item utilizado en SimpleDialog
        """
        QPushButton.__init__(self)

        self.__text = QLabel()
        self.__text.setWordWrap(True)

        self.__layout = QHBoxLayout()
        self.__layout.addWidget(self.__text)
        self.setFixedHeight(48)

        self.setLayout(self.__layout)
        if text:
            self.setText(text)

    def setText(self, text):
        """ SimpleDialogItem.setText(str)
        Establece el texto del widget
        """
        self.__text.setText(text)    

test.py

import sys

from PyQt4.QtGui import QApplication
from PyQt4.QtGui import QHBoxLayout
from PyQt4.QtGui import QPushButton, QDialog

from Dialog import SimpleDialog, SimpleDialogItem



class Main(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        b = QPushButton("button")
        b.released.connect(self.hola)

        l = QHBoxLayout()
        l.addWidget(b)

        self.addView(l)

    def hola(self):
        t = "Three line wrapped text goes here making it wrap to next line and continues longer to be here "
        tt = "You'll lose all photos and media."
        ttt = "You'll lose all photos and media."
        sd = SimpleDialog(title="Are you sure?")
        self.item = SimpleDialogItem(text=t, icon="slide_1.jpg")
        self.item.released.connect(self.chao)
        item2 = SimpleDialogItem(text=tt)
        item3 = SimpleDialogItem(text=ttt)
        sd.addItem(self.item)
        sd.addItem(item2)
        sd.addItem(item3)
        sd.exec_()

    def chao(self):
        print "Hola mundo!"


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Main()
    window.activateWindow()
    window.show()

    sys.exit(app.exec_())

这段代码,在 SimpleDialog 中没有检测到 focusOut :( 有什么解决方案吗?

【问题讨论】:

我尝试用户 Qt.Popup 如何 windowFlat 但在窗口中绘制阴影。 您只能放置代码中最重要的部分。 什么是 MainLayout?? 如果你会说西班牙语,最好发到es.***.com MainLayout 是一个修改过的 QWidget :) 在测试中我使用了一个 SimpleDialog 并添加了 3 个 SimpleDialogItem,当我按下添加的 Item 时我想关闭 SimpleDialog。我也在“ES”论坛上问过我的问题,但在这里我可以找到更多条目。 【参考方案1】:

我想向您展示我找到的解决问题的方法。 首先,如何关闭我的小部件 SimpleDialogal 点击它? 我在小部件的末尾做了一个小修改,这样我就可以扩展它并管理它的整个区域。

main = QVBoxLayout()
main.addWidget(...contenido...)

self.fullWidget = QWidget()
self.fullWidget.setLayout(main)
self.fullWidget.setStyleSheet("background-color: RGB(0,0,0,30)")

l = QHBoxLayout()
l.addWidget(self.fullWidget)

self.showFullScreen()
self.setLayout(l)

所以,这样我可以写mouseReleaseEvent 来检测顶部区域以及何时关闭单击

def mouseReleaseEvent(self, QEvent):
    if QApplication.widgetAt(QEvent.pos()) == self.fullWidget:
        self.close()

现在作为解决按下SimpleDialogItem时关闭SimpleDialog问题的方法是关于编写mouseReleaseEvent方法以使用QApplication找到父对象并关闭它

def mouseReleaseEvent(self, *args, **kwargs):
    for widget in QApplication.topLevelWidgets():
        if type(widget) == SimpleDialog:
            widget.close()

【讨论】:

以上是关于如何在点击外部关闭 QDialog 并在点击子小部件时关闭?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过点击外部来关闭 UITextView?

Qt 之 模态非模态半模态窗口的介绍及 实现QDialog的exec()方法

QT编程的QDialog对话框如何设置为不能用鼠标点击后拉大或缩小,也就是我想要一个不能伸缩的对话

通过点击外部关闭 UIAlertViewController

UIAlertView:点击警报框外部时关闭 UIAlertView [重复]

如何在 Flutter 的 ListView 中显示特定小部件的子小部件?