Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
230 views
in Technique[技术] by (71.8m points)

python - How to open a window with a click of a button from another window using PyQt?

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

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

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

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

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

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)

Working example

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

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.

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.

Then in 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_()

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...