如何将Matplotlib绘制的音频频谱图添加到PyQt指定布局中
问题修复方案
错误原因
- 你在音频控件的
set_audio方法中直接将matplotlib画布添加到了主窗口的布局,而非当前音频控件的内部区域,导致画布被放在了原有展示区的下方,出现挤压问题 - 承载音频功能的
DragAndDropAudio类继承自QLabel,没有配置内部布局,无法直接容纳matplotlib画布控件
修复后的完整代码
import sys, os from PyQt5.QtWidgets import * from PyQt5.QtCore import * from PyQt5.QtGui import * #audio plot on pyqt import numpy as np from scipy.io.wavfile import read from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas 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) # 调整对齐避免控件错位 self.layout.setAlignment(Qt.AlignTop | Qt.AlignHCenter) combo = QComboBox(self) combo.addItems(("textbox", "image", "audio")) combo.setFixedSize(200, 30) self.layout.addWidget(combo) self.lastWidget = QLineEdit(self) self.lastWidget.setFixedSize(500, 500) self.layout.addWidget(self.lastWidget) combo.activated[str].connect(self.onChanged) self.show() def onChanged(self, text): # 先移除旧控件 self.layout.removeWidget(self.lastWidget) self.lastWidget.deleteLater() if text == 'textbox': self.lastWidget = QLineEdit() self.lastWidget.setFixedSize(500, 500) elif text == 'image': self.lastWidget = DragAndDropImage() elif text == 'audio': self.lastWidget = DragAndDropAudio() # 统一添加新控件 self.layout.addWidget(self.lastWidget) self.update() class DragAndDropAudio(QWidget): # 改继承QWidget方便添加内部布局 def __init__(self): super().__init__() self.setAcceptDrops(True) self.setFixedSize(500, 500) # 给音频控件加内部布局 self.layout = QVBoxLayout(self) self.layout.setContentsMargins(0,0,0,0) # 添加拖拽提示文本 self.tip_label = QLabel('\n\n Drop Wav Audio Here \n\n') self.tip_label.setAlignment(Qt.AlignCenter) self.tip_label.setStyleSheet(''' QLabel{ border: 4px dashed #aaa } ''') self.layout.addWidget(self.tip_label) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): file_path = event.mimeData().urls()[0].toLocalFile() if file_path.lower().endswith('.wav'): self.set_audio(file_path) event.accept() return event.ignore() def set_audio(self, file_path): # 先清空原有提示内容 for i in reversed(range(self.layout.count())): self.layout.itemAt(i).widget().deleteLater() # 生成matplotlib画布 canvas = FigureCanvas(Figure(figsize=(5, 5), dpi=100)) ax = canvas.figure.subplots() # 读取音频文件 input_data = read(file_path) audio = input_data[1] # 绘制音频波形 ax.plot(audio[0:1024]) ax.set(xlabel='Sample Point', ylabel='Amplitude', title='Audio Waveform') # 把画布添加到当前控件的内部布局,不会影响主布局结构 self.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.scaled(self.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation)) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): file_path = event.mimeData().urls()[0].toLocalFile() if file_path.lower().endswith(('.png','.jpg','.jpeg','.bmp')): event.accept() return event.ignore() def dragMoveEvent(self, event): if event.mimeData().hasUrls(): event.accept() else: event.ignore() def dropEvent(self, event): if event.mimeData().hasUrls(): 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): self.setPixmap(QPixmap(file_path)) if __name__ == '__main__': app = QApplication(sys.argv) ex = UI() sys.exit(app.exec_())
关键修改说明
- 将
DragAndDropAudio的父类从QLabel改为QWidget,新增内部布局承载matplotlib画布,画布只会在当前控件的500*500区域内展示,不会挤压其他控件 - 删除了原代码中
ex.layout.addWidget(canvas)的错误调用,改为将画布添加到音频控件自身的内部布局中 - 优化了音频、图片的拖拽校验逻辑,只接受对应格式的文件
- 简化了
onChanged方法逻辑,删除重复代码 - 优化了图片展示的缩放逻辑,避免图片超出控件范围
内容的提问来源于stack exchange,提问作者Redoxsphere
相关产品推荐
相关产品推荐

