简体   繁体   中英

pyqt non-modal dialog always modal

I have a dialog designed in Qt Designer and set as non-modal that when launched is always modal. I am using OS X El Capitan, Python 3.5.1, Qt 5.4.2, pyqt4.

These code snippets show what I am doing:


Designer .ui code converted to python using pyuic.

from PyQt4 import QtCore, QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_purchaseInfoDialog(object):
    def setupUi(self, purchaseInfoDialog):
        purchaseInfoDialog.setObjectName(_fromUtf8("purchaseInfoDialog"))
        purchaseInfoDialog.setWindowModality(QtCore.Qt.NonModal)
        purchaseInfoDialog.resize(837, 377)
        purchaseInfoDialog.setSizeGripEnabled(True)
        purchaseInfoDialog.setModal(False)
        self.purchaseInfoButtonBox = QtGui.QDialogButtonBox(purchaseInfoDialog)
        self.purchaseInfoButtonBox.setGeometry(QtCore.QRect(710, 330, 101, 32))
        self.purchaseInfoButtonBox.setOrientation(QtCore.Qt.Horizontal)
        self.purchaseInfoButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Close)
        self.purchaseInfoButtonBox.setObjectName(_fromUtf8("purchaseInfoButtonBox"))
        self.purchaseInfoTable = QtGui.QTableWidget(purchaseInfoDialog)
        self.purchaseInfoTable.setGeometry(QtCore.QRect(10, 50, 911, 271))
        self.purchaseInfoTable.setObjectName(_fromUtf8("purchaseInfoTable"))
        self.purchaseInfoTable.setColumnCount(9)
        self.purchaseInfoTable.setRowCount(0)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(0, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(1, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(2, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(3, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(4, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(5, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(6, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(7, item)
        item = QtGui.QTableWidgetItem()
        self.purchaseInfoTable.setHorizontalHeaderItem(8, item)
        self.piPartLabel = QtGui.QLabel(purchaseInfoDialog)
        self.piPartLabel.setGeometry(QtCore.QRect(20, 20, 71, 16))
        self.piPartLabel.setObjectName(_fromUtf8("piPartLabel"))
        self.piPartdescriptionLabel = QtGui.QLabel(purchaseInfoDialog)
        self.piPartdescriptionLabel.setGeometry(QtCore.QRect(120, 20, 191, 16))
        self.piPartdescriptionLabel.setObjectName(_fromUtf8("piPartdescriptionLabel"))
        self.poFromSelectionPushButton = QtGui.QPushButton(purchaseInfoDialog)
        self.poFromSelectionPushButton.setGeometry(QtCore.QRect(540, 330, 171, 32))
        self.poFromSelectionPushButton.setObjectName(_fromUtf8("poFromSelectionPushButton"))

        self.retranslateUi(purchaseInfoDialog)
        QtCore.QObject.connect(self.purchaseInfoButtonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), purchaseInfoDialog.accept)
        QtCore.QObject.connect(self.purchaseInfoButtonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), purchaseInfoDialog.reject)
        #QtCore.QObject.connect(self.poFromSelectionPushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), purchaseInfoDialog.poFromSelection)
        QtCore.QMetaObject.connectSlotsByName(purchaseInfoDialog)

    def retranslateUi(self, purchaseInfoDialog):
        purchaseInfoDialog.setWindowTitle(_translate("purchaseInfoDialog", "Purchase History", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(0)
        item.setText(_translate("purchaseInfoDialog", "#", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(1)
        item.setText(_translate("purchaseInfoDialog", "P.O. #", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(2)
        item.setText(_translate("purchaseInfoDialog", "Vendor", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(3)
        item.setText(_translate("purchaseInfoDialog", "P.O. Date", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(4)
        item.setText(_translate("purchaseInfoDialog", "Mfg", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(5)
        item.setText(_translate("purchaseInfoDialog", "Mpn", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(6)
        item.setText(_translate("purchaseInfoDialog", "Qty", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(7)
        item.setText(_translate("purchaseInfoDialog", "Price", None))
        item = self.purchaseInfoTable.horizontalHeaderItem(8)
        item.setText(_translate("purchaseInfoDialog", "Dock", None))
        self.piPartLabel.setText(_translate("purchaseInfoDialog", "Part", None))
        self.piPartdescriptionLabel.setText(_translate("purchaseInfoDialog", "Description", None))
        self.poFromSelectionPushButton.setText(_translate("purchaseInfoDialog", "P.O. From Selection", None))

I sub-class the designer class

#
# PURCHASE INFO (HISTORY) Dialog
#
# Sub-class Ui_purchaseInfoDialog
class PurchaseInfoDialog(QDialog, Ui_purchaseInfoDialog):
    def __init__(self):
        QDialog.__init__((self))
        self.setModal(False)

Commented code below shows attempts to make it non-modal even though it should be. Nothing works.

   self.ui.orderPartButton.clicked.connect(lambda: self.orderPartButtonClicked())

#
# Parts Slots
#
#

@pyqtSlot()
def orderPartButtonClicked(self):
    selectedPart = MainWindow.ui.partShortagesTable.selectedItems()
    if (selectedPart):
        part = selectedPart[0].text()
        aPurchaseInfoDialog = PurchaseInfoDialog()
        pidUi = Ui_purchaseInfoDialog()
        pidUi.setupUi(aPurchaseInfoDialog)

    refreshPurchaseInfoTable(self, pidUi.purchaseInfoTable, pidUi.piPartLabel, pidUi.piPartdescriptionLabel, part, pathToArchive)

    #aPurchaseInfoDialog.setWindowModality(QtCore.Qt.NonModal)
    result = aPurchaseInfoDialog.exec_()  # Launch the Purchase Info Dialog. result = 0 for Close
    #aPurchaseInfoDialog.show()

Is there a problem with pyqt4 in my environment (I tried this under Linux with the same result) or am I missing some setting somewhere?

Demo:

import sys
from PyQt4 import QtCore
from PyQt4.QtCore import *
from PyQt4.QtGui import *



class Dialog1(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setModal(True)


class Dialog2(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setModal(False)



def window():
    app = QApplication(sys.argv)
    w = QWidget()
    b = QPushButton(w)
    b.setText("Modal Dialog")
    b.move(15, 25)
    b.clicked.connect(showdialog1)

    c = QPushButton(w)
    c.setText("Modless Dialog")
    c.move(15, 75)
    c.clicked.connect(showdialog2)

    w.setWindowTitle("PyQt Dialog demo")
    w.resize(200, 150)
    w.show()
    sys.exit(app.exec_())


def showdialog1():
    # d = QDialog()
    d = Dialog1()
    #d.setWindowModality(QtCore.Qt.Modal)
    b1 = QPushButton("Modal Dialog", d)
    b1.move(50, 50)
    d.setWindowTitle("Modal Dialog")
    d.setWindowModality(Qt.ApplicationModal)
    d.exec_()

def showdialog2():
    # d = QDialog()
    d = Dialog2()
    d.setWindowModality(QtCore.Qt.NonModal)
    b1 = QPushButton("ok", d)
    b1.move(50, 50)
    d.setWindowTitle("Modeless Dialog")
    d.setWindowModality(Qt.ApplicationModal)
    d.exec_()


if __name__ == '__main__':
    window()

I rearranged some of your code because of personal preference (I'm sure you can put it back no problem), and now one is modal, and the other is nonmodal.

When you create a nonmodal window, you must provide a parent QWidget in the instantiation of the QDialog class. Then, instead of using QDialog.exec_() , use QDialog.show() . This shows the nonmodal window but allows the original parent to keep running, in a sense. Using exec_() will always result in a modal window, even if you set it to nonmodal. Here's the documentation: http://pyqt.sourceforge.net/Docs/PyQt4/qdialog.html

Here is the code:

class Dialog1(QDialog):
    def __init__(self):
        QDialog.__init__(self)
        self.setModal(True)


class Dialog2(QDialog):
    def __init__(self, parent):
    QDialog.__init__(self, parent)
    self.setModal(0)
    b1 = QPushButton("ok", self)
    b1.move(50, 50)
    b1.clicked.connect(self.exit)
    self.setWindowTitle("Nonmodal Dialog")

    self.show()

def exit(self):
    self.close()


def window():
    app = QApplication(sys.argv)
    w = QWidget()
    b = QPushButton(w)
    b.setText("Modal Dialog")
    b.move(15, 25)
    b.clicked.connect(showdialog1)

    c = QPushButton(w)
    c.setText("Nonmodal Dialog")
    c.move(15, 75)
    c.clicked.connect(lambda: showdialog2(w))

    w.setWindowTitle("PyQt Dialog demo")
    w.resize(200, 150)
    w.show()
    sys.exit(app.exec_())


def showdialog1():
    # d = QDialog()
    d = Dialog1()
    #d.setWindowModality(QtCore.Qt.Modal)
    b1 = QPushButton("Modal Dialog", d)
    b1.move(50, 50)
    d.setWindowTitle("Modal Dialog")
    d.setWindowModality(Qt.ApplicationModal)
    d.exec_()

def showdialog2(w):
    # d = QDialog()
    Dialog2(w)



if __name__ == '__main__':
    window()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM