如果没有父窗口,则无法在 PyQt 中创建新窗口 [英] Cannot create a new window in PyQt without it having a parent

查看:57
本文介绍了如果没有父窗口,则无法在 PyQt 中创建新窗口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始使用 PyQt 在 Python 中编写一个简单的文本编辑器,但遇到了这个问题:对于新建文档"按钮,我想打开一个新的空文本编辑器,无论第一个窗口发生什么,它都保持打开状态.问题是,我让它显示窗口的唯一方法是,如果我将 self 作为参数发送(使其成为父窗口),这会导致第二个窗口在父窗口关闭时关闭.

I started coding a simple text editor in Python with PyQt and I ran into this problem: for the "New document" button I want to open a new empty text editor which stays open no matter what happened to the first window. The problem is that the only way I got it to show the window is if I send self as a parameter(making it the parent) which leads to the second window closing when the parent closes.

这是我的构造函数:

class Main(QtGui.QMainWindow):

def __init__(self, ctrl, parent=None):
    QtGui.QMainWindow.__init__(self, parent)

这是打开一个新窗口的方法:

and here's the method that opens a new window:

def new(self):
    repo = Repository()
    ctrl = Controller(repo)
    new_win = Main(ctrl)
    new_win.show()

注意:当这里的代码不起作用时,它只是不显示第二个窗口

Note: when the code that is here doesn't work, it just doesn't show the second window

编辑:决定我应该发布我所有的代码,所以这里是:

Edit: decided I should post all my code, so here it goes:

import sys

from PyQt4 import QtGui

from src.controller import Controller
from src.repository import Repository


class Main(QtGui.QMainWindow):

    nr_of_instances = -1

    def __init__(self, ctrl, parent=None):
        QtGui.QMainWindow.__init__(self, parent)
        Main.nr_of_instances += 1
        #ui elements
        self._toolbar = None
        self._menuBar = None
        self._file = None
        self._edit = None
        self._view = None
        self._formatBar = None
        self._statusBar = None
        self._text = None

        #actions
        self._newAction = None
        self._openAction = None
        self._saveAction = None
        self._saveAsAction = None

        #
        self._controller = ctrl

        self.init_ui()

    def init_ui(self):
        self._text = QtGui.QTextEdit(self)
        self.setCentralWidget(self._text)

        self.init_toolbar()
        self.init_formatBar()
        self.init_menuBar()
        self._statusBar = self.statusBar()

        self.setGeometry(50+(50*Main.nr_of_instances), 100+(50*Main.nr_of_instances), 800, 400)

        self.setWindowTitle("KekWriter")

    @staticmethod
    def new(self):
        repo = Repository()
        ctrl = Controller(repo)
        spawn = Main(ctrl)
        spawn.show()

    def set_title(self):
        if self._controller.get_file_name() != 0:
            new_title = self.windowTitle().split(" - ")
            new_title[0].strip()
            self.setWindowTitle(new_title[0]+" - "+self._controller.get_file_name())

    def open(self):
        fn = QtGui.QFileDialog.getOpenFileName(self, 'Open File', ".")
        self._controller.set_file_name(fn)
        try:
            if fn != '':
                self._text.setText(self._controller.open())
            self.set_title()
        except UnicodeDecodeError as msg:
            QtGui.QMessageBox.information(self, "Eroare!", "Tip de fisier invalid!")

    def _save_as(self):
        fn = QtGui.QFileDialog.getSaveFileName(self, 'Save File As', ".")
        print(fn)
        if fn != '':
            self._controller.set_file_name(fn)
            self._controller.save(self._text.toPlainText())
            self.set_title()

    def save(self):
        fn = self._controller.get_file_name()
        if fn == '':
            self._save_as()
        else:
            self._controller.save(self._text.toPlainText())
            self.set_title()

    def init_toolbar(self):
        self._newAction = QtGui.QAction(QtGui.QIcon("icons/new.png"), "New", self)
        self._newAction.setStatusTip("Creates a new document")
        self._newAction.setShortcut("Ctrl+N")
        self._newAction.triggered.connect(self.new)

        self._openAction = QtGui.QAction(QtGui.QIcon("icons/open.png"), "Open", self)
        self._openAction.setStatusTip("Opens existing document")
        self._openAction.setShortcut("Ctrl+O")
        self._openAction.triggered.connect(self.open)

        self._saveAction = QtGui.QAction(QtGui.QIcon("icons/save.png"), "Save", self)
        self._saveAction.setStatusTip("Saves current document")
        self._saveAction.setShortcut("Ctrl+S")
        self._saveAction.triggered.connect(self.save)

        self._saveAsAction = QtGui.QAction(QtGui.QIcon("icons/save_as.png"), "Save as", self)
        self._saveAsAction.setStatusTip("Saves current document with another name")
        self._saveAsAction.setShortcut("Ctrl+Shift+S")
        self._saveAsAction.triggered.connect(self._save_as)

        self._toolbar = self.addToolBar("Options")

        self._toolbar.addAction(self._newAction)
        self._toolbar.addAction(self._openAction)
        self._toolbar.addAction(self._saveAction)
        self._toolbar.addAction(self._saveAsAction)

        self.addToolBarBreak()

    def init_menuBar(self):
        self._menuBar = self.menuBar()
        self._file = self._menuBar.addMenu("File")
        self._edit = self._menuBar.addMenu("Edit")
        self._view = self._menuBar.addMenu("View")

        #file
        self._file.addAction(self._newAction)
        self._file.addAction(self._openAction)
        self._file.addAction(self._saveAction)
        self._file.addAction(self._saveAsAction)

    def init_formatBar(self):
        self._formatBar = self.addToolBar("Format")
        self.addToolBarBreak()


