FigureCanvas 在接收到 Popup 信号时无法出现

FigureCanvas Fail To Appear When Receiving Signal From Popup

我希望我能得到一些帮助来解决我一整天都被困的问题。我查看了以前的问题,但似乎没有什么与我面临的问题完全匹配。也许一双新鲜的眼睛可以引导我朝着正确的方向前进。我会在问题的末尾包含我的代码。

背景:

我正在开发一个简单的应用程序,它由主要 window 和弹出窗口 window 组成。主 window 仅包含一个按钮,按下时会打开弹出窗口 window。弹出窗口 window 包含两个复选框选项、一个确定按钮和一个取消按钮。按下时,弹出的确定按钮 returns 向主按钮 window 发出信号。此信号包含 1 和 0 的列表,具体取决于复选框的状态。该列表的目的是让主 window 中的函数可以确定要绘制的 canvases(绘图 1、绘图 2 或两者)。

请注意,主要 window 是使用网格布局组织的,每个 canvas 都应显示在第 3 列的一行中,并在第 4 列中有相应的标签。创建两个 canvases 时的预期结果如图所示:

问题:

一切正常,直到信号 returns 到达主 window 中 popup_input() 的插槽时结束。没有错误发生,但 canvases 根本没有出现。从 popup_input() 中获取用于创建图形的代码并将其放入 open_options() 中似乎确实有效并给出了如上所示的图形。但是,我的目标是让绘图在用户做出选择后出现。有谁知道为什么 canvases 没有出现?

import sys
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow, QLabel, QPushButton
from PyQt5.QtGui import QFont

import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.ticker import FormatStrFormatter

class Options(QMainWindow):
    popup_response = QtCore.pyqtSignal(object)
    def __init__(self):
        super().__init__()
        self._title = 'Plotting Options'
        self.setWindowTitle(self._title)

        self.selected_plots = [1, 1] # Always have both options selected by default

        self.option1 = QtWidgets.QCheckBox('Option 1')
        self.option1.setChecked(True)
        self.option2 = QtWidgets.QCheckBox('Option 2')
        self.option2.setChecked(True)

        self.checkbox_layout = QtWidgets.QHBoxLayout()
        self.checkbox_layout.addWidget(self.option1)
        self.checkbox_layout.addWidget(self.option2)

        self.ok_button = QtWidgets.QPushButton('OK', self)
        self.ok_button.clicked.connect(lambda: self.clicked_ok())
        self.cancel_button = QtWidgets.QPushButton('Cancel', self)
        self.cancel_button.clicked.connect(lambda: self.clicked_cancel())
        self.button_layout = QtWidgets.QHBoxLayout()
        self.button_layout.addWidget(self.ok_button)
        self.button_layout.addWidget(self.cancel_button)

        self._popup = QtWidgets.QWidget()
        self.setCentralWidget(self._popup)
        self.layout = QtWidgets.QGridLayout(self._popup)
        self.layout.addLayout(self.checkbox_layout, 0, 0)
        self.layout.addLayout(self.button_layout, 1, 0)


    def finalize_selected_plots(self):
        if self.option1.isChecked() == False:
            self.selected_plots[0] = 0
        if self.option2.isChecked() == False:
            self.selected_plots[1] = 0
        return self.selected_plots

    def clicked_ok(self):
        self.plots = self.finalize_selected_plots()

        # Send selection back to Results Window
        main_window = MainWindow()
        static_reply = self.plots
        self.popup_response.connect(main_window.popup_input)
        self.popup_response.emit(static_reply)
        self.plots = [1,1]
        self.close()

    def clicked_cancel(self):
        self.close()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.exPopup = Options()
        self.data_to_plot = [[1, 5, 10], [2, 4, 6], [6, 4, 2]] # Dummy values

        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main)

        self.button_options = QtWidgets.QPushButton('Plot Options', self)
        self.button_options.clicked.connect(self.open_options)

        self.option_layout = QtWidgets.QHBoxLayout()
        self.option_layout.addWidget(self.button_options)

        self.layout = QtWidgets.QGridLayout(self._main)
        self.layout.addLayout(self.option_layout, 0, 2)

    def open_options(self):
        self.exPopup.show()


    @QtCore.pyqtSlot(object)
    def popup_input(self, reply):
        plot_title_font_size = 15
        data = self.data_to_plot

        if reply[0] != 0:
            self.figure_xy1 = FigureCanvas(Figure(figsize=(5, 5)))
            self._figure1 = self.figure_xy1.figure.subplots()
            self._figure1.grid()

            self.layout.addWidget(self.figure_xy1, 1, 3)
            self.figure_label1 = QLabel('Test Plot 1', self)
            self.figure_label1.setFont(QFont('Times', plot_title_font_size))
            self.figure_label1.setAlignment(QtCore.Qt.AlignLeft)
            self.layout.addWidget(self.figure_label1, 1, 4)

            x = data[0]
            y = data[1]
            self._figure1.plot(x, y, '-')
            self._figure1.set_xlabel('x')
            self._figure1.set_ylabel('y1')
            self._figure1.figure.canvas.draw()

        if reply[1] != 0:
            self.figure_xy2 = FigureCanvas(Figure(figsize=(5, 5)))
            self._figure2 = self.figure_xy2.figure.subplots()
            self._figure2.grid()

            self.layout.addWidget(self.figure_xy2, 2, 3)
            self.figure_label2 = QLabel('Test Plot 2', self)
            self.figure_label2.setFont(QFont('Times', plot_title_font_size))
            self.figure_label2.setAlignment(QtCore.Qt.AlignLeft)
            self.layout.addWidget(self.figure_label2, 2, 4)

            x = data[0]
            y = data[2]
            self._figure2.plot(x, y, '-')
            self._figure2.set_xlabel('x')
            self._figure2.set_ylabel('y2')
            self._figure2.figure.canvas.draw()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = QtWidgets.QStackedWidget()
    main_window = MainWindow()
    widget.addWidget(main_window)
    widget.setWindowTitle("Main Window")
    widget.show()

    try:
        sys.exit(app.exec_())
    except:
        print("Exiting")

