使用Qt设计器表单和PyQt5在QWidget中绘制matplotlib图形



我不知道将matplotlib图形链接到从Qt Designer创建的表单的最佳方法。我在QtDesigner中创建了一个表单,然后通过pyuic5编译为python。我的主要程序是:

import app_framework as af
import matplotlib
from PyQt5 import QtWidgets
import sys
matplotlib.use('Qt5Agg')
app = QtWidgets.QApplication(sys.argv)
form = af.MyApp()
form.show()
app.exec_()

其中myApp调用从Qt Designer创建的app_framework.py表单,然后由pyuic5(design.py)转换:

from PyQt5.QtWidgets import QApplication, QMainWindow
import design
class MyApp(QMainWindow, design.Ui_mainWindow):
def __init(self):
super(self.__class__, self).__init__()
<button initializations>
<function definitions for button callbacks>

我很困惑,在这个框架中,我可以在哪里将matplotlib图形链接到QtDesigner中的预制空窗口小部件,或者类似的东西,这样我就可以在GUI窗口中绘制新数据(输入文本、按下按钮等)

我在SO和matplotlib的网站上找到了一些线程,但我不确定我是否理解在Qt Designer表单中为这个小部件创建空间,然后链接一个绘图,和/或创建一个小部件,然后链接和绘图的正确过程。

到目前为止,我所做的是在QtCreator中创建一个空的QWidget,然后在pyuic5编译后,我将design.py文件更改如下:

from PyQt5 import QtCore, QtGui, QtWidgets
# **** ADDED THIS
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
# **** 
class Ui_mainWindow(object):
def setupUi(self, mainWindow):
<mainWindow setup stuff>
self.centralwidget = QtWidgets.QWidget(mainWindow)
# ****ALTERED THIS FROM self.plotWidget = QtWidgets.QWidget(self.centralWidget)
self.plotWidget = MplWidget(self.centralWidget)
# ***** 
self.plotWidget.setGeometry(QtCore.QRect(20, 250, 821, 591))
self.plotWidget.setObjectName("plotWidget")
# **** ADDED THIS 
class MplCanvas(Canvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
Canvas.__init__(self, self.fig)
Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
Canvas.updateGeometry(self)

class MplWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.canvas = MplCanvas()
# ***********

然后app_framework.py为:

from PyQt5.QtWidgets import QApplication, QMainWindow
import design
class MyApp(QMainWindow, design.Ui_mainWindow):
def __init(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.pushButton_plotData.clicked.connect(self.plot_data)
def plot_data(self):
x=range(0, 10)
y=range(0, 20, 2)
self.plotWidget.canvas.ax.plot(x, y)
self.plotWidget.canvas.draw()

我以为这会起作用,但当我点击绘图按钮时,什么也没发生。它没有锁住,只是没有任何阴谋。我想我错过了在这个空的小部件中绘制matplotlib图形和/或画布的一些基本功能。

我通过这篇SO文章的帮助找到了解决方案,该文章链接到我可能需要购买的一本书的免费样本章节。正如许多其他帖子中提到的那样,需要使用标题MplWidget将空白的QtWidget"升级"为MplWidget。完成此操作,然后运行pyuic5命令,"from mplwidget import mplwidget"将出现在design.py文件中,该文件可以随时更新,而无需担心覆盖。然后,使用创建一个mplwidget.py文件

# Imports
from PyQt5 import QtWidgets
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as Canvas
import matplotlib
# Ensure using PyQt5 backend
matplotlib.use('QT5Agg')
# Matplotlib canvas class to create figure
class MplCanvas(Canvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
Canvas.__init__(self, self.fig)
Canvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
Canvas.updateGeometry(self)
# Matplotlib widget
class MplWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)   # Inherit from QWidget
self.canvas = MplCanvas()                  # Create canvas object
self.vbl = QtWidgets.QVBoxLayout()         # Set box for plotting
self.vbl.addWidget(self.canvas)
self.setLayout(self.vbl)

然后,应用程序框架可以和我之前的一样。当运行并按下绘图按钮时,图形将按预期显示。我想我基本上已经做了所有手工"推广"QWidget的事情,只是缺少vbl的东西,但每次编辑Qt Designer表单时,所有这些都会被覆盖。

app_framework.py:

from PyQt5.QtWidgets import QApplication, QMainWindow
import design
class MyApp(QMainWindow, design.Ui_mainWindow):
def __init(self):
super(self.__class__, self).__init__()
self.setupUi(self)
self.pushButton_plotData.clicked.connect(self.plot_data)
def plot_data(self):
x=range(0, 10)
y=range(0, 20, 2)
self.plotWidget.canvas.ax.plot(x, y)
self.plotWidget.canvas.draw()

main.py:

from PyQt5 import QtWidgets
import sys
# Local Module Imports
import app_framework as af
# Create GUI application
app = QtWidgets.QApplication(sys.argv)
form = af.MyApp()
form.show()
app.exec_()

最新更新