Python Tkinter父类中判断当前子类并执行对应操作
I'm developing a Python Tkinter GUI program that includes a Widget parent class, along with temperatureWidget and lightWidget subclasses that inherit from it. The parent class has an Entry component and a button bound to the setSensors() function. I want to determine which subclass is currently being used within this function: if it's a temperatureWidget, read the Scale value from temperatureSlider and display it in the corresponding Label. Is this requirement feasible?
Here's my full code:
import random from tkinter import * import threading from queue import * import datetime import matplotlib as matplotlib root = Tk() root.configure(background="white") root.title("Project 2.1") class SerialThread(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue class GUI: def __init__(self, master): self.msb = random.randint(0, 1) self.widgets = [] self.master = master self.master.geometry("{0}x{1}+0+0".format(master.winfo_screenwidth(), master.winfo_screenheight())) self.widgetFrame = Frame(master, bg="white") self.widgetFrame.pack(side=TOP) self.widgetTop = Frame(self.widgetFrame, bg="white") self.widgetTop.pack(side=TOP, fill=X) self.removeText = Entry(self.widgetTop) self.removeText.pack() removeButton = Button(self.widgetTop, text="Remove widget ", command=self.removeWidget) removeButton.pack() addButton = Button(self.widgetTop, text="Add widget", command=self.addWidgetToScreen) addButton.pack() def showGui(self): if len(self.widgets): for widget in range(len(self.widgets)): self.widgets[widget].mainFrame.pack(side=LEFT, pady=20, padx=20, fill=Y) else: NoInputLabel = Label(self.widgetTop, text="No modules connected, please connect a module", font='Helvetica 16 bold', bg='white', anchor='center') NoInputLabel.pack(side=TOP, pady=50, padx=20) def addWidget(self, widget): self.widgets.append(widget) def removeWidget(self): for index, widget in enumerate(self.widgets): if widget.name == self.removeText.get(): self.widgets[index].mainFrame.pack_forget() del self.widgets[index] def addWidgetToScreen(self): num = random.randint(0, 1) if len(self.widgets): if num == 0: newWidget = temperatureWidget(self.master, "COM" + str(len(self.widgets) + 1), self) else: newWidget = lightWidget(self.master, "COM" + str(len(self.widgets) + 1), self) else: if num == 0: newWidget = temperatureWidget(self.master, "COM1", self) else: newWidget = lightWidget(self.master, "COM1", self) self.widgets.append(newWidget) self.widgets[-1].mainFrame.pack(side=LEFT, pady=20, padx=20, fill=Y) class Widget: def __init__(self, master, name, gui): self.msb = 0 self.master = master self.name = name self.gui = gui self.mainFrame = Frame(gui.widgetFrame, bg='white') self.mainFrameTop = Frame(self.mainFrame, bg='white') self.mainFrameTop.pack(side=TOP) self.mainFrameCenter = Frame(self.mainFrame, bg='white') self.mainFrameCenter.pack(side=TOP) self.mainFrameBottom = Frame(self.mainFrame, bg='white') self.mainFrameBottom.pack(side=TOP) colorArray = list(matplotlib.colors.cnames.values()) self.WidgetName = Label(self.mainFrameTop, text=name, font='Helvetica 16 bold', bg=random.choice(colorArray)) self.WidgetName.pack(fill=X) self.msb = random.randint(0, 1) self.maxRolloutPositionLabel = Label(self.mainFrameTop, text="Rolling distance (cm): ", bg="white") self.maxRolloutPositionLabel.pack() self.maxRolloutEntry = Entry(self.mainFrameTop, bg="white") self.maxRolloutEntry.pack() self.submitFormButton = Button(self.mainFrameTop, text="Submit", command=self.setSensors, bg="white") self.submitFormButton.pack() self.openSunblindButton = Button(self.mainFrameCenter, text="Open sunblind", command=self.openSunblind, state=NORMAL, bg="#28a745", fg="white") self.openSunblindButton.pack(side=LEFT) self.closeSunblindButton = Button(self.mainFrameCenter, text="Close sunblind", command=self.closeSunblind, state=NORMAL, bg="#dc3545", fg="white") self.closeSunblindButton.pack(side=LEFT) self.setSunblindStatusButton = Button(self.mainFrameCenter, text="Automatic", command=self.setSunblindStatus, bg="#6c757d", fg="white") self.setSunblindStatusButton.pack(side=LEFT) self.sunblindFrame = Frame(self.mainFrameBottom, bg="white") self.sunblindFrame.pack(fill=X) self.sunblindStatusLabel = Label(self.sunblindFrame, text="Sunblind status:", bg="white", anchor="w") self.sunblindStatusLabel.pack(side=LEFT, pady=5) self.sunblindStatus = Label(self.sunblindFrame, text="Manual", bg="white") self.sunblindStatus.pack(side=RIGHT, pady=5) self.rolloutFrame = Frame(self.mainFrameBottom, bg="white") self.rolloutFrame.pack(fill=X) self.rolloutLabel = Label(self.rolloutFrame, text="Roll-out position: ", justify=LEFT, bg="white", anchor="w") self.rolloutLabel.pack(side=LEFT, pady=5) self.rolloutValue = Label(self.rolloutFrame, text="", bg="white") self.rolloutValue.pack(side=RIGHT, pady=5) self.variable = StringVar(self.mainFrameBottom) self.variable.set(self.name) self.chooseArduino = OptionMenu(self.mainFrameBottom, self.variable, "Living Room", "Bedroom", "Study") self.chooseArduino.pack(side=LEFT) self.setNameButton = Button(self.mainFrameBottom, text="Set name", command=self.setArduinoName) self.setNameButton.pack(side=LEFT) def setSensors(self): print("Set the temperature and light of the sensors") # Check which subclass is used self.maxRolloutPositionLabel.config(text="Rolling distance (cm): " + str(self.maxRolloutEntry.get())) def setName(self, widgetName): self.name = widgetName def openSunblind(self): print("Set the sunblind to an open state") self.rolloutValue.config(text="Rolled out") def closeSunblind(self): print("Set the sunblind to an closed state") self.rolloutValue.config(text="Rolled in") def setSunblindStatus(self): if self.setSunblindStatusButton.config('text')[-1] == 'Automatic': self.openSunblindButton.config(state=DISABLED) self.closeSunblindButton.config(state=DISABLED) self.setSunblindStatusButton.config(text='Manual') print("Sunblind is set to: " + self.setSunblindStatusButton['text']) self.sunblindStatus.config(text="Automatic") self.rolloutValue.config(text='') else: self.openSunblindButton.config(state=NORMAL) self.closeSunblindButton.config(state=NORMAL) self.setSunblindStatusButton.config(text='Automatic') print("Sunblind is set to: " + self.setSunblindStatusButton['text']) self.sunblindStatus.config(text="Manual") def setArduinoName(self): self.WidgetName.config(text=self.variable.get()) def getTemperature(self): return self.temperature def getLightIntensity(self): return self.lightIntensity class temperatureWidget(Widget): def __init__(self, master, name, gui): super().__init__(master, name, gui) self.temperatureSliderLabel = Label(self.mainFrameTop, text="Temperature (°C)", bg="white") self.temperatureSlider = Scale(self.mainFrameTop, orient=HORIZONTAL, length=250, from_=0, to=40, bg="white") self.temperatureSliderLabel.pack() self.temperatureSlider.pack() self.temperatureFrame = Frame(self.mainFrameBottom, bg="white") self.temperatureFrame.pack(fill=X) self.temperatureValueLabel = Label(self.temperatureFrame, text="Temperature: ", justify=LEFT, bg="white", anchor="w") self.temperatureValue = Label(self.temperatureFrame, text="", bg="white") self.temperatureValueLabel.pack(side=LEFT, pady=5) self.temperatureValue.pack(side=RIGHT, pady=5) class lightWidget(Widget): def __init__(self, master, name, gui): super().__init__(master, name, gui) self.lightSliderLabel = Label(self.mainFrameTop, text="Light Intensity (%)", bg="white") self.lightSlider = Scale(self.mainFrameTop, orient=HORIZONTAL, length=250, bg="white") self.lightSliderLabel.pack() self.lightSlider.pack() self.lightSliderFrame = Frame(self.mainFrameBottom, bg="white") self.lightSliderFrame.pack(fill=X) self.lightSliderValueLabel = Label(self.lightSliderFrame, text="Light Intensity: ", justify=LEFT, bg="white", anchor="w") self.lightSliderValue = Label(self.lightSliderFrame, text="", bg="white") self.lightSliderValueLabel.pack(side=LEFT, pady=5, fill=X) self.lightSliderValue.pack(side=RIGHT, pady=5) Visueel = GUI(root) Arduino1 = lightWidget(root, "COM1", Visueel) Arduino2 = temperatureWidget(root, "COMT", Visueel) Arduino3 = lightWidget(root, "COML", Visueel) Arduino4 = temperatureWidget(root, "COM4", Visueel) Arduino5 = lightWidget(root, "COM5", Visueel) Visueel.addWidget(Arduino1) Visueel.addWidget(Arduino2) Visueel.addWidget(Arduino3) Visueel.addWidget(Arduino4) Visueel.addWidget(Arduino5) Visueel.showGui() root.mainloop()
Absolutely, this requirement is totally feasible! There are two solid approaches to handle this in Python, each with its own benefits depending on how you want to structure your code.
Approach 1: Check Instance Type with isinstance()
The simplest way is to use Python's built-in isinstance() function directly in the parent setSensors() method to detect which subclass the current instance belongs to. This works perfectly for your use case.
Update the setSensors() method in the Widget class like this:
def setSensors(self): print("Set the temperature and light of the sensors") # Common logic for all widgets self.maxRolloutPositionLabel.config(text="Rolling distance (cm): " + str(self.maxRolloutEntry.get())) # Check if this is a temperatureWidget instance if isinstance(self, temperatureWidget): temp_value = self.temperatureSlider.get() self.temperatureValue.config(text=f"{temp_value} °C") # Add a check for lightWidget if you want to handle it too elif isinstance(self, lightWidget): light_value = self.lightSlider.get() self.lightSliderValue.config(text=f"{light_value} %")
Approach 2: Use Polymorphism (Cleaner OOP Practice)
If you want to follow better object-oriented design principles, overriding the setSensors() method in each subclass is the way to go. This avoids type checking entirely and makes your code more maintainable if you add new widget types later.
First, update the parent Widget class's setSensors() to handle only the common logic:
class Widget: def setSensors(self): print("Set the temperature and light of the sensors") # Common logic that applies to all widgets self.maxRolloutPositionLabel.config(text="Rolling distance (cm): " + str(self.maxRolloutEntry.get()))
Then override the method in each subclass to add their specific behavior:
class temperatureWidget(Widget): # ... keep your existing __init__ code ... def setSensors(self): # Call the parent's common logic first super().setSensors() # Subclass-specific logic for temperature widgets temp_value = self.temperatureSlider.get() self.temperatureValue.config(text=f"{temp_value} °C") class lightWidget(Widget): # ... keep your existing __init__ code ... def setSensors(self): super().setSensors() # Subclass-specific logic for light widgets light_value = self.lightSlider.get() self.lightSliderValue.config(text=f"{light_value} %")
Both methods work reliably, but the polymorphism approach is generally preferred because it keeps your code modular and easier to extend. Either way, your original goal is completely achievable with Python's OOP features.
内容的提问来源于stack exchange,提问作者user7301337

