<p>我在你的代码中发现了问题。让我们看看您的代码的作用:</p>
<ol>
<li><p>将第一个绘图添加到小部件(无论是<code>A1</code>还是<code>A2</code>)时,您将获得<code>PlotDataItem</code>并将其存储在<code>curve1</code>或<code>curve2</code>中。假设首先选中<code>A1</code>,然后<code>todo</code>函数首先检查复选框1是否选中,因此绘制数据并将其存储在<code>curve1</code>中,然后相同的函数检查复选框2。复选框2未选中,因此函数执行<code>else</code>语句,该语句将从绘图小部件中删除<code>curve2</code>,此变量不存在,因此可能会引发错误,但是,使用<code>try</code>语句时,错误永远不会出现</p>
</li>
<li><p>现在,选中<code>A2</code>框,函数首先检查复选框1,它被选中,因此函数将再次添加相同的绘图,但作为另一个<code>PlotDataItem</code>,并将其存储在<code>curve1</code>。到目前为止,您有两个相同数据的<code>PlotDataItem</code>(这意味着两个绘图),但只有最后一个存储在<code>curve1</code>中。该函数的下一步操作是检查复选框2,选中复选框后,它将绘制第二个数据并将其<code>PlotDataItem</code>保存在<code>curve2</code></p>
</li>
<li><p>因此,当您现在取消选中复选框1时,您的函数首先检查复选框1(抱歉,如果它是重复的),它被取消选中,因此函数将删除存储在<code>curve1</code>中的<code>PlotDataItem</code>并执行此操作,但请记住,您有两个相同数据的绘图,因此对于我们(观众)来说,绘图不会消失。这就是问题所在,但它并没有到此结束,函数现在检查复选框2,它被选中,因此函数将添加第二个数据的另一个<code>PlotDataItem</code>,并将其存储在<code>curve2</code>。我们将再次遇到与第一个数据相同的问题</p>
</li>
</ol>
<p>通过这个分析,我还学到了一些东西,<code>PlotDataItem</code>不会在“覆盖”存储它的变量时消失,从<code>PlotWidget</code>中删除时也不会消失。考虑到这一点,我对上一个答案的代码做了一些更改,因为每次我们选中之前选中的复选框和未选中的复选框时,旧代码将创建另一项。现在,如果创建了该项,我的函数将再次添加它,而不是创建另一个</p>
<p>我有一些建议:</p>
<ul>
<li><p>尝试使用对象,生成自己的小部件类。您可以避免调用全局变量,将它们作为类的属性传递。(就像我先前的回答)</p>
</li>
<li><p>如果您想保持代码的原样(不使用类),为了使其正常工作,您可以添加另外两个带有复选框“状态”的变量,因此当您首先调用函数时,它会检查状态是否没有更改,并忽略该复选框。另外,请检查<code>PlotDataItem</code>是否在之前生成,并且只需再次添加它以避免生成更多项</p>
</li>
<li><p>您的目标是对一组框或按钮执行此操作,尝试对所有框或按钮仅使用一个变量:例如,一个包含所有框/按钮(对象)的列表。然后,您可以通过索引管理它们中的任何一个。此外,还可以在该变量上执行循环,以将内部对象连接到同一函数</p>
<pre><code>my_buttons = [ QtGui.QPushButton() for _ in range(number_of_buttons) ]
my_boxes= [ QtGui.QCheckBox() for _ in range(number_of_boxes) ]
my_boxes[0].setText('Box 1 Here')
my_boxes[2].setChecked(True)
for i in range(number_of_boxes):
my_boxes[i].stateChanged.connect(some_function)
</code></pre>
</li>
<li><p>执行对象列表还有助于您轻松自动命名:</p>
<pre><code>my_boxes= [ QtGui.QCheckBox(f"Box number {i+1}") for i in range(number_of_boxes) ]
my_boxes= [ QtGui.QCheckBox(str(i+1)) for i in range(number_of_boxes) ]
my_boxes= [ QtGui.QCheckBox('Box {:d}'.format(i+1)) for i in range(number_of_boxes) ]
</code></pre>
</li>
</ul>
<p>最后,这里是您的代码,其中有一些小的更改以使其正常工作:</p>
<pre><code>from PyQt5 import QtWidgets, uic, QtGui
import matplotlib.pyplot as plt
from matplotlib.widgets import SpanSelector
import numpy as np
import sys
import string
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
app = QtWidgets.QApplication(sys.argv)
x = np.linspace(0, 3.14, 100)
y1 = np.sin(x)#Data number 1 associated to checkbox A1
y2 = np.cos(x)#Data number 2 associated to checkbox A2
#This function is called whenever the state of checkboxes changes
def todo():
global b1st, b2st, curve1, curve2
if cbx1.isChecked() != b1st:
b1st = cbx1.isChecked()
if cbx1.isChecked():
if curve1 is None:
curve1 = plot.plot(x, y1, pen = 'r')
else:
plot.addItem(curve1)
else:
plot.removeItem(curve1)
if cbx2.isChecked() != b2st:
b2st = cbx2.isChecked()
if cbx2.isChecked():
if curve2 is None:
curve2 = plot.plot(x, y2, pen = 'y')
else:
plot.addItem(curve2)
else:
plot.removeItem(curve2)
#A widget to hold all of my future widgets
widget_holder = QtGui.QWidget()
#Checkboxes named A1 and A2
cbx1 = QtWidgets.QCheckBox()
cbx1.setText('A1')
cbx1.stateChanged.connect(todo)
b1st = False
curve1 = None
cbx2 = QtWidgets.QCheckBox()
cbx2.setText('A2')
cbx2.stateChanged.connect(todo)
b2st = False
curve2 = None
#Making a pyqtgraph plot widget
plot = pg.PlotWidget()
#Setting the layout
layout = QtGui.QGridLayout()
widget_holder.setLayout(layout)
#Adding the widgets to the layout
layout.addWidget(cbx1, 0,0)
layout.addWidget(cbx2, 0, 1)
layout.addWidget(plot, 1,0, 3,1)
widget_holder.adjustSize()
widget_holder.show()
sys.exit(app.exec_())
</code></pre>