如何使用 PyQt 从另一个窗口单击按钮打开一个窗口?

如何使用 PyQt 从另一个窗口单击按钮打开一个窗口?

问题描述:

我正在尝试制作一个应用程序,但我一直被诸如此类的简单"事物所困扰,如何通过单击按钮打开一个新窗口?我尝试使用 new_lib_btn.clicked.connect(newlib)newlib 是包含我的第二个窗口的文件,new_lib_btn 是应该打开的按钮窗口,它在我的主窗口中,你可以在这里看到:

I'm trying to make an application but I keep getting punched by the "simple" things like this one, how do I open a new window though a button click? I tried using new_lib_btn.clicked.connect(newlib), newlib is the file that contains my second window and new_lib_btn is the button that should open the window, it's in my main window as you can see down here:

mainwindow.py

from PyQt4 import QtCore, QtGui
import newlib
import sys
# Main Window

class Window (QtGui.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        centralwidget = QtGui.QWidget(self)
        self.mainLayout = QtGui.QVBoxLayout(centralwidget)
        self.mainLayout.setAlignment(QtCore.Qt.AlignCenter)
        self.setCentralWidget(centralwidget)

        self.resize(800, 600)
        self.setWindowTitle("Virtual Library")
        self.setStyleSheet("Window {border-image: url(lib.jpg);}")

        # ExitOption
        menu_action1 = QtGui.QAction("Exit", self)
        menu_action1.setShortcut("Ctrl+Q")
        menu_action1.setStatusTip('Exit The App')
        menu_action1.triggered.connect(self.close_application)

        self.statusBar()

        # MenuBar
        main_menu = self.menuBar()
        file_menu = main_menu.addMenu('Options')
        file_menu.addAction(menu_action1)



        self.home()

    def home(self):
        # NewLibrary btn
        new_lib_btn = QtGui.QPushButton("New Library", self)
        new_lib_btn.setGeometry(QtCore.QRect(310, 180, 141, 41))
        new_lib_btn.setStyleSheet("color: black;")

        # AccessLibrary btn
        access_lib_btn = QtGui.QPushButton("Access Library", self)
        access_lib_btn.setGeometry(QtCore.QRect(310, 250, 141, 41))
        access_lib_btn.setStyleSheet("color: black;")

        # FindNewBooks btn
        find_nbooks = QtGui.QPushButton("Find New Books*", self)
        find_nbooks.setGeometry(QtCore.QRect(310, 320, 141, 41))
        find_nbooks.setStyleSheet("color: black;")

        self.mainLayout.addWidget(new_lib_btn)
        self.mainLayout.addWidget(access_lib_btn)
        self.mainLayout.addWidget(find_nbooks_btn)
        self.show()

    def close_application(self):
        choice = QtGui.QMessageBox.question(self, 'Exit',
                                        "Close the application?",
                                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        if choice == QtGui.QMessageBox.Yes:
            sys.exit()
        else:
            pass


def run():
    app = QtGui.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())


run()

这是我的第二个窗口,我想用 new_lib_btn

And here's my second window, the one I want to open with the new_lib_btn

newlib.py

class NewLibrary (QtGui.QMainWindow):
    def __init__(self):
         super(NewLibrary, self).__init__()

         self.resize(800,600)
         self.setWindowTitle("New Library")
         self.setStyleSheet("NewLibrary {border-image: url(wood.jpg);}")

         # File Options
         file_action1 = QtGui.QAction("New Library", self)
         file_action1.setShortcut("Ctrl+N")
         file_action1.setStatusTip("Creates a new library")

         file_action2 = QtGui.QAction("Exit this!", self)
         file_action2.setShortcut("Ctrl+Q")
         file_action2.setStatusTip("Closes The App")
         file_action2.triggered.connect(self.close_application)

         #File Menu
         main_menu = self.menuBar()
         file_menu = main_menu.addMenu("File")
         file_menu.addAction(file_action1)
         file_menu.addAction(file_action2)
         self.newLib()

         self.newLib()

     def newLib(self):
         centralwidget = QtGui.QWidget(self)
         self.mainLayout = QtGui.QVBoxLayout(centralwidget)
         self.mainLayout.setAlignment(QtCore.Qt.AlignCenter)

         #some useful buttons in the future

         self.setCentralWidget(centralwidget)
         self.show()

     def close_application(self):
         choice = QtGui.QMessageBox.question(self, 'Exit',
                                        "Close the application?",
                                        QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
         if choice == QtGui.QMessageBox.Yes:
             sys.exit()
         else:
             pass
def runNewLib():
    app = QtGui.QApplication(sys.argv)
    gui = NewLibrary()
    sys.exit(app.exec_())
runNewLib()

我搜索了很多关于这个但我无法理解与我的情况有些接近的几个,所以我寻求帮助,看起来很简单但我不明白:/,应该怎么做我要通过单击 new_lib_btn 打开第二个窗口吗?请帮忙.

I searched a lot about this but I couldn't understand the few ones that were somewhat close to my situation, so I'm asking for help, It seems so simple but I'm not getting it :/, what should I do to open the second window by clicking new_lib_btn? pls help.

我认为您发布的代码存在几个问题.首先,在 NewLibrary 构造函数中有两次对 self.newLib() 的调用.其次,你可能想把对 runNewLib() 的调用放在 newlib.py 底部的 if __name__... 块后面,像这样:

I think there are several issues with the code that you've posted. First, there are two calls to self.newLib() in the NewLibrary constructor. Second, you probably want to put that call to runNewLib() at the bottom of newlib.py behind an if __name__... block, like so:

if __name__ == '__main__':
    runNewLib()

否则,每次尝试导入 newlib.py 时,它都会尝试将 NewLibrary 作为单独的应用程序运行.

Otherwise, every time you try to import newlib.py, it will attempt to run NewLibrary as a separate application.

谈到您提出的问题,我认为您实际上不想在 Window.home() 中调用 self.show()NewLibrary.newLib().更典型的模式是创建 WindowNewLibrary 的实例,然后在该实例上调用 show().因此,在您的 Window 类中,您将添加一个函数来创建 NewLibrary 的实例,然后在其上调用 show,就像这样

Getting to the question you asked, I don't think you actually want to call self.show() in either Window.home() or NewLibrary.newLib(). A more typical pattern would be to create an instance of either Window or NewLibrary and then call show() on that instance. So, in your Window class, you'd add a function to create an instance of NewLibrary and then call show on it, like this

def create_new_library_window(self):
    self.new_lib = newlib.NewLibrary()
    self.new_lib.show()

请注意,正如 ekhumoro 指出的那样,您必须保留对 new_lib 的引用,否则在函数退出时它将被垃圾收集.然后在创建 new_lib_btn 后,在 NewLibrary.home() 中将它连接到这个新函数:

Note that, as ekhumoro points out, you have to keep a reference to new_lib around, otherwise it will get garbage collected when the function exits. Then in NewLibrary.home() after you've created the new_lib_btn connect it to this new function:

new_lib_btn.clicked.connect(self.create_new_library_window)

工作示例

此示例创建一个带有一个大按钮的主窗口,单击该按钮将打开第二个窗口.它使用从 QMainWindow 继承的两个类,如您的问题.首先,在main.py:

This example creates a main window with one big button that, when clicked will open a second window. It uses two classes that inherit from QMainWindow, as in your question. First, in main.py:

from PyQt4 import QtGui
from new_window import NewWindow


class Window(QtGui.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        self._new_window = None
        self._button = QtGui.QPushButton('New Window', self)
        self._button.clicked.connect(self.create_new_window)
        self.setCentralWidget(self._button)

    def create_new_window(self):
        self._new_window = NewWindow()
        self._new_window.show()

if __name__ == '__main__':
    app = QtGui.QApplication([])
    gui = Window()
    gui.show()
    app.exec_()

__init__ 函数创建一个按钮并将其连接到 create_new_window 函数.当按钮被点击时,create_new_window 将被调用.在create_new_window 内部,我们创建了一个NewWindow 的实例并将其分配给一个类成员以维护对窗口的引用并防止它被垃圾回收.然后我们在这个新窗口上调用 show 来显示它.

The __init__ function creates a button and connects it to the create_new_window function. When the button is clicked, create_new_window will be called. Inside of create_new_window, we create an instance of NewWindow and assign it to a class member to maintain a reference to the window and prevent it from being garbage collected. We then call show on this new window to display it.

在底部,我们使用通常的 if __name__ == '__main__': 模式来控制此文件是否运行应用程序.如果从命令行执行此文件(如 python main.py),__name__ == '__main__' 计算结果为 true,GUI 应用程序将启动.这样做的好处是允许文件有双重用途:它可以作为标准 python 包导入,也可以作为应用程序执行,所有这些都使用相同的文件.

At the bottom, we use the usual if __name__ == '__main__': pattern to control whether this file runs the application or not. If this file is executed from the command line (like python main.py) __name__ == '__main__' evaluates to true and the GUI application will be started. This has the advantage of allowing the file to serve a dual purpose: it can be imported as a standard python package, or executed as an application, all using the same file.

然后在new_window.py:

from PyQt4 import QtGui


class NewWindow(QtGui.QMainWindow):
    def __init__(self):
        super(NewWindow, self).__init__()
        self._new_window = None
        self._label = QtGui.QLabel('Hello, is it me you\'re looking for?')
        self.setCentralWidget(self._label)


if __name__ == '__main__':
    app = QtGui.QApplication([])
    gui = NewWindow()
    gui.show()
    app.exec_()

这个文件定义了第二个 QMainWindow,它使用一个标签作为它的中心部件.它还使用 __name__ == '__main__' 模式;这个文件也可以作为一个独立的应用程序执行,或者像上面的 main.py 一样导入.

This file defines a second QMainWindow that uses a label as its central widget. It also uses the __name__ == '__main__' pattern; this file can also be executed as a standalone application or imported as in main.py above.