【问题标题】:Tkinter Text Widget - variable in controllerTkinter Text Widget - 控制器中的变量
【发布时间】:2021-08-16 14:34:39
【问题描述】:

我有一个带有多个框架和不同小部件的小型 GUI。我能够使所有变量成为全局变量,并在控制器中可用,但我被困在文本小部件上。有什么建议吗?

这里只是一个例子,其中文本小部件在“PageOne”类中,打印功能在“PageTwo”上


import tkinter as tk
from tkinter import *
from tkinter import ttk

LARGE_FONT=("Verdana", 12)

class Movies(tk.Tk):

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

        tk.Tk.wm_title(self, "Movie I like")
        tk.Tk.wm_geometry(self, "500x500")
        container=tk.Frame(self)
        container.pack(side="top", fill="both", expand="True")
        
        self.app_data = {"movie":    StringVar(),
                         "popcorn": StringVar(),
                         "monday": BooleanVar(),
                         "tuesday": BooleanVar(),
                         "wednesday": BooleanVar(),
                         "thursday": BooleanVar(),
                         "friday": BooleanVar(),
                         "saturday": BooleanVar(),
                         "sunday": BooleanVar(),
                        }
        self.frames={}

        for F in (StartPage, PageOne, PageTwo):

            frame= F(container, self)
            self.frames[F]= frame

            frame.grid(row=0, column=0, sticky="nsew")


        self.show_frame(StartPage)
    
    def show_frame(self, cont):
        frame=self.frames[cont]
        frame.tkraise()



