【问题标题】:How to, in class 1, change the properties of a widget (label) in class 2 (Tkinter)?如何在第 1 类中更改第 2 类(Tkinter)中的小部件(标签)的属性?
【发布时间】:2019-04-29 07:48:08
【问题描述】:

我试图在MainMenu 类中设置一个recordBn 按钮,以更改RecordTime 类中dateLb 标签的文本。但我不断收到如下错误消息。

AttributeError: 'RecordTime' object has no attribute 'dateLb'

使用GFPTime类的empcbxlist()

我已尝试通过此post 和其他几篇具有相同错误消息 (AttributeError) 的帖子解决我的问题,但找不到解决方案。帮我解决我的错误

#!/usr/bin/python
import os.path
import sys
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
# from PIL import Image, ImageTk
# from dbfunctions import *
import datetime

class GFPTime(tk.Tk):
    def __init__(self,*args,**kwargs):

        tk.Tk.__init__(self,*args,**kwargs)

        tk.Tk.wm_title(self,"GFP Employee Timecard System")
        tk.Tk.wm_geometry(self,"800x480+0+0")

        container =tk.Frame(self)
        container.pack(side='top',fill='both',expand= True)

        container.grid_rowconfigure(0,weight=1)
        container.grid_columnconfigure(0,weight=1)

        self.frames = {}

        for F in (MainMenu,RecordTime):

            frame = F(container,self)

            self.frames[F] = frame
            frame.grid(row=0,column=0,stick='nsew')

        self.show_frame(MainMenu)
        # print(self.frames.values())
    def show_frame(self,cont):
        frame = self.frames[cont]
        frame.tkraise()

    def empcbxlist(self, widget_name, criteria, output):
        # db = TimeCardDB()
        # cbvalue = db.listActiveEmployees()
        # db.dbclose()

        widget = getattr(RecordTime,'dateLb')
        widget[criteria] = output