def main():
    app = QtGui.QApplication(sys.argv)
    repo = Repository()
    ctrl = Controller(repo)
    main = Main(ctrl)
    main.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

推荐答案

第二个窗口没有显示的原因是因为窗口对象超出范围并且被垃圾回收.您需要在某处存储对第二个窗口的引用,该引用在窗口关闭之前不会被删除.

The reason your second window doesn't show is because the window object goes out of scope and is garbage collected. You need to store a reference to the second window somewhere which won't be deleted until the window is closed.

我能想到有几种方法可以做到这一点,但这取决于您想要如何构建程序.

There are a few ways to do this that I can think of, but it is really up to you with how you want to structure your program.

  1. 有一个 Main 的类属性,它是一个列表.因此,此列表对所有实例都是通用的,您可以在创建该列表时将新实例附加到该列表中.只要存在一个实例,窗口就不应该被垃圾收集(我认为)

  1. Have a class attribute of Main which is a list. This list will thus be common to all instances and you can append a new instance to that list when it is created. As long as one instance exists, the window shouldn't be garbage collected (I think)

一开始不要实例化 QMainWindow,而是实例化一个将保存对窗口的引用的类.创建新窗口时,在此对象中删除对新窗口的引用.

Don't instantiate a QMainWindow initially, but instead instantiate a class that will hold references to windows. When a new window is created, sore the reference to the new window in this object.

希望这能让您了解问题所在,以便您能够以适合您程序布局的方式解决问题

Hopefully this gives you an idea of what is wrong so you can solve it in a way that suits the layout of your program

有关如何执行选项 2 的粗略指南:

For a rough guide of how you would do option 2:

class WindowContainer(object):
    def __init__(self):
        self.window_list = []
        self.add_new_window()

    def add_new_window(self):
        repo = Repository()
        ctrl = Controller(repo)
        spawn = Main(ctrl, self)
        self.window_list.append(spawn)
        spawn.show()


class Main(QtGui.QMainWindow):
    def __init__(self, ctrl, window_container, parent=None):
        QtGui.QMainWindow.__init__(self, parent) 
        ...
        self.window_container = window_container
        ...

    ...

    def init_toolbar(self):
        ...
        self._newAction.triggered.connect(self.window_container.add_new_window)
        ...

    ...


def main():
    app = QtGui.QApplication(sys.argv)
    # this variable will never go out of scope
    window_container = WindowContainer()
    sys.exit(app.exec_())

这篇关于如果没有父窗口,则无法在 PyQt 中创建新窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