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
- 使用 QDialogButtonBox 简化对话框按钮方案
- 分别为我的确定和取消按钮包含接受和拒绝的信号。我还为 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")
我希望我能得到一些帮助来解决我一整天都被困的问题。我查看了以前的问题,但似乎没有什么与我面临的问题完全匹配。也许一双新鲜的眼睛可以引导我朝着正确的方向前进。我会在问题的末尾包含我的代码。
背景:
我正在开发一个简单的应用程序,它由主要 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
- 使用 QDialogButtonBox 简化对话框按钮方案
- 分别为我的确定和取消按钮包含接受和拒绝的信号。我还为 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")