如何将 Matplotlib 图添加到我的 pyqt 布局

How to add Matplotlib graph to my pyqt layout

目前,我正在开发一个使用 PYQT 组合框选择应用程序的应用程序。组合框中的选择有:

  1. 文本框(只允许用户输入)
  2. 图片(让用户拖放图片查看图片)
  3. 音频(让用户拖放音频文件以查看频谱 从 matplotlib 绘制的图表)- 只能使用 wav 文件。

除了音频部分,一切正常。当我拖放我的 wav 文件时,会发生这种情况。

我明白为什么它被推低了。因为上面有布局。所以我的问题是如何将其放入“lastWidget”布局?这样它就可以以与我的文本框和图像相同的布局显示。我尝试将它添加到另一个变量并添加一个小部件,还尝试添加像素图。但是,我似乎无法让它工作。

import sys, os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import * 

#audio plot on pyqt
import numpy as np
import matplotlib.pyplot as plt
from scipy.io.wavfile import read
from matplotlib.backends.backend_qt5agg import *
from matplotlib.figure import Figure


class UI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Programme")
        self.setFixedSize(600, 600)

        central = QWidget()
        self.setCentralWidget(central)
        self.layout = QVBoxLayout(central)

        combo = QComboBox(self)
        combo.addItems(("textbox", "image", "audio"))
        combo.setFixedSize(200, 30)
        self.layout.addWidget(combo)

        self.lastWidget = QLineEdit(self)
        self.layout.addWidget(self.lastWidget)
        self.lastWidget.setFixedSize(500, 500)
        combo.activated[str].connect(self.onChanged)  

        self.show()

    def onChanged(self, text):

        if text == 'textbox':
            self.layout.removeWidget(self.lastWidget)
            self.lastWidget.deleteLater()

            self.lastWidget = QLineEdit()
            self.lastWidget.setFixedSize(500, 500)

        elif text == 'image':
            self.layout.removeWidget(self.lastWidget)
            self.lastWidget.deleteLater()
            #Doing drag and drop for image
            self.lastWidget = DragAndDropImage()
            self.layout.addWidget(self.lastWidget)

        elif text == 'audio':

            self.layout.removeWidget(self.lastWidget)
            self.lastWidget.deleteLater()
            #Doing drag and drop for Audio
            self.lastWidget = DragAndDropAudio()
            self.layout.addWidget(self.lastWidget)

        self.layout.addWidget(self.lastWidget)
        
        QApplication.processEvents()
        self.adjustSize()

class DragAndDropAudio(QLabel):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)
        self.setFixedSize(500, 500)
 
    
    def dragEnterEvent(self, event):
        event.accept()

    def dragMoveEvent(self, event):
        event.accept()

    def dropEvent(self, event):
        if event.mimeData().hasUrls:
            file_path = event.mimeData().urls()[0].toLocalFile()
            # print(file_path)
            self.set_audio(file_path)
            event.accept()
        else:
            event.ignore() 
    
    def set_audio(self, file_path):
        canvas = FigureCanvas(Figure(figsize=(5, 4)))
        ax = canvas.figure.subplots()
        # fig, self.ax = plt.subplots(figsize=(5, 4), dpi=120)
        t = np.arange(0.0, 2.0, 0.01)
        s = 1 + np.sin(2 * np.pi * t)
        # read audio samples
        input_data = read(file_path)
        audio = input_data[1]
        # plot the first 1024 samples
        ax.plot(audio[0:1024])
        # label the axes   
        ax.plot(t, s)
        ax.set(xlabel='time (s)', ylabel='Amlitude',
               title='Audio Spectrum')

        ex.layout.addWidget(canvas)
        

class DragAndDropImage(QLabel):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)
        self.setFixedSize(500, 500)
        self.setAlignment(Qt.AlignCenter)
        self.setText('\n\n Drop Image Here (InputImage) \n\n')
        self.setStyleSheet('''
            QLabel{
                border: 4px dashed #aaa
            }
        ''')

    def setPixmap(self, image):
        super().setPixmap(image)
    
    def dragEnterEvent(self, event):
        if event.mimeData().hasImage:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasImage:
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        if event.mimeData().hasImage:
            event.setDropAction(Qt.CopyAction)
            file_path = event.mimeData().urls()[0].toLocalFile()
            self.set_image(file_path)
            event.accept()
        else:
            event.ignore() 
    
    def set_image(self, file_path):
        ex.lastWidget.setPixmap(QPixmap(file_path))

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = UI()
    sys.exit(app.exec_())

不要添加和删除小部件,在这种情况下最好使用 QStackedWidget。

class UI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Programme")
        self.setFixedSize(600, 600)

        central = QWidget()
        self.setCentralWidget(central)

        self.combo = QComboBox()
        self.combo.setFixedSize(200, 30)

        self.textbox = QLineEdit()
        self.textbox.setFixedSize(500, 500)
        self.dnd_image = DragAndDropImage()
        self.dnd_audio = DragAndDropAudio()

        self.stacked_widget = QStackedWidget()
        self.stacked_widget.addWidget(self.textbox)
        self.stacked_widget.addWidget(self.dnd_image)
        self.stacked_widget.addWidget(self.dnd_audio)

        layout = QVBoxLayout(central)
        layout.addWidget(self.combo)
        layout.addWidget(self.stacked_widget)

        self.combo.addItem("textbox", self.textbox)
        self.combo.addItem("image", self.dnd_image)
        self.combo.addItem("audio", self.dnd_audio)

        self.combo.currentIndexChanged.connect(self.onChanged)
        self.show()

    def onChanged(self):
        widget = self.combo.currentData()
        if isinstance(widget, QWidget):
            self.stacked_widget.setCurrentWidget(widget)
        self.adjustSize()