设置 QDialog 框并保留对 QDialog 中元素的访问的最佳方法?
Posted
技术标签:
【中文标题】设置 QDialog 框并保留对 QDialog 中元素的访问的最佳方法?【英文标题】:Best approach to setting up QDialog boxes and retain access to elements in the QDialog? 【发布时间】:2017-12-11 13:41:56 【问题描述】:我目前正在运行 QDialog 的这个实现,它可以满足我的需要,但似乎不是最佳实践方法,并且存在我似乎无法解决的缺陷。我知道 QDialog 可以实现为类或方法,但我需要能够访问 QDialog 的元素,例如 QLineEdit
和 QComboBox
,除了我在下面列出的代码之外,我不确定如何执行此操作. QDialog
中与 QComboBox
关联的所有值都会立即应用,因此在 QDialog 关闭后无需保留其副本。
Test.py
from PyQt5 import uic
from PyQt5.Qt import Qt
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
Ui_MainWindow = uic.loadUiType('TestMainWindow.ui')[0]
Ui_ExampleDialog = uic.loadUiType('TestExampleDialog.ui')[0]
class ExampleDialog(QDialog, Ui_ExampleDialog):
def __init__(self, parent=None, flags=Qt.Dialog):
QDialog.__init__(self, parent, flags)
self.setupUi(self)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None, flags=Qt.Window):
QMainWindow.__init__(self, parent, flags)
self.setupUi(self)
self.setWindowTitle('MCVE')
# THIS DOES NOT SEEM APPROPRIATE, BUT I NEED TO ACCESS
# ELEMENTS OF THE UI FILE OUTSIDE OF 'showExampleDialog'
self.exampleDialog = ExampleDialog()
self.itemInfoBtn.clicked.connect(self.showExampleDialog)
self.setupItemInfo()
def showExampleDialog(self):
# ACCORDING TO PYCHARM 'self' IS 'QMainWindow',
# DO I ASSUME THAT 'parent = QMainWindow'?
self.exampleDialog.setWindowFlags(Qt.WindowCloseButtonHint)
self.exampleDialog.closeButton.clicked.connect(self.exampleDialog.accept)
self.exampleDialog.exec_() # CREATES A TASKBAR ENTRY ... BUT WHY?
def setupItemInfo(self):
# THIS IS AN EXAMPLE OF HOW I'M CURRENTLY ACCESSING
# ELEMENTS OF THE `showExampleDialog' DIALOG
val = 'Entry #3', 'Entry #2', 'Entry #1'
self.exampleDialog.setWindowTitle('Example Dialog')
self.exampleDialog.exampleCombo.insertItems(0, val)
self.exampleDialog.exampleCombo.setCurrentIndex(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
TestMainWindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>282</width>
<height>173</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="itemInfoBtn">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>ItemInfoBtn</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>
TestExampleDialog.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="windowModality">
<enum>Qt::ApplicationModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>174</width>
<height>98</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="Message">
<property name="text">
<string>I'm a Dialog ...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="exampleCombo"/>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
我遇到的一个问题是QDialog
在QMainWindow
旁边创建了第二个任务栏条目。这对我来说没有意义。据我了解,QDialog
可以是模态的或无模态的,我相信我当前的实现具有模态集。考虑到这一点,PyCharm 说 self 是 QMainWindow 所以我假设它继承了应该防止第二个任务栏条目填充的父级。也许我错了。
我遇到的另一个问题是访问QDialog
的元素和当它作为一个类实现时的变量,我不完全确定如何做到这一点,而且我的研究并没有真正解释清楚。理解方式。
解决此问题的最佳方法是什么?如何防止 QDialog
创建第二个任务栏条目?
【问题讨论】:
看起来好像您错误地使用了返回的小部件。您应该在给定的小部件上运行“setupUI”,在您的情况下是 QDialog 的实例。见pyqt.sourceforge.net/Docs/PyQt5/designer.html#the-uic-module @deets 在阅读完文档后,这是否意味着我需要使用 pyuic5 编译 UI 文件,将它们导入为from ui_file import ui_class
?这种方法似乎不太经济,因为我的应用程序仍在开发中,并且 UI 文件的更改正在迅速发生,因此直接加载 UI 文件会删除很多步骤。此外,我将QDialog
的 UI 文件分配给了self.exampleDialog
,因此我可以访问 UI 文件中的对象,尽管这对我来说似乎并不正确,而且我不知道如何解决这个问题。
不,不是这个意思。文档有点不清楚,但是如果您实例化自己,或者使用 loadUIC 来获取实例,这应该没关系。但这两种情况下都需要 setupUi。此外,即使您必须使用 pyuic,这也只是 ui 修改后的构建步骤。关于你的第二个问题:为什么感觉不对?如果你想访问东西,你必须让它们可以访问。我看不出有什么办法。
请不要getter和setter! Python 不是 Java!您对相关小部件的访问是基于它们的名称,这正是这样做的正确方法,因为它将周围代码的交互点与小部件的内部结构分离。 Python 允许比其他语言更强大的属性概念在这里工作,因此您可以获得“dialog.widgetName”-模式。顺便说一句,我会遵循小部件名称的 python 命名约定,因为现在它们看起来像类名。当然还有更多语义命名 - ComboBox 是一种类型,而不是具体的列表,例如国家。
@AaronTomason。 self.exampleDialog.setWindowFlags(self.exampleDialog.windowFlags() | Qt.WindowCloseButtonHint)
。 (而且你需要导入QDialog
)。
【参考方案1】:
这完全解决了这个问题。将 self 分配给 self.exampleDialog = ExampleDialog(self)
并更新 self.exampleDialog.setWindowFlags
以包含 self.exampleDialog.windowFlags()
消除了第二个任务栏条目。
可以使用self.exampleDialog.<element>
访问对话框的元素,例如self.exampleDialog.setWindowTitle('Example Dialog')
from PyQt5 import uic
from PyQt5.Qt import Qt
from PyQt5.QtWidgets import QApplication, QDialog, QMainWindow
import sys
Ui_MainWindow = uic.loadUiType('TestMainWindow.ui')[0]
Ui_ExampleDialog = uic.loadUiType('TestExampleDialog.ui')[0]
class ExampleDialog(QDialog, Ui_ExampleDialog):
def __init__(self, parent = None, flags = Qt.Dialog):
QDialog.__init__(self, parent, flags)
self.setupUi(self)
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent = None, flags = Qt.Window):
QMainWindow.__init__(self, parent, flags)
self.setupUi(self)
self.setWindowTitle('MCVE')
# Assign 'self' to 'ExampleDialog' so we can
# access elements of the dialog.
self.exampleDialog = ExampleDialog(self)
self.itemInfoBtn.clicked.connect(self.showExampleDialog)
self.setupItemInfo()
def showExampleDialog(self):
self.exampleDialog.setWindowFlags(self.exampleDialog.windowFlags() | Qt.WindowCloseButtonHint)
self.exampleDialog.closeButton.clicked.connect(self.exampleDialog.accept)
self.exampleDialog.exec_() # CREATES A TASKBAR ENTRY ... BUT WHY?
def setupItemInfo(self):
val = 'Entry #3', 'Entry #2', 'Entry #1'
self.exampleDialog.setWindowTitle('Example Dialog')
self.exampleDialog.exampleCombo.insertItems(0, val)
self.exampleDialog.exampleCombo.setCurrentIndex(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
【讨论】:
以上是关于设置 QDialog 框并保留对 QDialog 中元素的访问的最佳方法?的主要内容,如果未能解决你的问题,请参考以下文章