You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Tkinter父类中判断当前子类并执行对应操作

Can I determine which subclass is being used in a parent class method in 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()

Answer

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:42:43