###
class MainMenu(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        #tk.Frame.configure(self,background='red')
        font9 = "-family {Minion Pro} -size 14 -weight bold"
        self.controller = controller

        recordBn = tk.Button(self,command=lambda: [self.controller.show_frame(RecordTime), self.controller.empcbxlist('self.dateLb','text','yessss')])
        recordBn.place(relx=0.269, rely=0.646, height=50, width=180)
        recordBn.configure(activebackground="#ececec")
        recordBn.configure(activeforeground="#000000")
        recordBn.configure(background="#d9d9d9")
        recordBn.configure(disabledforeground="#a3a3a3")
        recordBn.configure(font=font9)
        recordBn.configure(foreground="#000000")
        recordBn.configure(highlightbackground="#d9d9d9")
        recordBn.configure(highlightcolor="black")
        recordBn.configure(pady="0")
        recordBn.configure(text='''Record Time''')#!/usr/bin/python


class RecordTime(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        self.controller = controller
        dateLb = tk.Label(self)
        dateLb.place(relx=0.213, rely=0.021, height=38, width=144)
        dateLb.configure(activebackground="#f9f9f9")
        dateLb.configure(activeforeground="black")
        dateLb.configure(disabledforeground="#a3a3a3")
        dateLb.configure(font="-family {Minion Pro} -size 14 -weight bold")
        dateLb.configure(foreground="#000000")
        dateLb.configure(highlightbackground="#d9d9d9")
        dateLb.configure(highlightcolor="black")
        dateLb.configure(text='''SHOW DATE''')



GFPTime().mainloop()

【问题讨论】:

  • 这里的代码太多了。请尽可能多地删除代码,同时仍然保留问题的本质。哦,还要格式化它,以便 Python 程序员可以阅读。
  • 这是因为dateLbRecordTime类的__init__(...)内部的局部变量,所以不能在类外访问。在RecordTime 类中将dateLb 替换为self.dateLb
  • @acw1668:这不会解决问题,因为他没有从他保存在列表self.frame 中的类中获取属性,而是直接从没有的类中调用它有一个实例。

标签: python python-3.x tkinter widget tk


【解决方案1】:

您的代码几乎没有问题。

  1. 当您创建字典 self.frames 并使用其类名保存每个框架的对象时,然后使用字典来获取它们的方法和属性 不要使用像 widget = getattr(RecordTime,'dateLb') 这样的类名来访问他们而不是RecordTime 使用您保存在字典中的类。

  2. 不要在 lambda 函数中提供小部件名称 self.dateLb,只需 dateLb 就足够了。

    变化:

    self.controller.empcbxlist('self.dateLb','text','yessss')

    self.controller.empcbxlist('dateLb','text','yessss')

  3. 正如@aw1668 所说“将RecordTime 类中的dateLb 替换为self.dateLb 因此,通过将dateLb 标签更改为self.dateLb 来全球化。

我把empcbxlist()里面的代码块改成了这个。

def empcbxlist(self, widget_name, criteria, output):
    # db = TimeCardDB()
    # cbvalue = db.listActiveEmployees()
    # db.dbclose()

    # Get the frame. 
    ob = self.frames.get( RecordTime ) 
    widget = getattr(ob,widget_name)
    widget[criteria] = output

    # can use this to change the text to be on safe side.
    # for i, j  in self.frames.items():
    #     if i.__name__ == RecordTime.__name__:
    #         widget = getattr(j,widget_name)
    #         widget[criteria] = output

完整代码:

#!/usr/bin/python
import os.path
import sys
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
# from PIL import Image, ImageTk
# from dbfunctions import *
import datetime

class GFPTime(tk.Tk):
    def __init__(self,*args,**kwargs):

        tk.Tk.__init__(self,*args,**kwargs)

        tk.Tk.wm_title(self,"GFP Employee Timecard System")
        tk.Tk.wm_geometry(self,"800x480+0+0")

        container =tk.Frame(self)
        container.pack(side='top',fill='both',expand= True)

        container.grid_rowconfigure(0,weight=1)
        container.grid_columnconfigure(0,weight=1)

        self.frames = {}

        for F in (MainMenu,RecordTime):

            frame = F(container,self)

            self.frames[F] = frame
            frame.grid(row=0,column=0,stick='nsew')

        self.show_frame(MainMenu)
        # print(self.frames.values())
    def show_frame(self,cont):
        frame = self.frames[cont]
        frame.tkraise()

    def empcbxlist(self, widget_name, criteria, output):
        # db = TimeCardDB()
        # cbvalue = db.listActiveEmployees()
        # db.dbclose()

        ob = self.frames.get( RecordTime ) 
        widget = getattr(ob,widget_name)
        widget[criteria] = output

###
class MainMenu(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        #tk.Frame.configure(self,background='red')
        font9 = "-family {Minion Pro} -size 14 -weight bold"
        self.controller = controller

        recordBn = tk.Button(self,command=lambda: [self.controller.show_frame(RecordTime), self.controller.empcbxlist('dateLb','text','yessss')])
        recordBn.place(relx=0.269, rely=0.646, height=50, width=180)
        recordBn.configure(activebackground="#ececec")
        recordBn.configure(activeforeground="#000000")
        recordBn.configure(background="#d9d9d9")
        recordBn.configure(disabledforeground="#a3a3a3")
        recordBn.configure(font=font9)
        recordBn.configure(foreground="#000000")
        recordBn.configure(highlightbackground="#d9d9d9")
        recordBn.configure(highlightcolor="black")
        recordBn.configure(pady="0")
        recordBn.configure(text='''Record Time''')#!/usr/bin/python


class RecordTime(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        self.controller = controller
        self.dateLb = tk.Label(self)
        self.dateLb.place(relx=0.213, rely=0.021, height=38, width=144)
        self.dateLb.configure(activebackground="#f9f9f9")
        self.dateLb.configure(activeforeground="black")
        self.dateLb.configure(disabledforeground="#a3a3a3")
        self.dateLb.configure(font="-family {Minion Pro} -size 14 -weight bold")
        self.dateLb.configure(foreground="#000000")
        self.dateLb.configure(highlightbackground="#d9d9d9")
        self.dateLb.configure(highlightcolor="black")
        self.dateLb.configure(text='''SHOW DATE''')



GFPTime().mainloop()

希望这会有所帮助。

【讨论】:

  • 谢谢大家的帮助。抱歉,代码/帖子凌乱,漫长的夜晚试图解决这个问题,但仍然是 python 的菜鸟并在堆栈溢出时发帖。
【解决方案2】:

您的代码有点混乱,而且过于复杂。我已将其缩小到更易于消化的大小 - 装饰只会增加代码的混乱程度。

请一直盯着它看,直到您了解哪些元素在做什么,并且可能从那里重建。

import tkinter as tk
import datetime


class GFPTime(tk.Tk):

    def __init__(self):
        super().__init__()
        super().wm_title("GFP Employee Timecard System")
        self.container = tk.Frame(self)
        self.container.pack(side='top',fill='both',expand= True)
        self.frames = {}
        for F in (MainMenu, RecordTime):    
            self.frames[F] = F(self.container, self)
            self.frames[F].grid(row=0,column=0,stick='nsew')
        self.show_frame(MainMenu)

    def show_frame(self, container):
        self.frames[container].tkraise()

    def empcbxlist(self, text_value):
        self.show_frame(RecordTime)
        self.frames[RecordTime].date_lbl.configure(text=text_value)


class MainMenu(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller
        record_btn = tk.Button(self, text='Record Time', 
                             command=lambda text_value=str(datetime.date.today()): self.controller.empcbxlist(text_value))
        record_btn.pack()


class RecordTime(tk.Frame):

    def __init__(self, parent, controller):
        super().__init__(parent)
        self.controller = controller
        self.date_lbl = tk.Label(self, text='SHOW DATE')
        self.date_lbl.pack()


GFPTime().mainloop()

【讨论】:

  • 您的建议将消除在原始 OP 设计中更改 RecordTime 类的不同属性的灵活性。
  • 是的。该代码最初是从 Bryan Oakley 的一篇文章中复制而来的,但已经看到了如此多的变化,以至于它变得笨拙。关键是要做到足够简单,(1)它可以工作,(2)OP 理解它的作用,以及如何......然后将功能重新添加到其中。
猜你喜欢
  • 2021-08-13
  • 1970-01-01
  • 1970-01-01
  • 2020-04-22
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-21
相关资源
最近更新 更多