简体   繁体   中英

Get PyQt4 to open another Qt window when a button is pressed

I'm trying to get one Qt window to display a matplotlib figure in another Qt window when a button is pressed. I have one .py file that generates that UI with the button, and another .py file that when run, opens a QT window displaying a graph.

If I just run the second .py file, the QT window to display the graph opens up, no problem.

However, the problem is that when I run the second .py file through the first one, pythonw.exe crashes when I click the button to run the second .py file.

Here is the code (one .py file. It creates the UI for the user to click the button if they want to see a matplotlib graph):

import matplotlib
matplotlib.use('Qt4Agg')
import pylab
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

import matplotlibtest
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(690, 786)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.widget_2 = QtGui.QWidget(self.centralwidget)
        self.widget_2.setGeometry(QtCore.QRect(120, 20, 471, 51))
        self.widget_2.setObjectName(_fromUtf8("widget_2"))

        #...some other irrelevant code...

        self.plotButton = QtGui.QPushButton(self.layoutWidget_2)
        self.plotButton.setMinimumSize(QtCore.QSize(0, 23))
        self.plotButton.setObjectName(_fromUtf8("plotButton"))
        self.gridLayout_2.addWidget(self.plotButton, 9, 1, 1, 1)
        self.plotButton.clicked.connect(self.showimage)

    def showimage(self):
        matplotlibtest.main()

So when the user clicks plotButton , the main function of matplotlibtest.py is run.

And in matplotlibtest.py , I have this code (from http://packtlib.packtpub.com/library/9781847197900/ch06 ). This code when run opens a QT window which displays a simple matplotlib graph. There is no issue here-- when this code is run, it opens the graph just as I want it to.

# for command-line arguments
import sys
# Python Qt4 bindings for GUI objects
from PyQt4 import QtGui
# Numpy functions for image creation
import numpy as np
# Matplotlib Figure object
from matplotlib.figure import Figure
import matplotlib
matplotlib.use('Qt4Agg')
# import the Qt4Agg FigureCanvas object, that binds Figure to
# Qt4Agg backend. It also inherits from QWidget
from matplotlib.backends.backend_qt4agg \
import FigureCanvasQTAgg as FigureCanvas
# import the NavigationToolbar Qt4Agg widget
from matplotlib.backends.backend_qt4agg \
import NavigationToolbar2QTAgg as NavigationToolbar

class Qt4MplCanvas(FigureCanvas):

    def __init__(self, parent):
        # plot definition
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)
        t = np.arange(0.0, 3.0, 0.01)
        s = np.cos(2*np.pi*t)
        self.axes.plot(t, s)
        # initialization of the canvas
        FigureCanvas.__init__(self, self.fig)
        # set the parent widget
        self.setParent(parent)
        # we define the widget as expandable
        FigureCanvas.setSizePolicy(self,
        QtGui.QSizePolicy.Expanding,
        QtGui.QSizePolicy.Expanding)
        # notify the system of updated policy
        FigureCanvas.updateGeometry(self)

class ApplicationWindow(QtGui.QMainWindow):
    def __init__(self):
        # initialization of Qt MainWindow widget
        QtGui.QMainWindow.__init__(self)
        # set window title
        self.setWindowTitle("Matplotlib Figure in a Qt4 Window With NavigationToolbar")
        # instantiate a widget, it will be the main one
        self.main_widget = QtGui.QWidget(self)
        # create a vertical box layout widget
        vbl = QtGui.QVBoxLayout(self.main_widget)
        # instantiate our Matplotlib canvas widget
        qmc = Qt4MplCanvas(self.main_widget)
        # instantiate the navigation toolbar
        ntb = NavigationToolbar(qmc, self.main_widget)
        # pack these widget into the vertical box
        vbl.addWidget(qmc)
        vbl.addWidget(ntb)
        # set the focus on the main widget
        self.main_widget.setFocus()
        # set the central widget of MainWindow to main_widget
        self.setCentralWidget(self.main_widget)

def main():
    # create the GUI application
    qApp = QtGui.QApplication(sys.argv)
    # instantiate the ApplicationWindow widget
    aw = ApplicationWindow()
    # show the widget
    aw.show()
    sys.exit(qApp.exec_())

if __name__ == '__main__':
    main()    

How do I get the matplotlib graph displayed when the button is clicked?

Why does pythonw.exe crash?

EDIT:

If I wanted to pass arguments (x = [1,2,3], y=[1,1,1]) to make the graph, would I put class Qt4MplCanvas(FigureCanvas): def __init__(self,parent,x,y) , and when I construct it would I write qmc = Qt4MplCanvas(self.main_widget, [1,2,3], [1,1,1]) ?