class StartPage(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        tk.Frame.__init__(self, parent)

        s = ttk.Style()
        s.configure('my.TButton', font=('Verdana', 8))

        label=tk.Label(self, text="Home Page", font=LARGE_FONT)
        label.pack(pady=10, padx=30)

        label1=tk.Label(self, text="When are you available?")
        label1.pack()
        #CheckButton
        ttk.Checkbutton(self, text='Monday', variable=self.controller.app_data["monday"]).pack()
        ttk.Checkbutton(self, text='Tuesday', variable=self.controller.app_data["tuesday"]).pack()
        ttk.Checkbutton(self, text='Wednesday', variable=self.controller.app_data["wednesday"]).pack()
        ttk.Checkbutton(self, text='Thursday', variable=self.controller.app_data["thursday"]).pack()
        ttk.Checkbutton(self, text='Friday', variable=self.controller.app_data["friday"]).pack()
        ttk.Checkbutton(self, text='Saturday', variable=self.controller.app_data["saturday"]).pack()
        ttk.Checkbutton(self, text='Sunday', variable=self.controller.app_data["sunday"]).pack()

        button_load=ttk.Button(self, text="Kind of Movie ", width=30, style='my.TButton',
                          command= lambda: controller.show_frame(PageOne))
        button_load.pack(padx=30)

class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        tk.Frame.__init__(self, parent)

        mybutton=ttk.Radiobutton(self, text='Drama', variable=self.controller.app_data["movie"], value="Drama").grid(column=1,row=1, sticky=W, padx=10)
        mybutton1=ttk.Radiobutton(self, text='Comedy', variable=self.controller.app_data["movie"], value="Comedy").grid(column=2,row=1, sticky=W, padx=10)
        
        globals()['user_message_entry'] = tk.Text(self, height=10, width=60).grid(column=1, row= 3, padx=5)



        button_next=ttk.Button(self, text="Next >> ", width=30, style='my.TButton',
                          command= lambda: controller.show_frame(PageTwo)).grid(column=3, row= 10, padx=5)
        
class PageTwo(tk.Frame):
    def __init__(self, parent, controller):
        self.controller = controller
        tk.Frame.__init__(self, parent)
        
        body = globals()['user_message_entry'].get("1.0", "end")
        mybutton2=ttk.Radiobutton(self, text='Salty', variable=self.controller.app_data["popcorn"], value="Salty").grid(column=1,row=1, sticky=W, padx=10)
        mybutton3=ttk.Radiobutton(self, text='Sweet', variable=self.controller.app_data["popcorn"], value="Sweet").grid(column=2,row=1, sticky=W, padx=10)
        
        def save_info():
            pop_info=self.controller.app_data["popcorn"].get()
            movie_info=self.controller.app_data["movie"].get()
            week=["monday", "tuesday", "wednesday","thursday","friday","saturday","sunday"]
            print("you like " + movie_info + " and you would like " + pop_info +" popcorn")
            print("This is the body" + body)
            test=len(week)
            for i in range (0, test):
                if self.controller.app_data[week[i]].get() == True:
                    print(week[i])


        button_submit=ttk.Button(self, text="Submit", width=15,
                          command=save_info).grid(column=3, row= 10, padx=5)


app=Movies()
app.mainloop()

【问题讨论】:

  • 为什么要让它们全球化?为什么要使用global() 而不是仅仅将其声明为全局?没有必要。您是否看过this answer 中的“使用共享数据”部分?
  • 是的,我看到了这个,我用它在控制器中为所有其他小部件创建变量。但是,文本小部件是不同的,因为我无法将文本链接到变量,或者至少我不知道该怎么做..
  • tk.Text(self, height=10, width=60).grid(column=1, row= 3, padx=5) 返回无。应该是:variable = tk.Text(self, height=10, width=60)variable.grid(column=1, row= 3, padx=5)
  • @8349697 .grid 确实在工作,我的问题是让 textwidget 输入在多个类中可用
  • 当我运行你的代码时,我得到了错误:AttributeError: 'NoneType' object has no attribute 'get'.

标签: python tkinter text-widget


【解决方案1】:

一种解决方案是将小部件存储在控制器中,就像保存其他东西一样。

例如:

class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        ...
        self.controller.app_data["user_message_entry"] = Text(self, height=10, width=60)
        ...

然后,要获取值,类似于获取其他变量的方式:

body = self.controller.app_data['user_message_entry'].get("1.0", "end")

另一种访问它的方法是给你的控制器一个返回页面的函数。然后您可以使用返回的页面访问它。

例如,首先在控制器中添加一个函数来返回一个页面:

class Movies(tk.Tk):
    ...
    def get_page(self, page_class):
        return self.frames[page_class]
    ...

接下来,确保文本小部件是一个实例变量:

class PageOne(tk.Frame):
    def __init__(self, parent, controller):
        ...
        self.user_message_entry' = tk.Text(self, height=10, width=60).grid(column=1, row= 3, padx=5)
        ...

最后,在控制器中使用该函数获取另一个页面,然后从那里获取文本小部件:

page = self.controller.get_page(PageOne)
body = page.textuser_message_entry.get("1.0", "end")

上面描述了如何从多个地方访问文本小部件。但是,您还有另一个问题,即您编写的代码试图在创建小部件几毫秒后从小部件中获取文本。您需要等到用户有机会在小部件中输入内容才能获取数据。

例如,您需要将body = page.textuser_message_entry.get("1.0", "end") 移动到save_info 函数内。

【讨论】:

  • 我很抱歉,但不知何故它似乎不起作用 1) 我将 user_message_entry": Text(), 添加到控制器,将小部件添加到 PageOne tk.Text(self,self.controller.app_data["user_message_entry"], height=10, width=60).grid(column=1, row= 3, padx=5) 然后尝试获取它 body = self.controller.app_data['user_message_entry'].get("1.0", "end") 我没有任何错误,但是当我尝试打印它时它是空的
  • @startingover:很抱歉我的回答不清楚。您不能在顶部定义user_message_entry。你必须在PageOne.__init__ 内完成。我更新了我的答案以更清楚。
  • 不知何故我仍然无法打印它的正文,不确定我在这里遗漏了什么。我将以下内容添加到 PageOne self.controller.app_data["user_message_entry"] = Text(self, height=10, width=60) 并将以下内容添加到 PageTwo... body = self.controller.app_data['user_message_entry'].get(0.0, END)然后我的打印功能总是在 PageTwo
  • 我也尝试了类的可能性,但我仍然无法打印它。它看起来总是返回一个空白空间 - 不知道为什么
  • @startingover:PageTwo.__init__ 中的代码几乎在文本小部件创建后立即发生。用户还没有机会输入任何内容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-27
  • 1970-01-01
  • 2020-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多