使用PyQt5嵌入matplotlib,實現根據界面輸入數值更換顯示的matplotlib圖形


實現本次博文的功能花了有點時間呀。。。。。。。。。。。。。。。

使用的編程語言是python3.4, 界面設計軟件是erics 6結合PyQt5  


1、使用QT Designer實現UI 界面

在eric 6 中,點擊項目,新建一個項目,增加如下圖的一些控件與布局,不相同都可以。

除了 QVBoxLayout 垂直布局、QPushButton按鈕、和comboBox輸入widget控件需要注意外,其他的控件都沒有使用(即沒有使用信號與槽函數),后期可以自行實現其他功能。分別對應上圖中的最小的紅框、顯示圖片按鈕、顯示1的可選控件。

 

這是自動生成的代碼:

# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'E:\PyQt\paper_test\test_1.ui' # # Created: Fri Dec 21 20:18:35 2018 # by: PyQt5 UI code generator 5.4 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(753, 578) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap(":/pic/cnc.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) MainWindow.setWindowIcon(icon) self.centralWidget = QtWidgets.QWidget(MainWindow) self.centralWidget.setObjectName("centralWidget") self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralWidget) self.horizontalLayout.setObjectName("horizontalLayout") self.verticalLayout = QtWidgets.QVBoxLayout() self.verticalLayout.setObjectName("verticalLayout") self.tabWidget = QtWidgets.QTabWidget(self.centralWidget) self.tabWidget.setAcceptDrops(False) self.tabWidget.setLayoutDirection(QtCore.Qt.LeftToRight) self.tabWidget.setAutoFillBackground(True) self.tabWidget.setTabShape(QtWidgets.QTabWidget.Rounded) self.tabWidget.setUsesScrollButtons(False) self.tabWidget.setDocumentMode(True) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") self.pushButton = QtWidgets.QPushButton(self.tab) self.pushButton.setGeometry(QtCore.QRect(80, 440, 75, 23)) self.pushButton.setObjectName("pushButton") self.pushButton_3 = QtWidgets.QPushButton(self.tab) self.pushButton_3.setGeometry(QtCore.QRect(250, 440, 75, 23)) self.pushButton_3.setObjectName("pushButton_3") self.verticalLayoutWidget_2 = QtWidgets.QWidget(self.tab) self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(10, 20, 521, 371)) self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2") self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") self.comboBox = QtWidgets.QComboBox(self.tab) self.comboBox.setGeometry(QtCore.QRect(360, 440, 69, 22)) self.comboBox.setObjectName("comboBox") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.comboBox.addItem("") self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("tab_2") self.pushButton_2 = QtWidgets.QPushButton(self.tab_2) self.pushButton_2.setGeometry(QtCore.QRect(100, 370, 75, 23)) self.pushButton_2.setObjectName("pushButton_2") self.tabWidget.addTab(self.tab_2, "") self.tab_3 = QtWidgets.QWidget() self.tab_3.setObjectName("tab_3") self.tabWidget.addTab(self.tab_3, "") self.tab_4 = QtWidgets.QWidget() self.tab_4.setObjectName("tab_4") self.tabWidget.addTab(self.tab_4, "") self.tab_5 = QtWidgets.QWidget() self.tab_5.setObjectName("tab_5") self.tabWidget.addTab(self.tab_5, "") self.verticalLayout.addWidget(self.tabWidget) self.horizontalLayout.addLayout(self.verticalLayout) MainWindow.setCentralWidget(self.centralWidget) self.menuBar = QtWidgets.QMenuBar(MainWindow) self.menuBar.setGeometry(QtCore.QRect(0, 0, 753, 23)) self.menuBar.setObjectName("menuBar") self.menu = QtWidgets.QMenu(self.menuBar) self.menu.setObjectName("menu") self.menu_2 = QtWidgets.QMenu(self.menuBar) self.menu_2.setObjectName("menu_2") self.menu_3 = QtWidgets.QMenu(self.menuBar) self.menu_3.setObjectName("menu_3") MainWindow.setMenuBar(self.menuBar) self.actionAciton = QtWidgets.QAction(MainWindow) self.actionAciton.setObjectName("actionAciton") self.actionOpen = QtWidgets.QAction(MainWindow) self.actionOpen.setObjectName("actionOpen") self.actionOpen_2 = QtWidgets.QAction(MainWindow) self.actionOpen_2.setObjectName("actionOpen_2") self.actionAbout = QtWidgets.QAction(MainWindow) self.actionAbout.setObjectName("actionAbout") self.actionShezih = QtWidgets.QAction(MainWindow) self.actionShezih.setObjectName("actionShezih") self.actionBaochun = QtWidgets.QAction(MainWindow) self.actionBaochun.setObjectName("actionBaochun") self.actionXinjian = QtWidgets.QAction(MainWindow) self.actionXinjian.setObjectName("actionXinjian") self.actionLingchunwei = QtWidgets.QAction(MainWindow) self.actionLingchunwei.setObjectName("actionLingchunwei") self.actionAbou2 = QtWidgets.QAction(MainWindow) self.actionAbou2.setObjectName("actionAbou2") self.menu.addAction(self.actionOpen_2) self.menu.addAction(self.actionBaochun) self.menu.addAction(self.actionXinjian) self.menu.addAction(self.actionLingchunwei) self.menu_2.addAction(self.actionShezih) self.menu_3.addAction(self.actionAbout) self.menu_3.addAction(self.actionAbou2) self.menuBar.addAction(self.menu.menuAction()) self.menuBar.addAction(self.menu_2.menuAction()) self.menuBar.addAction(self.menu_3.menuAction()) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "顯示圖片")) self.pushButton_3.setText(_translate("MainWindow", "顯示2")) self.comboBox.setItemText(0, _translate("MainWindow", "1")) self.comboBox.setItemText(1, _translate("MainWindow", "2")) self.comboBox.setItemText(2, _translate("MainWindow", "3")) self.comboBox.setItemText(3, _translate("MainWindow", "4")) self.comboBox.setItemText(4, _translate("MainWindow", "5")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "文本1")) self.pushButton_2.setText(_translate("MainWindow", "顯示2")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "文本2")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "文本3")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), _translate("MainWindow", "文本4")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_5), _translate("MainWindow", "文本5")) self.menu.setTitle(_translate("MainWindow", "文件")) self.menu_2.setTitle(_translate("MainWindow", "設置")) self.menu_3.setTitle(_translate("MainWindow", "幫助")) self.actionAciton.setText(_translate("MainWindow", "about")) self.actionOpen.setText(_translate("MainWindow", "open")) self.actionOpen_2.setText(_translate("MainWindow", "打開")) self.actionAbout.setText(_translate("MainWindow", "關於")) self.actionShezih.setText(_translate("MainWindow", "設置1")) self.actionBaochun.setText(_translate("MainWindow", "保存")) self.actionXinjian.setText(_translate("MainWindow", "新建")) self.actionLingchunwei.setText(_translate("MainWindow", "另存為")) self.actionAbou2.setText(_translate("MainWindow", "聯系我們")) import my_pic_rc if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_()) 

