Python 根据当前选择的小部件更新变量
Python Updating Variables Based on Current Widget Selected
有几个例子可以说明如何做到这一点,但在尝试了所有这些之后,我不明白如何正确地实施它。我有一个程序,一个按钮创建一个内部包含内容的小部件并将其分配给网格布局,它还在 canvas 上创建一个图形。再次单击该按钮会创建另一个填充相同内容的小部件和另一个图形,并将其分配给布局。
其中一个内容是一个旋转框,它控制图形的旋转。我希望每个旋转框都能够单独控制用它创建的图形。这就是我被困的地方。
我如何拥有一个可以创建多个小部件的通用按钮,然后在每个旋转框的每个值发生变化时,都能够分辨出它来自哪个小部件,以便旋转正确的图形?我想要小部件 ID 或名称,或者我可以访问它。到目前为止,这是我所拥有的 - 提前致谢!:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
import math
from scipy.optimize import fsolve
from mplwindow5 import Ui_mplMainWindow
from cU_widget import cU_Widget
class Viewer(QMainWindow, Ui_mplMainWindow):
def __init__(self, parent = None):
super(Viewer, self).__init__(parent)
self.setupUi(self)
self.count = 0
self.cU_widget = []
self.cU_rotate = []
self.lbl_cU_rotate = []
self.lbl_cU = []
self.btn_cU.clicked.connect(self.add_cU)
def add_cU(self):
self.cU_widget.append(int(self.count))
self.cU_widget[self.count] = QWidget(self.scrollAreaWidgetContents)
self.cU_widget[self.count].setMinimumSize(QSize(101, 81))
self.cU_widget[self.count].setMaximumSize(QSize(101, 81))
self.cU_widget[self.count].setObjectName("cU_widget" + str(self.count+1))
self.lbl_cU.append(int(self.count))
self.lbl_cU[self.count] = QLabel("cU " + str(self.count+1), self.cU_widget[self.count])
self.lbl_cU[self.count].setGeometry(QRect(0, 0, 101, 27))
self.lbl_cU[self.count].setObjectName("lbl_cU_" + str(self.count+1))
self.lbl_cU_rotate.append(int(self.count))
self.lbl_cU_rotate[self.count] = QLabel("R", self.cU_widget[self.count])
self.lbl_cU_rotate[self.count].setGeometry(QRect(6, 50, 20, 20))
self.lbl_cU_rotate[self.count].setObjectName("lbl_cU_rotate" + str(self.count+1))
self.cU_rotate.append(int(self.count))
self.cU_rotate[self.count] = QDoubleSpinBox(self.cU_widget[self.count])
self.cU_rotate[self.count].setGeometry(QRect(20, 40, 71, 27))
self.cU_rotate[self.count].setObjectName("cU_rotate" + str(self.count+1))
self.cU_rotate[self.count].valueChanged.connect(self.cU) # ??? What to use here
self.gridLayout.addWidget(self.cU_widget[self.count], self.count, 0)
self.cU()
def cU(self):
self.cU_rotate[self.count] = self.cU_rotate[self.count].value() # ?? What to use here
rotate = 1
tt = np.arange(0,1, 0.001)
lco_x0 = 0
lco_x1 = 4
lco_y0 = 1
lco_y1 = 3
cU_L_x0 = (lco_x0 * math.cos(math.radians(self.cU_rotate[self.count] + rotate))) - (lco_y0 * math.sin(math.radians(self.cU_rotate[self.count] + rotate)))
cU_L_x1 = (lco_x1 * math.cos(math.radians(self.cU_rotate[self.count] + rotate))) - (lco_y1 * math.sin(math.radians(self.cU_rotate[self.count] + rotate)))
#...
cU_L_y0 = (lco_x0 * math.sin(math.radians(self.cU_rotate[self.count] + rotate))) + (lco_y0 * math.cos(math.radians(self.cU_rotate[self.count] + rotate)))
cU_L_y1 = (lco_x1 * math.sin(math.radians(self.cU_rotate[self.count] + rotate))) + (lco_y1 * math.cos(math.radians(self.cU_rotate[self.count] + rotate)))
#...
cU_L_ax = ( 1 * cU_L_x0)
cU_L_bx = ((-6 * cU_L_x0) +(30 * cU_L_x1))
# ...
cU_L_ay = ( 1 * cU_L_y0)
cU_L_by = ((-6 * cU_L_y0) +(30 * cU_L_y1))
#...
cU_L_xtt = (cU_L_ax * tt**2) + (cU_L_bx * tt) + 1
cU_L_ytt = (cU_L_ay * tt**2) + (cU_L_by * tt) + 1
self.mplContainer.canvas.ax.plot(cU_L_xtt, cU_L_ytt, 'r')
self.mplContainer.canvas.ax.set_ylim([-5, 5])
self.mplContainer.canvas.ax.set_xlim([0, 10])
self.mplContainer.canvas.ax.set_aspect(1)
self.mplContainer.canvas.draw()
self.count += 1
app = QApplication(sys.argv)
viewer = Viewer()
viewer.show()
sys.exit(app.exec_())
这里是 mplwindow5:
from PyQt4 import QtCore, QtGui
class Ui_mplMainWindow(object):
def setupUi(self, mplMainWindow):
mplMainWindow.setObjectName("mplMainWindow")
mplMainWindow.resize(1171, 826)
self.centralwidget = QtGui.QWidget(mplMainWindow)
self.centralwidget.setObjectName("centralwidget")
self.mplContainer = MplWidget(self.centralwidget)
self.mplContainer.setGeometry(QtCore.QRect(259, 20, 861, 741))
self.mplContainer.setObjectName("mplContainer")
self.inputContainer = QtGui.QWidget(self.centralwidget)
self.inputContainer.setGeometry(QtCore.QRect(10, 20, 251, 741))
self.inputContainer.setObjectName("inputContainer")
self.scrollArea = QtGui.QScrollArea(self.inputContainer)
self.scrollArea.setGeometry(QtCore.QRect(0, 160, 241, 581))
self.scrollArea.setFrameShape(QtGui.QFrame.WinPanel)
self.scrollArea.setLineWidth(1)
self.scrollArea.setMidLineWidth(10)
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtGui.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 226, 577))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.scrollLayout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents)
self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName("formLayout")
self.gridLayout.setColumnStretch(0, 0)
self.gridLayout.setColumnStretch(2, 4)
self.scrollLayout.addLayout(self.gridLayout)
self.scrollLayout.addStretch()
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
mplMainWindow.setCentralWidget(self.centralwidget)
self.btn_cU = QtGui.QPushButton("cU", self.inputContainer)
self.btn_cU.setGeometry(QtCore.QRect(0, 0, 31, 27))
self.btn_cU.setObjectName("btn_cU")
QtCore.QMetaObject.connectSlotsByName(mplMainWindow)
from mplwidget import MplWidget
mpl 小部件:
from PyQt4.QtGui import *
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplCanvas(FigureCanvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Preferred)
FigureCanvas.updateGeometry(self)
class MplWidget(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.main_widget = QWidget(self)
self.canvas = MplCanvas()
self.ntb = NavigationToolbar(self.canvas, self.main_widget)
self.vbl = QGridLayout()
self.vbl.addWidget(self.canvas)
self.vbl.addWidget(self.ntb)
self.setLayout(self.vbl)
由于没有必要进行大量的数学运算来解决这个问题,所以我忽略了那部分。因此,假设我们想要使用 SpinBoxes 更改多条线的斜率。
一个选项是使线条成为 class 的一部分,该 class 控制 SpinBoxes 以及 matplotlib 线条。我在下面的代码中称它为 LineWidget
。按下按钮时,将创建一个新的 LineWidget
实例并将其添加到滚动区域,您可以在其中操作参数。一旦参数更改,该行就会更新。
这是一个完整的示例,我还简化了其余代码。
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
from PyQt4 import QtGui , QtCore
class Viewer(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Viewer, self).__init__(parent)
self.setupUI()
self.ax = self.fig.add_subplot(111)
self.count = 0
self.container = []
self.button.clicked.connect(self.addLine)
def setupUI(self):
self.centralwidget = QtGui.QWidget(self)
self.setCentralWidget(self.centralwidget)
self.centralwidget.setLayout(QtGui.QHBoxLayout())
self.leftWidget = QtGui.QWidget(self)
self.leftWidget.setMinimumWidth(200)
self.leftWidget.setLayout(QtGui.QVBoxLayout())
self.mplWidget = QtGui.QWidget(self)
self.mplWidget.setLayout(QtGui.QVBoxLayout())
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.ntb = NavigationToolbar(self.canvas, self.mplWidget)
self.mplWidget.layout().addWidget(self.canvas)
self.mplWidget.layout().addWidget(self.ntb)
self.button = QtGui.QPushButton("Push")
self.scrollWidget = QtGui.QWidget()
self.scrollLayout = QtGui.QVBoxLayout()
self.scrollWidget.setLayout(self.scrollLayout)
self.scrollLayout.addStretch()
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
self.leftWidget.layout().addWidget(self.button)
self.leftWidget.layout().addWidget(self.scrollArea)
self.centralwidget.layout().addWidget(self.leftWidget)
self.centralwidget.layout().addWidget(self.mplWidget)
def addLine(self):
b = LineWidget(self.count, self.ax)
self.container.append(b)
self.scrollLayout.insertWidget(self.scrollLayout.count() - 1, b)
self.count += 1
class LineWidget(QtGui.QWidget):
def __init__( self, number, ax, R=0, parent=None, **kwargs):
super(LineWidget, self).__init__(parent)
self.number = number
label = QtGui.QLabel("cU " + str(self.number))
self.spin = QtGui.QDoubleSpinBox()
self.spin.setSingleStep(0.2)
self.spin.setRange(-100,100)
self.setLayout(QtGui.QHBoxLayout())
self.layout().addWidget(label)
self.layout().addWidget(self.spin)
self.R = R
self.t = np.linspace(0,1)
self.f = lambda t, R: R*t
self.ax = ax
self.line, = self.ax.plot([],[], **kwargs)
self.update()
self.spin.valueChanged.connect(self.changed)
def changed(self):
self.R = self.spin.value()
self.update()
def update(self):
self.line.set_data(self.t, self.f(self.t, self.R))
self.ax.relim()
self.ax.autoscale_view()
self.ax.figure.canvas.draw_idle()
app = QtGui.QApplication(sys.argv)
viewer = Viewer()
viewer.show()
sys.exit(app.exec_())
有几个例子可以说明如何做到这一点,但在尝试了所有这些之后,我不明白如何正确地实施它。我有一个程序,一个按钮创建一个内部包含内容的小部件并将其分配给网格布局,它还在 canvas 上创建一个图形。再次单击该按钮会创建另一个填充相同内容的小部件和另一个图形,并将其分配给布局。
其中一个内容是一个旋转框,它控制图形的旋转。我希望每个旋转框都能够单独控制用它创建的图形。这就是我被困的地方。
我如何拥有一个可以创建多个小部件的通用按钮,然后在每个旋转框的每个值发生变化时,都能够分辨出它来自哪个小部件,以便旋转正确的图形?我想要小部件 ID 或名称,或者我可以访问它。到目前为止,这是我所拥有的 - 提前致谢!:
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
import math
from scipy.optimize import fsolve
from mplwindow5 import Ui_mplMainWindow
from cU_widget import cU_Widget
class Viewer(QMainWindow, Ui_mplMainWindow):
def __init__(self, parent = None):
super(Viewer, self).__init__(parent)
self.setupUi(self)
self.count = 0
self.cU_widget = []
self.cU_rotate = []
self.lbl_cU_rotate = []
self.lbl_cU = []
self.btn_cU.clicked.connect(self.add_cU)
def add_cU(self):
self.cU_widget.append(int(self.count))
self.cU_widget[self.count] = QWidget(self.scrollAreaWidgetContents)
self.cU_widget[self.count].setMinimumSize(QSize(101, 81))
self.cU_widget[self.count].setMaximumSize(QSize(101, 81))
self.cU_widget[self.count].setObjectName("cU_widget" + str(self.count+1))
self.lbl_cU.append(int(self.count))
self.lbl_cU[self.count] = QLabel("cU " + str(self.count+1), self.cU_widget[self.count])
self.lbl_cU[self.count].setGeometry(QRect(0, 0, 101, 27))
self.lbl_cU[self.count].setObjectName("lbl_cU_" + str(self.count+1))
self.lbl_cU_rotate.append(int(self.count))
self.lbl_cU_rotate[self.count] = QLabel("R", self.cU_widget[self.count])
self.lbl_cU_rotate[self.count].setGeometry(QRect(6, 50, 20, 20))
self.lbl_cU_rotate[self.count].setObjectName("lbl_cU_rotate" + str(self.count+1))
self.cU_rotate.append(int(self.count))
self.cU_rotate[self.count] = QDoubleSpinBox(self.cU_widget[self.count])
self.cU_rotate[self.count].setGeometry(QRect(20, 40, 71, 27))
self.cU_rotate[self.count].setObjectName("cU_rotate" + str(self.count+1))
self.cU_rotate[self.count].valueChanged.connect(self.cU) # ??? What to use here
self.gridLayout.addWidget(self.cU_widget[self.count], self.count, 0)
self.cU()
def cU(self):
self.cU_rotate[self.count] = self.cU_rotate[self.count].value() # ?? What to use here
rotate = 1
tt = np.arange(0,1, 0.001)
lco_x0 = 0
lco_x1 = 4
lco_y0 = 1
lco_y1 = 3
cU_L_x0 = (lco_x0 * math.cos(math.radians(self.cU_rotate[self.count] + rotate))) - (lco_y0 * math.sin(math.radians(self.cU_rotate[self.count] + rotate)))
cU_L_x1 = (lco_x1 * math.cos(math.radians(self.cU_rotate[self.count] + rotate))) - (lco_y1 * math.sin(math.radians(self.cU_rotate[self.count] + rotate)))
#...
cU_L_y0 = (lco_x0 * math.sin(math.radians(self.cU_rotate[self.count] + rotate))) + (lco_y0 * math.cos(math.radians(self.cU_rotate[self.count] + rotate)))
cU_L_y1 = (lco_x1 * math.sin(math.radians(self.cU_rotate[self.count] + rotate))) + (lco_y1 * math.cos(math.radians(self.cU_rotate[self.count] + rotate)))
#...
cU_L_ax = ( 1 * cU_L_x0)
cU_L_bx = ((-6 * cU_L_x0) +(30 * cU_L_x1))
# ...
cU_L_ay = ( 1 * cU_L_y0)
cU_L_by = ((-6 * cU_L_y0) +(30 * cU_L_y1))
#...
cU_L_xtt = (cU_L_ax * tt**2) + (cU_L_bx * tt) + 1
cU_L_ytt = (cU_L_ay * tt**2) + (cU_L_by * tt) + 1
self.mplContainer.canvas.ax.plot(cU_L_xtt, cU_L_ytt, 'r')
self.mplContainer.canvas.ax.set_ylim([-5, 5])
self.mplContainer.canvas.ax.set_xlim([0, 10])
self.mplContainer.canvas.ax.set_aspect(1)
self.mplContainer.canvas.draw()
self.count += 1
app = QApplication(sys.argv)
viewer = Viewer()
viewer.show()
sys.exit(app.exec_())
这里是 mplwindow5:
from PyQt4 import QtCore, QtGui
class Ui_mplMainWindow(object):
def setupUi(self, mplMainWindow):
mplMainWindow.setObjectName("mplMainWindow")
mplMainWindow.resize(1171, 826)
self.centralwidget = QtGui.QWidget(mplMainWindow)
self.centralwidget.setObjectName("centralwidget")
self.mplContainer = MplWidget(self.centralwidget)
self.mplContainer.setGeometry(QtCore.QRect(259, 20, 861, 741))
self.mplContainer.setObjectName("mplContainer")
self.inputContainer = QtGui.QWidget(self.centralwidget)
self.inputContainer.setGeometry(QtCore.QRect(10, 20, 251, 741))
self.inputContainer.setObjectName("inputContainer")
self.scrollArea = QtGui.QScrollArea(self.inputContainer)
self.scrollArea.setGeometry(QtCore.QRect(0, 160, 241, 581))
self.scrollArea.setFrameShape(QtGui.QFrame.WinPanel)
self.scrollArea.setLineWidth(1)
self.scrollArea.setMidLineWidth(10)
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtGui.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 226, 577))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.scrollLayout = QtGui.QVBoxLayout(self.scrollAreaWidgetContents)
self.gridLayout = QtGui.QGridLayout()
self.gridLayout.setObjectName("formLayout")
self.gridLayout.setColumnStretch(0, 0)
self.gridLayout.setColumnStretch(2, 4)
self.scrollLayout.addLayout(self.gridLayout)
self.scrollLayout.addStretch()
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
mplMainWindow.setCentralWidget(self.centralwidget)
self.btn_cU = QtGui.QPushButton("cU", self.inputContainer)
self.btn_cU.setGeometry(QtCore.QRect(0, 0, 31, 27))
self.btn_cU.setObjectName("btn_cU")
QtCore.QMetaObject.connectSlotsByName(mplMainWindow)
from mplwidget import MplWidget
mpl 小部件:
from PyQt4.QtGui import *
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
class MplCanvas(FigureCanvas):
def __init__(self):
self.fig = Figure()
self.ax = self.fig.add_subplot(111)
FigureCanvas.__init__(self, self.fig)
FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, QSizePolicy.Preferred)
FigureCanvas.updateGeometry(self)
class MplWidget(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.main_widget = QWidget(self)
self.canvas = MplCanvas()
self.ntb = NavigationToolbar(self.canvas, self.main_widget)
self.vbl = QGridLayout()
self.vbl.addWidget(self.canvas)
self.vbl.addWidget(self.ntb)
self.setLayout(self.vbl)
由于没有必要进行大量的数学运算来解决这个问题,所以我忽略了那部分。因此,假设我们想要使用 SpinBoxes 更改多条线的斜率。
一个选项是使线条成为 class 的一部分,该 class 控制 SpinBoxes 以及 matplotlib 线条。我在下面的代码中称它为 LineWidget
。按下按钮时,将创建一个新的 LineWidget
实例并将其添加到滚动区域,您可以在其中操作参数。一旦参数更改,该行就会更新。
这是一个完整的示例,我还简化了其余代码。
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QT as NavigationToolbar
from matplotlib.figure import Figure
import numpy as np
from PyQt4 import QtGui , QtCore
class Viewer(QtGui.QMainWindow):
def __init__(self, parent = None):
super(Viewer, self).__init__(parent)
self.setupUI()
self.ax = self.fig.add_subplot(111)
self.count = 0
self.container = []
self.button.clicked.connect(self.addLine)
def setupUI(self):
self.centralwidget = QtGui.QWidget(self)
self.setCentralWidget(self.centralwidget)
self.centralwidget.setLayout(QtGui.QHBoxLayout())
self.leftWidget = QtGui.QWidget(self)
self.leftWidget.setMinimumWidth(200)
self.leftWidget.setLayout(QtGui.QVBoxLayout())
self.mplWidget = QtGui.QWidget(self)
self.mplWidget.setLayout(QtGui.QVBoxLayout())
self.fig = Figure()
self.canvas = FigureCanvas(self.fig)
self.ntb = NavigationToolbar(self.canvas, self.mplWidget)
self.mplWidget.layout().addWidget(self.canvas)
self.mplWidget.layout().addWidget(self.ntb)
self.button = QtGui.QPushButton("Push")
self.scrollWidget = QtGui.QWidget()
self.scrollLayout = QtGui.QVBoxLayout()
self.scrollWidget.setLayout(self.scrollLayout)
self.scrollLayout.addStretch()
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setWidget(self.scrollWidget)
self.leftWidget.layout().addWidget(self.button)
self.leftWidget.layout().addWidget(self.scrollArea)
self.centralwidget.layout().addWidget(self.leftWidget)
self.centralwidget.layout().addWidget(self.mplWidget)
def addLine(self):
b = LineWidget(self.count, self.ax)
self.container.append(b)
self.scrollLayout.insertWidget(self.scrollLayout.count() - 1, b)
self.count += 1
class LineWidget(QtGui.QWidget):
def __init__( self, number, ax, R=0, parent=None, **kwargs):
super(LineWidget, self).__init__(parent)
self.number = number
label = QtGui.QLabel("cU " + str(self.number))
self.spin = QtGui.QDoubleSpinBox()
self.spin.setSingleStep(0.2)
self.spin.setRange(-100,100)
self.setLayout(QtGui.QHBoxLayout())
self.layout().addWidget(label)
self.layout().addWidget(self.spin)
self.R = R
self.t = np.linspace(0,1)
self.f = lambda t, R: R*t
self.ax = ax
self.line, = self.ax.plot([],[], **kwargs)
self.update()
self.spin.valueChanged.connect(self.changed)
def changed(self):
self.R = self.spin.value()
self.update()
def update(self):
self.line.set_data(self.t, self.f(self.t, self.R))
self.ax.relim()
self.ax.autoscale_view()
self.ax.figure.canvas.draw_idle()
app = QtGui.QApplication(sys.argv)
viewer = Viewer()
viewer.show()
sys.exit(app.exec_())