小部件可见性更改时在 MacOS 中呈现 Qt 错误表单

Posted

技术标签:

【中文标题】小部件可见性更改时在 MacOS 中呈现 Qt 错误表单【英文标题】:Qt buggy form rendering in MacOS when widget visibility changes 【发布时间】:2019-04-17 09:53:34 【问题描述】:

我在表单上有几个单选按钮和 2 行输入。 根据选中的选项,我只希望其中一个输入可见。

所以,每次用户点击时,我都会通过 setVisible() 函数。

它在 Windows 上运行良好,但在 MacOS 上我看到了伪像。在可见的 lineedit 后面,我看到了隐藏 lineedit 的“残余”:

在 mac os 上是否有任何 hack 来解决这个问题?

PyQt 版本 5

编辑:

根据要求,下面是验证示例。在 MacOS 中使用 python 3 运行它。

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
import sys

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.verticalLayout = QtWidgets.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")
        self.radioButton = QtWidgets.QRadioButton(self.centralwidget)
        self.radioButton.setObjectName("radioButton")
        self.verticalLayout.addWidget(self.radioButton)
        self.radioButton_2 = QtWidgets.QRadioButton(self.centralwidget)
        self.radioButton_2.setObjectName("radioButton_2")
        self.verticalLayout.addWidget(self.radioButton_2)
        self.verticalLayout_3.addLayout(self.verticalLayout)
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit.setVisible(False)
        self.lineEdit.setObjectName("lineEdit")
        self.lineEdit.setPlaceholderText("LineEdit 1")
        self.horizontalLayout.addWidget(self.lineEdit)
        self.pushButton = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton.setVisible(False)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout.addWidget(self.pushButton)
        self.verticalLayout_2.addLayout(self.horizontalLayout)
        self.lineEdit_2 = QtWidgets.QLineEdit(self.centralwidget)
        self.lineEdit_2.setVisible(False)
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.lineEdit_2.setPlaceholderText("LineEdit 2")
        self.verticalLayout_2.addWidget(self.lineEdit_2)
        self.verticalLayout_3.addLayout(self.verticalLayout_2)
        spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.verticalLayout_3.addItem(spacerItem)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.radioButton.setText(_translate("MainWindow", "Option 1"))
        self.radioButton_2.setText(_translate("MainWindow", "Option 2"))
        self.pushButton.setText(_translate("MainWindow", "PushButton"))

class App:
    def __init__(self):
        self.app = QApplication(sys.argv)
        self.window = QMainWindow()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self.window)
        self.ui.radioButton.clicked.connect(self.update_visibility)
        self.ui.radioButton_2.clicked.connect(self.update_visibility)

    def update_visibility(self):
        self.ui.lineEdit.setVisible(self.ui.radioButton.isChecked())
        self.ui.lineEdit_2.setVisible(self.ui.radioButton_2.isChecked())

    def exec(self):
        self.window.show()
        sys.exit(self.app.exec_())

def main():
    a = App()
    a.exec()


if __name__ == "__main__":
    main()

【问题讨论】:

添加示例。 为什么不使用 QStackedWidget 来切换 QLineEdits 的可见性? 你能举个例子吗? 谢谢。堆叠小部件绝对是更好的解决方案。 【参考方案1】:

可能发出信号的错误是 Qt 错误或某些驱动程序不兼容。

我的解决方案朝着另一个方向发展,您可以使用 QButtonGroup 旁边的 QStackedWidget 来设置 QLineEdits 的可见性,而不是隐藏 QLineEdits。

from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        self.import_radiobutton = QtWidgets.QRadioButton(
            "import from file", checked=True
        )
        self.download_radiobutton = QtWidgets.QRadioButton(
            "Download via magnet link"
        )
        self.import_lineedit = QtWidgets.QLineEdit(
            placeholderText="LineEdit 1"
        )
        self.download_lineedit = QtWidgets.QLineEdit(
            placeholderText="LineEdit 2"
        )

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        lay = QtWidgets.QVBoxLayout(central_widget)
        lay.addWidget(self.import_radiobutton)
        lay.addWidget(self.download_radiobutton)
        stacked = QtWidgets.QStackedWidget()
        stacked.setSizePolicy(
            QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum
        )
        lay.addWidget(stacked)
        lay.addStretch()
        buttongroup = QtWidgets.QButtonGroup(self)
        buttongroup.buttonClicked[int].connect(stacked.setCurrentIndex)
        for button, lineedit in zip(
            (self.import_radiobutton, self.download_radiobutton),
            (self.import_lineedit, self.download_lineedit),
        ):
            ix = stacked.addWidget(lineedit)
            buttongroup.addButton(button, ix)
        self.resize(640, 480)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = MainWindow()
    w.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【讨论】:

【参考方案2】:

好的,临时解决方案是每次在窗口或每个有问题的元素上调用 repaint()。然而,它看起来生涩。有更好的解决方案吗?

【讨论】:

以上是关于小部件可见性更改时在 MacOS 中呈现 Qt 错误表单的主要内容,如果未能解决你的问题,请参考以下文章

单击时更改小部件可见性

markdown 根据序列步骤更改窗口小部件可见性

markdown 根据序列步骤更改窗口小部件可见性

markdown 根据序列步骤更改窗口小部件可见性

使用PyQt中的QCheckBox或QComboBox更改小部件可见性

如何切换网格布局中的小部件可见性?