我找到了解决问题的办法。在 jmacey 的帮助下,在 Reddit 的 pyqt 页面上,我发现了以下内容:

  • 我的弹出窗口应该继承 QDialog vs QMainWindow
  • 使用 QDialogBu​​ttonBox 简化对话框按钮方案
  • 分别为我的确定和取消按钮包含接受和拒绝的信号。我还为 clicked_ok 添加了一个额外的信号,它将在对话框关闭时执行我想要的功能。
  • 弹出对话框应该从我的主 window 执行。如果我在对话框中单击“确定”,那么它将 运行 我与绘图相关的代码。

这是我的更新 类:

class Options(QDialog):
    popup_response = QtCore.pyqtSignal(object)
    def __init__(self, parent=None):
        super().__init__(parent)
        self._title = 'Plotting Options'
        self.setWindowTitle(self._title)
        self.setGeometry(100, 100, 300, 200)

        self.selected_plots = [1, 1] # Always have both options selected by default

        self.option1 = QtWidgets.QCheckBox('Option 1')
        self.option1.setChecked(True)
        self.option2 = QtWidgets.QCheckBox('Option 2')
        self.option2.setChecked(True)

        self.checkbox_layout = QtWidgets.QHBoxLayout()
        self.checkbox_layout.addWidget(self.option1)
        self.checkbox_layout.addWidget(self.option2)


        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self.clicked_ok)
        self.button_box.rejected.connect(self.reject)


        self.popup_layout = QtWidgets.QVBoxLayout()
        self.popup_layout.addLayout(self.checkbox_layout)
        self.popup_layout.addWidget(self.button_box)
        self.setLayout(self.popup_layout)

    def finalize_selected_plots(self):
        if self.option1.isChecked() == False:
            self.selected_plots[0] = 0
        if self.option2.isChecked() == False:
            self.selected_plots[1] = 0
        return self.selected_plots

    def clicked_ok(self):
        print("clicked ok")
        self.plots = self.finalize_selected_plots()

        # Send selection back to Results Window
        # main_window = MainWindow()
        # static_reply = self.plots
        # self.popup_response.connect(main_window.popup_input)
        # self.popup_response.emit(static_reply)
        self.plots = [1,1]
        self.close()
        

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        #self.exPopup = Options()
        self.data_to_plot = [[1, 5, 10], [2, 4, 6], [6, 4, 2]] # Dummy values

        self._main = QtWidgets.QWidget()
        self.setCentralWidget(self._main)

        self.button_options = QtWidgets.QPushButton('Plot Options', self)
        #self.button_options.clicked.connect(self.open_options)
        self.button_options.clicked.connect(self.popup_input)

        self.option_layout = QtWidgets.QHBoxLayout()
        self.option_layout.addWidget(self.button_options)

        self.layout = QtWidgets.QGridLayout(self._main)
        self.layout.addLayout(self.option_layout, 0, 2)

    # def open_options(self):
    #   self.exPopup.show()


    #@QtCore.pyqtSlot(object)
    def popup_input(self):
        plot_title_font_size = 15
        data = self.data_to_plot

        self.grab_popup = Options(self)

        if self.grab_popup.exec():
            print("Pressed ok")
            if reply[0] != 0:
                self.figure_xy1 = FigureCanvas(Figure(figsize=(5, 5)))
                self._figure1 = self.figure_xy1.figure.subplots()
                self._figure1.grid()

                self.layout.addWidget(self.figure_xy1, 1, 3)
                self.figure_label1 = QLabel('Test Plot 1', self)
                self.figure_label1.setFont(QFont('Times', plot_title_font_size))
                self.figure_label1.setAlignment(QtCore.Qt.AlignLeft)
                self.layout.addWidget(self.figure_label1, 1, 4)

                x = data[0]
                y = data[1]
                self._figure1.plot(x, y, '-')
                self._figure1.set_xlabel('x')
                self._figure1.set_ylabel('y1')
                self._figure1.figure.canvas.draw()

            if reply[1] != 0:
                self.figure_xy2 = FigureCanvas(Figure(figsize=(5, 5)))
                self._figure2 = self.figure_xy2.figure.subplots()
                self._figure2.grid()

                self.layout.addWidget(self.figure_xy2, 2, 3)
                self.figure_label2 = QLabel('Test Plot 2', self)
                self.figure_label2.setFont(QFont('Times', plot_title_font_size))
                self.figure_label2.setAlignment(QtCore.Qt.AlignLeft)
                self.layout.addWidget(self.figure_label2, 2, 4)

                x = data[0]
                y = data[2]
                self._figure2.plot(x, y, '-')
                self._figure2.set_xlabel('x')
                self._figure2.set_ylabel('y2')
                self._figure2.figure.canvas.draw()

        else:
            print("Pressed Cancel")