In __init__ for any Qt object, do we run the super's __init__ to initialize the Qt object's parent? Why are the arguments to super(MyMainWindow,self) ?

Why do we use 'object' in class Ui_MainWIndow(object): but we use 'QtGui.QMainWindow' in class MyMainWindow(QtGui.QMainWindow) ?

Are 'object' and 'QtGui.QMainWindow' arguments?

When we construct a Ui_MainWindow, why do we write self.ui = Ui_MainWindow() and not self.ui = Ui_MainWindow(object) ?

Ok, you have several problems in your code:

  1. You have an Ui definition object but you are not using it.
  2. You can't user matplotlib.use two times in a run (one in your main .py and one in matplotlibtest)
  3. If you want a PyQt application to run you must create a QApplication object
  4. Other minor errors involving the layouts

For the solutions check the code, this are some modifications I did to your code for get it to work:

In your .py main file :

from PyQt4 import QtCore,QtGui

try:
    _fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
    def _fromUtf8(s):
        return s

try:
    _encoding = QtGui.QApplication.UnicodeUTF8
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
    def _translate(context, text, disambig):
        return QtGui.QApplication.translate(context, text, disambig)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("MainWindow"))
        MainWindow.resize(690, 786)
        self.centralwidget = QtGui.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
        self.gridLayout_2 = QtGui.QGridLayout(self.centralwidget) #here
        self.centralwidget.setLayout(self.gridLayout_2) #here

        #...some other irrelevant code...

        self.plotButton = QtGui.QPushButton() #here
        self.plotButton.setMinimumSize(QtCore.QSize(0, 23))
        self.plotButton.setObjectName(_fromUtf8("plotButton"))
        self.gridLayout_2.addWidget(self.plotButton, 9, 1, 1, 1)
        self.plotButton.clicked.connect(self.showimage)

    def showimage(self):
        #changes here
        from matplotlibtest import ApplicationWindow
        self.aw = ApplicationWindow()
        self.aw.show()

#class that actually shows something
class MyMainWindow(QtGui.QMainWindow):

    def __init__(self,parent=None):
        super(MyMainWindow,self).__init__()
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

#put the main window here
def main():
    import sys
    qApp = QtGui.QApplication(sys.argv)
    aw = MyMainWindow()
    aw.show()
    sys.exit(qApp.exec_())

if __name__ == '__main__':
    main()  

And in matplotlibtest.py :

# Python Qt4 bindings for GUI objects
from PyQt4 import QtGui
# Numpy functions for image creation
import numpy as np
# Matplotlib Figure object
from matplotlib.figure import Figure
import matplotlib
matplotlib.use('Qt4Agg')
# import the Qt4Agg FigureCanvas object, that binds Figure to
# Qt4Agg backend. It also inherits from QWidget
from matplotlib.backends.backend_qt4agg \
import FigureCanvasQTAgg as FigureCanvas
# import the NavigationToolbar Qt4Agg widget
from matplotlib.backends.backend_qt4agg \
import NavigationToolbar2QTAgg as NavigationToolbar

class Qt4MplCanvas(FigureCanvas):

    def __init__(self, parent):
        # plot definition
        self.fig = Figure()
        self.axes = self.fig.add_subplot(111)
        t = np.arange(0.0, 3.0, 0.01)
        s = np.cos(2*np.pi*t)
        self.axes.plot(t, s)
        # initialization of the canvas
        FigureCanvas.__init__(self, self.fig)
        # set the parent widget
        self.setParent(parent)
        # we define the widget as expandable
        FigureCanvas.setSizePolicy(self,
        QtGui.QSizePolicy.Expanding,
        QtGui.QSizePolicy.Expanding)
        # notify the system of updated policy
        FigureCanvas.updateGeometry(self)

class ApplicationWindow(QtGui.QMainWindow):
    def __init__(self):
        # initialization of Qt MainWindow widget
        QtGui.QMainWindow.__init__(self)
        # set window title
        self.setWindowTitle("Matplotlib Figure in a Qt4 Window With NavigationToolbar")
        # instantiate a widget, it will be the main one
        self.main_widget = QtGui.QWidget(self)
        # create a vertical box layout widget
        vbl = QtGui.QVBoxLayout(self.main_widget)
        # instantiate our Matplotlib canvas widget
        qmc = Qt4MplCanvas(self.main_widget)
        # instantiate the navigation toolbar
        ntb = NavigationToolbar(qmc, self.main_widget)
        # pack these widget into the vertical box
        vbl.addWidget(qmc)
        vbl.addWidget(ntb)
        # set the focus on the main widget
        self.main_widget.setFocus()
        # set the central widget of MainWindow to main_widget
        self.setCentralWidget(self.main_widget)

#deleted the main function here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM