我正在pyqt5应用程序上工作,并且有一个小部件,其中包含用matplotlib制作的图形。我想添加一个允许用户单击图形的功能,它将以全屏方式打开。我怎样才能做到这一点?小部件中的图形的构建方式如下:
class CanvasUp(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=50):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
self.plot()
def plot(self):
# obtaining data
...
ax = self.figure.add_subplot(111)
self.figure.text(0.5, 0.5, "TEST", transform=ax.transAxes,
fontsize=40, color='gray', alpha=0.5,
ha='center', va='center')
ax.fill_between(x1, y1=y1, label='psavert', alpha=0.5, color='tab:green', linewidth=2)
dt = ax.plot(x1, y1)
ax.set_title(lab, loc='left')
ax.grid()
self.draw_idle()
如果我简化程序,它看起来像这样:
from PyQt5.QtWidgets import QDialog, QVBoxLayout
from PyQt5.QtWidgets import QApplication
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import sys
class CanvasUp(FigureCanvas):
def __init__(self, parent=None, width=5, height=5, dpi=50):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
self.plot()
def plot(self):
try:
x1 = [1, 2, 3]
y1 = [3, 2, 1]
ax = self.figure.add_subplot(111)
ax.set_ylim([0, max(y1)*1.15])
self.figure.text(0.5, 0.5, "test", transform=ax.transAxes,
fontsize=40, color='gray', alpha=0.5,
ha='center', va='center')
ax.fill_between(x1, y1=y1, label='psavert', alpha=0.5, color='tab:green', linewidth=2)
dt = ax.plot(x1, y1)
ax.grid()
self.draw_idle()
except:
print("Bad graphs")
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setGeometry(50, 50, 700, 700)
layout = QVBoxLayout(self)
plot = CanvasUp()
layout.addWidget(plot)
self.show()
if __name__ == '__main__':
App = QApplication(sys.argv)
window = MainWindow()
sys.exit(App.exec())
如果要全屏显示child小部件,则需要将其父级设置为None
。
注意,如果要恢复先前的状态,还需要跟踪布局中的先前位置。在您的示例中并不是真正的要求,但是如果有更多小部件,则必须考虑这一点。
class CanvasUp(FigureCanvas):
toggle = pyqtSignal()
def __init__(self, parent=None, width=5, height=5, dpi=50):
self.fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
self.setParent(parent)
self.plot()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
# emit a signal to notify the parent that we want to toggle the mode
self.toggle.emit()
# ...
class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setGeometry(50, 50, 700, 700)
self.setWindowTitle('fig test')
layout = QVBoxLayout(self)
self.plot = CanvasUp()
layout.addWidget(self.plot)
self.show()
self.plot.toggle.connect(self.toggleFigure)
def toggleFigure(self):
if self.plot.parent():
# store the current index in the layout
self.layoutIndex = self.layout().indexOf(self.plot)
self.plot.setParent(None)
# manually reparenting a widget requires to explicitly show it,
# usually by calling show() or setVisible(True), but this is
# automatically done when calling showFullScreen()
self.plot.showFullScreen()
else:
self.layout().insertWidget(self.layoutIndex, self.plot)
但是,如果您使用的是网格布局,则索引是不够的,因为insertWidget
仅存在于QBoxLayouts中,所以必须提取网格坐标之前,以使小部件成为父项。请考虑一下,虽然您在将窗口小部件添加到布局中的同时将坐标存储在一个变量中,但始终最好只在需要时才获取它们。class MainWindow(QDialog):
def __init__(self):
super().__init__()
self.setGeometry(50, 50, 700, 700)
self.setWindowTitle('fig test')
layout = QGridLayout(self)
layout.addWidget(QPushButton(), 0, 0)
layout.addWidget(QPushButton(), 0, 1)
self.plot = CanvasUp()
layout.addWidget(self.plot, 1, 0, 1, 2)
self.show()
self.plot.toggle.connect(self.toggleFigure)
def toggleFigure(self):
if self.plot.parent():
layoutIndex = self.layout().indexOf(self.plot)
# store the position in grid coordinates:
# row, column, horizontal span and vertical span
self.layoutPosition = self.layout().getItemPosition(layoutIndex)
self.plot.setParent(None)
self.plot.showFullScreen()
else:
self.layout().addWidget(self.plot, *self.layoutPosition)