import my_pic_rc 是我的資源文件,保存着圖片文件,eric 6能把其編譯成二進制文件

小伙伴們可以刪除它

 

2.實現界面與業務邏輯代碼分離

eric6 相對於 wxpython是能實現界面與業務邏輯代碼分離

右鍵點擊剛剛創建的.ui 文件,在彈出的選項框中 點擊 ‘ 生成對話框代碼’ 

‘新建’,輸入自定義的類名、文件名、路徑名

因為這次的小項目只是使用了 ‘顯示圖片’這個按鈕,對應名稱為 pushButton,勾選信號類型,點擊確定,自動生成代碼

# -*- coding: utf-8 -*- """ Module implementing CallTest. """ from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow from PyQt5 import QtCore, QtGui, QtWidgets import matplotlib matplotlib.use('Qt5Agg') from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from PyQt5 import QtCore, QtWidgets,QtGui import matplotlib.pyplot as plt from Ui_test_1 import Ui_MainWindow class CallTest(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(CallTest, self).__init__(parent) self.setupUi(self)  @pyqtSlot() def on_pushButton_clicked(self): """ Slot documentation goes here. """ # TODO: not implemented yet #self.plot_() print(self.comboBox.currentText())

需要顯示的話,加上下面的代碼

if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) demo = CallTest() demo.show() sys.exit(app.exec_())

3.增加顯示matplotlib圖形的代碼

