如何从主窗口打开子窗口

时间:2016-02-07 15:32:02

标签: python pyqt window childwindow

我的问题很难解释,但我正在尽我所能。请帮助我。

我在QtDesigner中设计了一个gui,并将.ui文件转换为.py文件,例如main_window.py。现在为了避免在main_window.py中进行更改,我为侦听器创建了另一个类。

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,我无法从这个窗口打开该窗口。我搜索了答案,但无法应用于我的代码。当课程从QtGui.QMainWindow或QtGui.QWidget扩展时,这些答案适用,但我的情况不同。

1 个答案:

答案 0 :(得分:4)

您正在将Ui_MainWindow对象与实际窗口对象(QMainWindow,QDialog,QWidget等)混合.self.window = Ui_MainWindow()没有做任何事情,因为您要将其附加到的类不是Window 。您需要创建一个窗口并将Ui_MainWindow应用于它。

显然你可以make this work,但它看起来并不漂亮。您需要通过findChild访问您的小部件。我能看到的唯一好处就是你在改变设计师的形式后不会运行pyside-uic,这很容易。

更简单的方法

当您使用pyuic / pyside-uic时,它会将.ui文件转换为.py文件。 您不应该编辑.py,因为下次使用QtDesigner时它们会被覆盖。您需要创建一个窗口类并将UI类应用于它。

设置新表单

  • 在QtDesigner中生成文件mainWinui.ui - 类名称MainWindow
  • 转换为pyside-uic -o mainWinui.py mainWinui.ui。 mainWinui.py永远不会手工编辑
  • 创建mainWinClass.py以加载ui.py并执行所有自定义UI工作
  • 声明信号和插槽,在mainWinClass.py
  • 中使用.connect等

这些模块名称中的一些可能看起来有点尴尬,但我已经确定了它们,因为在过去我遇到了模块和类之间名称冲突的问题;我不明白Qt Designer如何处理它的命名。

如果你查看pyside-uic创建的文件,它的顶部包含你需要在mainWinClass.py中使用的正确的类和方法名称

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并将正确的导入和类名复制到它,再加上一些样板来加载.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方面,如更新程序或全局日志记录。 我已经看过所有子窗口都在这里被实例化的代码,但我不是(通常)那样做的。我将它们保留在主窗体中。这取决于您打算如何设计应用程序。

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

现在任何子窗口都会再次出现这种情况。

模态表格

在Qt Designer中创建一个新的'对话框底部带按钮'。 根据需要添加小部件并另存为dialogAddStaffui.ui。

运行

pyside-uic -o dialogAddStaffui.py dialogAddStaffui.ui.

创建一个名为dialogAddStaffClass.py并使用的新的空文本文档  dialogAddStaffui.ui作为类名的引用等。编辑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,表格是一个"对话框,按钮底部"

对于这些简单形式,它们有一个accept方法,用于检查用户输入的数据的有效性,并使用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自动将OK按钮设置为触发接受。我只是覆盖了这种方法。

如果您想要父和子之间的通信,您可以在引用父项的子项上设置属性,或者在子项关闭后读取子项的属性,但在它变量被垃圾收集之前。创建循环引用可能存在问题,所以要小心。

由于新表单是模态的,因此用户无法与主表单进行交互,直到他们关闭子表单,并且启动chil d窗口的功能将停止,直到子窗口关闭,因此它& #39;可以使用局部变量来保存子类。

'添加员工'按钮已连接到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

因为子表单是用exec_运行的,所以主表单等待直到子表单关闭才继续。当函数退出时,addStaffForm变量被垃圾收集,因此不再引用子表单的属性。 (可能没有形式......)

如果你想打开一个Long Living表单,你可以将它实例化到更持久的地方。

非模态表格

以下是SisterForm的示例。它是在“主窗口”的设计者中创建的。类型(它有它自己的菜单和状态栏等)。如果您不需要这些装饰,请使用对话框表格,但将它的windowModality设置为NonModal。

  • 在Qt Designer中创建sisterWinui.ui - 设置objectName SisterWin
  • pyside-uic -o sisterWinui.py sisterWinui.ui
  • 创建一个文件sisterwinClass.py - 设置它的import和init
  • 创建一个变量以将其保存在长期居住的地方(MainWin本身,使用self.ref属性)
  • 为它创建一个启动按钮并将其连接到MainWin类
  • 中的方法

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 - 设置它的import和init

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()

我希望现在涵盖你想要的东西? 如果想要了解如何隐藏主窗口,请查看here 快乐的黑客行为: - )