PySide & QWT object disable/destroy
-
wrote on 21 Jan 2022, 10:37 last edited by
I am just learning OOP and PySide. I have created a code as below. The application doesn't do anything much (it's a development project in learning stages).
import numpy as np import sys from qtpy.QtWidgets import ( QWidget, QMainWindow, QVBoxLayout, QAction, QMenu, QLabel, QApplication, QMessageBox, QDesktopWidget, ) from qtpy.QtCore import Qt, Slot, QPoint, QObject from qwt import ( QwtPlot, QwtPlotMarker, QwtPlotGrid, QwtLegend, QwtPlotCurve, QwtLegendData, ) class contexMenuHelper(QObject): def __init__(self, plot, legend, legendItem): super(contexMenuHelper, self).__init__() self.plot = plot self.legend = legend self.legendItem = legendItem @Slot(QPoint) def contextMenuSlot(self, pos): context = QMenu(self.legendItem) context.addAction(QAction("Delete", self)) context.exec_(self.legendItem.mapToGlobal(pos)) class Plot(QwtPlot, QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setAxisTitle(QwtPlot.xBottom, "X-axis") self.setAxisTitle(QwtPlot.yLeft, "Y-axis") self.setCanvasBackground(Qt.white) self.setAxisScale(QwtPlot.yLeft, -2, 2) QwtPlotGrid.make(self, color=Qt.lightGray, width=0, style=Qt.DotLine) legend = QwtLegend() legend.setDefaultItemMode(QwtLegendData.Checkable) self.insertLegend(legend, QwtPlot.RightLegend) x = np.arange(-5.0, 5.0, 0.1) curves = [] curves.append( QwtPlotCurve.make( x, np.cos(x), "Cosinus", self, linecolor="red", antialiased=True ) ) curves.append( QwtPlotCurve.make( x, np.sin(x), "Sinus", self, linecolor="blue", antialiased=True ) ) self.helpers = dict() for a in curves: legend.legendWidget(a).setContextMenuPolicy(Qt.CustomContextMenu) h = contexMenuHelper(self, legend, legend.legendWidget(a)) self.helpers[a] = h legend.legendWidget(a).customContextMenuRequested.connect(h.contextMenuSlot) QwtPlotMarker.make( align=Qt.AlignRight | Qt.AlignTop, linestyle=QwtPlotMarker.HLine, color="black", plot=self, ) for keys, value in self.helpers.items(): print(keys) print(value) # insert a vertical marker at x = 0 QwtPlotMarker.make( align=Qt.AlignRight | Qt.AlignTop, linestyle=QwtPlotMarker.VLine, color="black", plot=self, ) legend.checked.connect(self.showCurve) self.replot() @Slot(object, bool, int) def showCurve(self, obj, condition, num): obj.setVisible(not condition) self.replot() @Slot(object, bool, int) def __del__(self, obj, condition): print('Destructor called, vehicle deleted.') class SimplePlot(QWidget): def __init__(self, parent=None): super().__init__(parent) layout = QVBoxLayout() self.setLayout(layout) plot = Plot() plot.setTitle("Trigonometric") self.setWindowTitle("Trigonometric") layout.addWidget(plot) label = QLabel("Press the legend to en/disable a curve") layout.addWidget(label) self.center() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def closeEvent(self, event): reply = QMessageBox.question( self, "Message", "Are you sure to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ) if reply == QMessageBox.Yes: event.accept() else: event.ignore() if __name__ == "__main__": app = QApplication(sys.argv) window = SimplePlot() window.show() window.resize(800, 600) sys.exit(app.exec_())
I made the active legend and the context menu.
I want to make it so that when I select "Delete" from the context menu, the corresponding function waveform in the graph and the corresponding object in the legend will be deleted. -
Hi and welcome to devnet,
One way is to keep a map of legend and curve and in the slot connected to your delete action you remove both from the plot.
-
wrote on 26 Jan 2022, 10:25 last edited by
Hello .
Thank you for saying hello. :)Using : QwtPlotCurve.detach(curves[1])
I am able to get what I need.
However, I really don't know how to hook this up to "Deleate" in the context menu.
Please help me with the code .
-
Did you build the map I suggested ?
-
wrote on 26 Jan 2022, 20:43 last edited by
Hi.
@SGaist
Unfortunately I don't understand what you are writing about, I am new to PySide :( . Please provide clear translations.I made it this way.
Please write if it is correct ?
And how else can it be done ?import numpy as np import sys from qtpy.QtWidgets import ( QWidget, QMainWindow, QVBoxLayout, QAction, QMenu, QLabel, QApplication, QMessageBox, QDesktopWidget, ) from qtpy.QtCore import Qt, Slot, QPoint, QObject from qwt import ( QwtPlot, QwtPlotMarker, QwtPlotGrid, QwtLegend, QwtPlotCurve, QwtLegendData, ) class contexMenuHelper(QObject): def __init__(self, plot, legend, legendItem): super(contexMenuHelper, self).__init__() self.plot = plot self.legend = legend self.legendItem = legendItem self.emlSel = QAction("Delete") @Slot(QPoint) def contextMenuSlot(self, pos): context = QMenu(self.legendItem) context.addAction(self.emlSel) context.exec_(self.legendItem.mapToGlobal(pos)) self.emlSel.triggered.connect(self.destroy()) @Slot() def destroy(self): QwtPlotCurve.detach(self.legend) class Plot(QwtPlot, QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): self.setAxisTitle(QwtPlot.xBottom, "X-axis") self.setAxisTitle(QwtPlot.yLeft, "Y-axis") self.setCanvasBackground(Qt.white) self.setAxisScale(QwtPlot.yLeft, -2, 2) QwtPlotGrid.make(self, color=Qt.lightGray, width=0, style=Qt.DotLine) legend = QwtLegend() legend.setDefaultItemMode(QwtLegendData.Checkable) legend.resize(100,100) self.insertLegend(legend, QwtPlot.RightLegend) x = np.arange(-5.0, 5.0, 0.1) curves = [] curves.append( QwtPlotCurve.make( x, np.cos(x), "Cosinus", self, linecolor="red", antialiased=True ) ) curves.append( QwtPlotCurve.make( x, np.sin(x), "Sinus", self, linecolor="blue", antialiased=True ) ) self.helpers = dict() for a in curves: legend.legendWidget(a).setContextMenuPolicy(Qt.CustomContextMenu) h = contexMenuHelper(self, a, legend.legendWidget(a)) self.helpers[a] = h legend.legendWidget(a).customContextMenuRequested.connect(h.contextMenuSlot) QwtPlotMarker.make( align=Qt.AlignRight | Qt.AlignTop, linestyle=QwtPlotMarker.HLine, color="black", plot=self, ) QwtPlotMarker.make( align=Qt.AlignRight | Qt.AlignTop, linestyle=QwtPlotMarker.VLine, color="black", plot=self, ) legend.checked.connect(self.showCurve) self.replot() @Slot(object, bool, int) def showCurve(self, obj, condition, num): obj.setVisible(not condition) self.replot() class SimplePlot(QWidget): def __init__(self, parent=None): super().__init__(parent) layout = QVBoxLayout() self.setLayout(layout) plot = Plot() plot.setTitle("Trigonometric") self.setWindowTitle("Trigonometric") layout.addWidget(plot) label = QLabel("Press the legend to en/disable a curve") layout.addWidget(label) self.center() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def closeEvent(self, event): reply = QMessageBox.question( self, "Message", "Are you sure to quit?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ) if reply == QMessageBox.Yes: event.accept() else: event.ignore() if __name__ == "__main__": app = QApplication(sys.argv) window = SimplePlot() window.show() window.resize(850, 600) sys.exit(app.exec_())
-
Sorry, I think I have misunderstood your answer. You have it working so I am unsure what you were asking.
-
wrote on 30 Jan 2022, 17:52 last edited by
It works like this. It's only working now. Compare the two codes for yourself. However, thank you very much for your support. Thanks to you, it dazzled my brain :)
Please also note the error I made :(
1/7