# -*- coding: utf-8 -*- """ Module implementing CallTest. """ import sys import random import matplotlib from PyQt5.QtCore import pyqtSlot from PyQt5 import QtCore, QtGui, QtWidgets matplotlib.use('Qt5Agg') from PyQt5 import QtCore, QtWidgets,QtGui from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QSizePolicy, QWidget from numpy import arange, sin, pi from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar from matplotlib.figure import Figure import matplotlib.pyplot as plt import numpy as np from Ui_test_1 import Ui_MainWindow import sip #創建一個matplotlib圖形繪制類 class MyFigure(FigureCanvas): def __init__(self,width=5, height=4, dpi=100): #第一步:創建一個創建Figure self.fig = Figure(figsize=(width, height), dpi=dpi) #第二步:在父類中激活Figure窗口 super(MyFigure,self).__init__(self.fig) #此句必不可少,否則不能顯示圖形 #第三步:創建一個子圖,用於繪制圖形用,111表示子圖編號,如matlab的subplot(1,1,1) self.axes = self.fig.add_subplot(111) #第四步:就是畫圖,【可以在此類中畫,也可以在其它類中畫】,最好是在別的地方作圖 def plotsin(self): self.axes0 = self.fig.add_subplot(111) t = np.arange(0.0, 3.0, 0.01) s = np.sin(2 * np.pi * t) self.axes0.plot(t, s) def plotcos(self): t = np.arange(0.0, 3.0, 0.01) s = np.sin(2 * np.pi * t) self.axes.plot(t, s) class CallTest(QMainWindow, Ui_MainWindow): step = 0 """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(CallTest, self).__init__(parent) self.setupUi(self) def myfunction(self): self.F = MyFigure(width=3, height=2, dpi=100) t = np.arange(0.0, int(self.comboBox.currentText()), 0.01) s = np.cos(2 * np.pi * t) self.F.axes.plot(t, s) #使用控件,在widget上作圖 self.F.fig.suptitle("cos") if self.verticalLayout_2.count() < 2: self.verticalLayout_2.addWidget(self.F) self.mpl_ntb = NavigationToolbar(self.F, self) # 添加完整的 toolbar,增加圖片放大、移動的按鈕 self.verticalLayout_2.addWidget(self.mpl_ntb) #此處的代碼可以進行顯示,如何將圖片進行變換 def plotcos(self): self.step += 1 if self.step == 1: self.myfunction() else: sip.delete(self.F) sip.delete(self.mpl_ntb) self.myfunction() print(str(self.step))  @pyqtSlot() def on_pushButton_clicked(self): """ Slot documentation goes here. """ # TODO: not implemented yet # self.mpl.start_static_plot() print('this is button 1') self.plotcos() if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) demo = CallTest() demo.show() sys.exit(app.exec_())

創建一個class MyFigure(FigureCanvas): 類,繼承於  FigureCanvas

接下來主要講下 myfunction 函數和 plotcos 函數

1. myfunction 函數

self.F = MyFigure(width=3, height=2, dpi=100)

 可以理解self.F是一個widget 控件了

t = np.arange(0.0, int(self.comboBox.currentText()), 0.01)

獲取comboBox控件的當前選擇的值,由於是字符型,需要強制轉換成int 型。用於變換cos函數的間距。

        if self.verticalLayout_2.count() < 2: 
            self.verticalLayout_2.addWidget(self.F) 
            self.mpl_ntb = NavigationToolbar(self.F, self)  # 添加完整的 toolbar,增加圖片放大、移動的按鈕
            self.verticalLayout_2.addWidget(self.mpl_ntb)

當垂直布局中的widget 少於 2個時,將F和 操作圖形的控件mpl_ntb 增加到垂直布局中,使用函數addWidget()

最主要是使layout中不一直 增加控件,如果沒有if的話,將一直垂直增加控件。

 2.plotcos 函數

        self.step += 1
        if self.step == 1:
            self.myfunction()
        else:
            sip.delete(self.F)
            sip.delete(self.mpl_ntb) 
            self.myfunction()           
            
        print(str(self.step))

初始化的step為0, step用來判斷是否是用戶第一次顯示圖形,如果是第一次則創建圖形,將其增加到垂直布局中;

如果是要刷新圖片,則要先將原始垂直布局layout中的widget 刪除。

題外話:本來看到api文檔有removeWidget函數的,試過用來刪除,但是沒用。。。。。。。。但我把一個按鈕QPushButton按鈕控件加入到垂直布局中,使用removeWidget函數能把按鈕控件刪除。。。。。。。。。不明覺厲。。。。。。。網上查了好久,才查到使用import sip 模塊。

使用

            sip.delete(self.F)
            sip.delete(self.mpl_ntb) 

將原來的兩個控件進行刪除,然后調用myfunction 函數,再根據comboBox控件,更新顯示。

 

 

終於。。。。。。。大功告成。。。。。。。。。。。。

最后顯示結果:

 

讓我們共同學習,共同進步


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM