如何从主 window 打开子 window
How to open a child window from the main window
我的问题很难解释,但我正在尽力解决。请在这方面帮助我。
我在 QtDesigner 中设计了一个 gui 并将 .ui 文件转换为 .py 例如main_window.py。现在,为了避免在 main_window.py 中发生变化,我为听众创建了另一个 class。
class Main():
window = None
app = None
def __init__(self):
self.launch()
self.attach_listener()
self.execute()
''' Launch GUI '''
def launch(self):
self.app = QtGui.QApplication(sys.argv)
self.window = Ui_MainWindow()
self.window.show()
''' Execute Window '''
def execute(self):
sys.exit(self.app.exec_())
''' Attach Listeners '''
def attach_listener(self):
self.window.add_button.clicked.connect(self.add_listener)
self.window.delete_button.clicked.connect(self.delete_listener)
self.window.update_button.clicked.connect(self.update_listener)
self.window.connect(self.window.combo_box, QtCore.SIGNAL('activated(QString)'), self.logout_listener)
我有另一个具有相同结构的 child_window.py,但由于 QApplication,我无法从这个 window 打开它。我搜索了答案,但无法应用于我的代码。当 class 从 QtGui.QMainWindow 或 QtGui.QWidget 扩展时,这些答案适用,但我的情况不同。
您将 Ui_MainWindow object 与实际的 window object(QMainWindow、QDialog、QWidget 等)混淆了 self.window = Ui_MainWindow() 不执行任何操作,因为您要附加它的 class 不是 Window。您需要创建一个 window 并将 Ui_MainWindow 应用于它。
Apparent只能 make this work,但它看起来并不漂亮。您需要通过 findChild 访问您的小部件。我能看到的唯一好处是,在设计器中更改表单后,您不需要 运行 pyside-uic,这非常简单。
更简单的方法
当您使用 pyuic / pyside-uic 时,它会将 .ui 文件转换为 .py 文件。
您不应该编辑 .py,因为它们将在您下次使用 QtDesigner 时被覆盖。您需要创建一个 window class 并将 UI class 应用于它。
设置新表单
- 在QtDesigner中生成文件mainWinui.ui - Class name MainWindow
- 转换为 pyside-uic -o mainWinui.py mainWinui.ui。 mainWinui.py 从未被手工编辑过
- 创建 mainWinClass.py 以加载 ui.py 并完成所有自定义 UI 工作
- 在mainWinClass.py
中声明信号和槽,使用.connect等
其中一些模块名称可能看起来有点尴尬,但我已经决定使用它们,因为过去我遇到过模块和 classes 之间的名称冲突问题;由于我不了解 Qt Designer 将如何处理它的命名。
如果您查看 pyside-uic 创建的文件,它的顶部包含您需要在 mainWinClass.py[=23= 中使用的正确 class 和方法名称]
mainWinui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainWinui.ui'
#
# Created: Sun Feb 7 14:22:09 2016
# by: pyside-uic 0.2.15 running on PySide 1.2.4
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
创建一个新的 mainwinClass.py 并将正确的导入和 class 名称复制到其中,加上一些样板文件来加载 .ui.
看起来像这样:
mainWinClass.py
from mainWinui import Ui_MainWindow
from PySide import QtGui
class MainWin(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setup_signals()
# Is this is the same as your Listeners ??
def setup_signals(self):
# Signal for updating the lineedits from the grid
self.ui.tabWidget.currentChanged.connect(self.onTabChanged)
# Connect the "Add Staff" button to the addStaffMember method
self.ui.btnAddStaff.clicked.connect(self.addStaffMember)
然后使用另一个文件来启动应用程序本身,并维护应用程序的一些非 GUI 方面,例如更新程序或全局日志记录。
我已经看到所有 child windows 都在此处实例化的代码,但我(通常)不会那样做。我将它们保留在主窗体中。这取决于您打算如何设计应用程序。
appname.py
from PySide import QtGui, QtCore
from mainwinClass import MainWin
import sys
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainWin = MainWin()
mainWin.show()
sys.exit(app.exec_())
# Nothing else _needed_ in here
现在对于任何 child windows 再次执行相同的操作。
情态形式
在 Qt Designer 中创建一个新的 'Dialog with buttons bottom'。
根据需要添加小部件并另存为 dialogAddStaffui.ui.
运行
pyside-uic -o dialogAddStaffui.py dialogAddStaffui.ui.
创建一个名为 dialogAddStaffClass.py 的新的空文本文档并使用
dialogAddStaffui.ui 作为 class 名称等的参考。将 dialogAddStaffClass.py 编辑为如下所示:
dialogAddStaffClass
from dialogAddStaffui import Ui_DialogAddStaff
from PySide import QtCore, QtGui
class DialogAddStaff(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_DialogAddStaff()
self.ui.setupUi(self)
# Your own init stuff
这两个导入是这里唯一需要的。
如果你想复制这个,请注意我在 Qt Designer 中有
windowModality = ApplicationModal 并且表单是 "Dialog with Buttons Bottom"
对于这些简单的表单,它们有一个接受方法来检查用户输入的数据的有效性并使用 self.done(1) 关闭。
如果您想查看如何处理验证和关闭:
dialogAddStaffClass
def validate(self):
retval = True
if not self.ui.editLname.text():
retval = False
QtGui.QMessageBox.information(self, 'Invalid Last name',
"Last Name must not be blank")
self.ui.editLname.setFocus()
return retval
def accept(self):
if self.validate():
self.done(1)
对于这些对话框窗体,Qt 已自动将确定按钮设置为触发接受。我只是推翻了那个方法。
如果您想在 parent 和 child 之间进行通信,您可以在引用 parent 的 child 上设置 属性,或者阅读child 在它关闭之后但在它的变量被垃圾收集之前的属性。创建循环引用可能会出现问题,所以要小心。
由于新窗体是模态的,用户在关闭 Child 窗体之前无法与主窗体交互,并且启动子 d window 的功能将停止,直到child window 已关闭,因此可以使用局部变量来保存 child class.
'Add Staff' 按钮已连接到 addStaffMember 函数。
mainWinClass.py
from dialogAddStaffClass import DialogAddStaff
def addStaffMember(self):
addStaffForm = DialogAddStaff()
res = addStaffForm.exec_() # exec_ waits, show would continue
# Function waits here for the Modal form to close.
if res: # child was closed with OK and validated correctly
print(addStaffForm.ui.editLname.text())
# Saveing other Staff data happens here
因为 child 表单是 运行 with exec_,所以主表单会等到 child 表单关闭后再继续 uing。当函数退出时,addStaffForm 变量被垃圾回收,因此不再有任何对 child 表单属性的引用。 (可能没有表格...)
如果你想打开一个长期存在的形式,你可以在更持久的地方实例化它。
非模态形式
这是一个 SisterForm 的例子。它是在设计器中从 'Main Window' 类型创建的(它有自己的菜单和状态栏等)。如果您不需要这些装饰,请使用 Dialog 表单,但将其 windowModality 设置为 NonModal。
- 在 Qt Designer 中创建 sisterWinui.ui - 设置 objectName SisterWin
- pyside-uic -o sisterWinui.py sisterWinui.ui
- 创建一个文件sisterwinClass.py - 设置它的导入和初始化
- 创建一个变量将其保存在一个长期存在的地方(MainWin itsef、使用自我。 ref 属性)
- 为其制作一个启动按钮并将其连接到 MainWin 中的方法 Class
sisterWinui.ui
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'sisterWinui.ui'
#
# Created: Mon Feb 8 12:05:37 2016
# by: pyside-uic 0.2.15 running on PySide 1.2.4
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
class Ui_SisterWin(object):
def setupUi(self, SisterWin):
SisterWin.setObjectName("SisterWin")
运行 uic
pyside-uic -o sisterWinui.py sisterWinui.ui
创建一个文件sisterwinClass.py - 设置它的导入和初始化
sisterwinClass.py
from sisterWinui import Ui_SisterWin
from PySide import QtCore, QtGui
class SisterWin(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_SisterWin()
self.ui.setupUi(self)
# Your custom stuff after this
在 Qt Designer 中,向您的主窗体添加一个按钮或其他任何东西以启动 sisterForm。然后对mainwinClass进行一些编辑。
创建一个变量将其保存在一个长期存在的地方
mainwinClass
from sisterwinClass import SisterWin
# no other new imports needed, just the stuff you had before
class MainWin(QtGui.QMainWindow):
def __init__(self, parent=None):
# These three lines were already there
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Add a long lived attribute to hold the class instance
self.sisterWin = None
# Next line was already there
self.setup_signals()
def setup_signals(self):
# Connect button to openSisterWin
self.ui.btnSisterwin.clicked.connect(self.openSisterWin)
# You probably have other connects after this
# This toggles the window
def openSisterWin(self):
if not self.sisterWin:
self.sisterWin = SisterWin()
if self.sisterWin.isVisible():
print('Hiding')
self.sisterWin.hide()
# hide or close, it's your choice
# self.sisterWin.close()
else:
print('Showing')
self.sisterWin.show()
我希望这涵盖了您现在正在寻找的内容?
如果想知道如何隐藏主要 window ,请查看 here
快乐黑客:-)
我的问题很难解释,但我正在尽力解决。请在这方面帮助我。
我在 QtDesigner 中设计了一个 gui 并将 .ui 文件转换为 .py 例如main_window.py。现在,为了避免在 main_window.py 中发生变化,我为听众创建了另一个 class。
class Main():
window = None
app = None
def __init__(self):
self.launch()
self.attach_listener()
self.execute()
''' Launch GUI '''
def launch(self):
self.app = QtGui.QApplication(sys.argv)
self.window = Ui_MainWindow()
self.window.show()
''' Execute Window '''
def execute(self):
sys.exit(self.app.exec_())
''' Attach Listeners '''
def attach_listener(self):
self.window.add_button.clicked.connect(self.add_listener)
self.window.delete_button.clicked.connect(self.delete_listener)
self.window.update_button.clicked.connect(self.update_listener)
self.window.connect(self.window.combo_box, QtCore.SIGNAL('activated(QString)'), self.logout_listener)
我有另一个具有相同结构的 child_window.py,但由于 QApplication,我无法从这个 window 打开它。我搜索了答案,但无法应用于我的代码。当 class 从 QtGui.QMainWindow 或 QtGui.QWidget 扩展时,这些答案适用,但我的情况不同。
您将 Ui_MainWindow object 与实际的 window object(QMainWindow、QDialog、QWidget 等)混淆了 self.window = Ui_MainWindow() 不执行任何操作,因为您要附加它的 class 不是 Window。您需要创建一个 window 并将 Ui_MainWindow 应用于它。
Apparent只能 make this work,但它看起来并不漂亮。您需要通过 findChild 访问您的小部件。我能看到的唯一好处是,在设计器中更改表单后,您不需要 运行 pyside-uic,这非常简单。
更简单的方法
当您使用 pyuic / pyside-uic 时,它会将 .ui 文件转换为 .py 文件。 您不应该编辑 .py,因为它们将在您下次使用 QtDesigner 时被覆盖。您需要创建一个 window class 并将 UI class 应用于它。
设置新表单
- 在QtDesigner中生成文件mainWinui.ui - Class name MainWindow
- 转换为 pyside-uic -o mainWinui.py mainWinui.ui。 mainWinui.py 从未被手工编辑过
- 创建 mainWinClass.py 以加载 ui.py 并完成所有自定义 UI 工作
- 在mainWinClass.py 中声明信号和槽,使用.connect等
其中一些模块名称可能看起来有点尴尬,但我已经决定使用它们,因为过去我遇到过模块和 classes 之间的名称冲突问题;由于我不了解 Qt Designer 将如何处理它的命名。
如果您查看 pyside-uic 创建的文件,它的顶部包含您需要在 mainWinClass.py[=23= 中使用的正确 class 和方法名称]
mainWinui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainWinui.ui'
#
# Created: Sun Feb 7 14:22:09 2016
# by: pyside-uic 0.2.15 running on PySide 1.2.4
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
创建一个新的 mainwinClass.py 并将正确的导入和 class 名称复制到其中,加上一些样板文件来加载 .ui.
看起来像这样:
mainWinClass.py
from mainWinui import Ui_MainWindow
from PySide import QtGui
class MainWin(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.setup_signals()
# Is this is the same as your Listeners ??
def setup_signals(self):
# Signal for updating the lineedits from the grid
self.ui.tabWidget.currentChanged.connect(self.onTabChanged)
# Connect the "Add Staff" button to the addStaffMember method
self.ui.btnAddStaff.clicked.connect(self.addStaffMember)
然后使用另一个文件来启动应用程序本身,并维护应用程序的一些非 GUI 方面,例如更新程序或全局日志记录。 我已经看到所有 child windows 都在此处实例化的代码,但我(通常)不会那样做。我将它们保留在主窗体中。这取决于您打算如何设计应用程序。
appname.py
from PySide import QtGui, QtCore
from mainwinClass import MainWin
import sys
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mainWin = MainWin()
mainWin.show()
sys.exit(app.exec_())
# Nothing else _needed_ in here
现在对于任何 child windows 再次执行相同的操作。
情态形式
在 Qt Designer 中创建一个新的 'Dialog with buttons bottom'。 根据需要添加小部件并另存为 dialogAddStaffui.ui.
运行
pyside-uic -o dialogAddStaffui.py dialogAddStaffui.ui.
创建一个名为 dialogAddStaffClass.py 的新的空文本文档并使用 dialogAddStaffui.ui 作为 class 名称等的参考。将 dialogAddStaffClass.py 编辑为如下所示:
dialogAddStaffClass
from dialogAddStaffui import Ui_DialogAddStaff
from PySide import QtCore, QtGui
class DialogAddStaff(QtGui.QDialog):
def __init__(self, parent=None):
QtGui.QDialog.__init__(self, parent)
self.ui = Ui_DialogAddStaff()
self.ui.setupUi(self)
# Your own init stuff
这两个导入是这里唯一需要的。 如果你想复制这个,请注意我在 Qt Designer 中有
windowModality = ApplicationModal 并且表单是 "Dialog with Buttons Bottom"
对于这些简单的表单,它们有一个接受方法来检查用户输入的数据的有效性并使用 self.done(1) 关闭。 如果您想查看如何处理验证和关闭:
dialogAddStaffClass
def validate(self):
retval = True
if not self.ui.editLname.text():
retval = False
QtGui.QMessageBox.information(self, 'Invalid Last name',
"Last Name must not be blank")
self.ui.editLname.setFocus()
return retval
def accept(self):
if self.validate():
self.done(1)
对于这些对话框窗体,Qt 已自动将确定按钮设置为触发接受。我只是推翻了那个方法。
如果您想在 parent 和 child 之间进行通信,您可以在引用 parent 的 child 上设置 属性,或者阅读child 在它关闭之后但在它的变量被垃圾收集之前的属性。创建循环引用可能会出现问题,所以要小心。
由于新窗体是模态的,用户在关闭 Child 窗体之前无法与主窗体交互,并且启动子 d window 的功能将停止,直到child window 已关闭,因此可以使用局部变量来保存 child class.
'Add Staff' 按钮已连接到 addStaffMember 函数。
mainWinClass.py
from dialogAddStaffClass import DialogAddStaff
def addStaffMember(self):
addStaffForm = DialogAddStaff()
res = addStaffForm.exec_() # exec_ waits, show would continue
# Function waits here for the Modal form to close.
if res: # child was closed with OK and validated correctly
print(addStaffForm.ui.editLname.text())
# Saveing other Staff data happens here
因为 child 表单是 运行 with exec_,所以主表单会等到 child 表单关闭后再继续 uing。当函数退出时,addStaffForm 变量被垃圾回收,因此不再有任何对 child 表单属性的引用。 (可能没有表格...)
如果你想打开一个长期存在的形式,你可以在更持久的地方实例化它。
非模态形式
这是一个 SisterForm 的例子。它是在设计器中从 'Main Window' 类型创建的(它有自己的菜单和状态栏等)。如果您不需要这些装饰,请使用 Dialog 表单,但将其 windowModality 设置为 NonModal。
- 在 Qt Designer 中创建 sisterWinui.ui - 设置 objectName SisterWin
- pyside-uic -o sisterWinui.py sisterWinui.ui
- 创建一个文件sisterwinClass.py - 设置它的导入和初始化
- 创建一个变量将其保存在一个长期存在的地方(MainWin itsef、使用自我。 ref 属性)
- 为其制作一个启动按钮并将其连接到 MainWin 中的方法 Class
sisterWinui.ui
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'sisterWinui.ui'
#
# Created: Mon Feb 8 12:05:37 2016
# by: pyside-uic 0.2.15 running on PySide 1.2.4
#
# WARNING! All changes made in this file will be lost!
from PySide import QtCore, QtGui
class Ui_SisterWin(object):
def setupUi(self, SisterWin):
SisterWin.setObjectName("SisterWin")
运行 uic
pyside-uic -o sisterWinui.py sisterWinui.ui
创建一个文件sisterwinClass.py - 设置它的导入和初始化
sisterwinClass.py
from sisterWinui import Ui_SisterWin
from PySide import QtCore, QtGui
class SisterWin(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_SisterWin()
self.ui.setupUi(self)
# Your custom stuff after this
在 Qt Designer 中,向您的主窗体添加一个按钮或其他任何东西以启动 sisterForm。然后对mainwinClass进行一些编辑。 创建一个变量将其保存在一个长期存在的地方
mainwinClass
from sisterwinClass import SisterWin
# no other new imports needed, just the stuff you had before
class MainWin(QtGui.QMainWindow):
def __init__(self, parent=None):
# These three lines were already there
QtGui.QMainWindow.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# Add a long lived attribute to hold the class instance
self.sisterWin = None
# Next line was already there
self.setup_signals()
def setup_signals(self):
# Connect button to openSisterWin
self.ui.btnSisterwin.clicked.connect(self.openSisterWin)
# You probably have other connects after this
# This toggles the window
def openSisterWin(self):
if not self.sisterWin:
self.sisterWin = SisterWin()
if self.sisterWin.isVisible():
print('Hiding')
self.sisterWin.hide()
# hide or close, it's your choice
# self.sisterWin.close()
else:
print('Showing')
self.sisterWin.show()
我希望这涵盖了您现在正在寻找的内容? 如果想知道如何隐藏主要 window ,请查看 here 快乐黑客:-)