tkinter:如何让 Label 的子类显示在屏幕上?

tkinter: How to get a subclass of Label to show on screen?

我正在尝试在 Python 中使用 类 做一些事情(我来自程序语言背景)。尝试创建一个版本的 tkinter Label 小部件支持几个新方法来操作标签的文本。

我的问题是我无法让标签在屏幕上实际可见。

代码如下:

from tkinter import *

DEFAULT_BG = '#f0f0f0'


class cngMsg(Label):
    """Message Display label"""
    def __init__(self, parent, w, h):
        """Init the Message Label"""
        self.parent = parent
        Label.__init__(self, parent)
        self.msgText = "Hello World"
        self.msgLabel = Label(parent, text=self.msgText)
        self.msgLabel.config(height=h, width=w, bg=DEFAULT_BG)

    def clear(self):
        self.msgText = ""
        print(len(self.msgText))
        self.msgLabel.config(text=self.msgText)

    def newMessage(self, message):
        print("about to display <" + message + ">")
        self.msgText = message
        print(len(self.msgText))
        self.msgLabel.config(text=self.msgText)

    def show(self, message, sameLine=None):
        if (not sameLine) and len(self.msgText) > 0:
            self.msgText += '/n'
        print("about to show: <" + message + ">")
        self.msgText = self.msgText + message
        print(len(self.msgText))
        self.msgLabel.config(text=self.msgText)


#Root Stuff

if __name__ == "__main__":

    app = Tk()
    app.title("Message Test")

    # this is the start of the application
    print("initialise the Message Test")

    gMsg = cngMsg(app, 60, 20)
    gMsg.pack()
    gMsg.newMessage("new message")
    gMsg.show("this is a test")
    gMsg.show("second test")

    app.mainloop()

调试打印消息出现在控制台上,但应用程序 window 不显示标签。

GUI 编程需要使用非过程范式,因为它们是用户输入驱动的。问题 Tkinter — executing functions over time 对此进行了讨论并提供了一些示例代码。

我个人经常发现在创建 GUI 应用程序时将它们视为 FSM (Finite State Machines) 很有用,用户输入会导致它们改变状态。

这里是如何做一些类似于我认为你在你的示例代码中尝试做的事情,它基于@Bryan Oakley 对链接问题的回答(更新为 Python 3)。它还显示了子类化 tkinter 类 的正确方法。此外,它主要遵循 PEP 8 - Style Guide for Python Code 指南,我强烈 建议您阅读并开始关注。

from tkinter import *

DEFAULT_BG = '#f0f0f0'
DEFAULT_MSG_TEXT = "Hello World"
DELAY = 1000  # Milliseconds.


class CngMsg(Label):
    """Message Display label"""
    def __init__(self, parent, w, h):
        # Intialize with default text and background color.
        super().__init__(parent, text=DEFAULT_MSG_TEXT, height=h, width=w, bg=DEFAULT_BG)

    def clear(self):
        self.config(text='')

    def newMessage(self, message):
        self.config(text=message)

    def show(self, message, same_line=False):
        text = self.cget('text')  # Get value of current option.
        if not same_line and text:
            text += '\n'
        text += message
        self.config(text=text)


class MyApp(Tk):
    def __init__(self):
        super().__init__()
        self.frame = Frame(self)
        self.frame.pack()

        self.test_msg = CngMsg(self.frame, 60, 20)
        self.test_msg.pack()

        self.state = 0
        self.do_test()

    def do_test(self):
        if self.state == 0:
            self.test_msg.newMessage("start message")
            self.state = 1
        elif self.state == 1:
            self.test_msg.show("this is a test")
            self.state = 2
        elif self.state == 2:
            self.test_msg.show("second test")
            self.state = 3
        elif self.state == 3:
            self.test_msg.clear()
            self.test_msg.show("TEST COMPLETED")
            self.state = -1  # Enter final state.
        elif self.state != -1:
            self.quit()  # Stop mainloop.
            raise RuntimeError("Unknown state encountered")

        if self.state != -1: # Not final state?
            self.after(DELAY, self.do_test)  # Schedule another call.


if __name__ == "__main__":
    root = MyApp()
    root.title("Message Test")
    root.mainloop()

您的 cngMsg class 正在创建 两个 标签。第一个是 class 本身的实例。第二个是在您执行 self.msgLabel = Label(parent, text=self.msgText) 时创建的。第二个标签是 cngMsg 标签的子标签。由于您没有在第二个标签上调用 packplacegrid,因此它不会出现在任何地方。

在您的 newMessage 方法中,您正在更新不可见标签而不是实际标签中的文本。

您不需要第二个标签,在 newMessage 中您应该这样配置自己:

def newMessage(self, message):
    self.msgText = msgText
    self.configure(text=self.msgText)

类似地,showclear应该以类似的方式定义:

def clear(self):
    self.msgText = ""
    self.config(text=self.msgText)

def show(self, message, sameLine=None):
    if (not sameLine) and len(self.msgText) > 0:
        self.msgText += '/n'
    self.msgText = self.msgText + message
    self.config(text=self.msgText)