简体   繁体   English

Tkinter OptionMenu小部件未显示值

[英]Tkinter OptionMenu widget is not displaying values

At the moment I am working on a project using Python 3.6 Tkinter. 目前,我正在使用Python 3.6 Tkinter进行项目。 At the moment, I am trying to make a user access rights OptionMenu for me to put either "User" or "Admin". 目前,我正在尝试为用户提供OptionOption的访问权限,使其放置“ User”或“ Admin”。 I have tried various methods, but cannot seem to either fix it myself or to find helpful documentation online. 我尝试了各种方法,但似乎无法自己修复或在线找到有用的文档。 The problem isn't in making the OptionMenu and displaying it, nor is it that the value of the StringVar variable isn't changing. 问题不在于制作OptionMenu并显示它,也不在于StringVar变量的值没有改变。 The problem is that the text inside of the OptionMenu isn't changing when any new option is selected. 问题在于,当选择任何新选项时,OptionMenu内的文本不会更改。

class UsersDetailsEditPage(Tk):
def __init__(self, *args, **kwargs):
    Tk.__init__(self, *args, **kwargs)
    self.title("Edit User Details")
    self.option_add("*Font", 'TkDefaultFont')

    self.noteBook = ttk.Notebook(self)

    for i in range(len(users)):
        self.noteBook.add(self.getUserViewFrame(users[i]), text=users[i][2])
    self.noteBook.pack()

    self.resizable(width=False, height=False)

def getUserViewFrame(self, user):
    frame = Frame(self)
    frame.grid_rowconfigure(1, weight=1)
    frame.grid_columnconfigure(1, weight=1)

    Label(frame, text="User's name:").grid(row=0, column=0, sticky=W)
    nameText = Text(frame, height=1, width=20)
    nameText.insert("1.0", user[2])
    nameText.edit_reset()
    nameText.grid(row=0, column=1, sticky=E)

    Label(frame, text="Username:").grid(row=1, column=0, sticky=W)
    usernameText = Text(frame, height=1, width=20)
    usernameText.insert("1.0", user[0])
    usernameText.edit_reset()
    usernameText.grid(row=1, column=1, sticky=E)

    Label(frame, text="Password:").grid(row=2, column=0, sticky=W)
    passwordText = Text(frame, height=1, width=20)
    passwordText.insert("1.0", user[1])
    passwordText.edit_reset()
    passwordText.grid(row=2, column=1, sticky=E)

    # the constructor syntax is:
    # OptionMenu(master, variable, *values)

    Label(frame, text="User Access:").grid(row=3, column=0, sticky=W)
    self.options = StringVar()
    self.options.set("User")

    self.userAccessDrop = ttk.OptionMenu(frame, self.options, "User", *("User", "Admin"))
    self.userAccessDrop.config(width=10)
    self.userAccessDrop.grid(row=3, column=1, sticky=E)

    return frame

This is the output of the code 这是代码的输出

I have all the library imports that are needed (I think): 我有所有需要的库导入(我认为):

from tkinter import *
from tkinter import messagebox
import tkinter.ttk as ttk
import csv
import os

If anyone can work out how to make this work it would be much appreciated. 如果有人能解决如何完成这项工作,将不胜感激。 Thanks 谢谢

I tried your code and it works for me. 我尝试了您的代码,它对我有用。 I can only guess that this is a garbage collection problem. 我只能猜测这是垃圾回收问题。 Try assigning the option menu to frame rather than self, so that it doesn't get overwritten. 尝试将选项菜单分配给边框而不是边框​​,这样就不会被覆盖。

frame.options = StringVar()
frame.options.set("User")

frame.userAccessDrop = ttk.OptionMenu(frame, frame.options, "User", *("User", "Admin"))
frame.userAccessDrop.config(width=10)
frame.userAccessDrop.grid(row=3, column=1, sticky=E)

You really should rewrite this so that you subclass a Frame to make the user instances. 您确实应该重写此代码,以便子类化Frame来制作用户实例。

Edit: for example: 编辑:例如:

import tkinter as tk
from tkinter import ttk

class UserFrame(tk.Frame):
    def __init__(self, master=None, data=None, **kwargs):
        tk.Frame.__init__(self, master, **kwargs)

        data = data[2], data[0], data[1] # rearrange data
        labels = ("User's name:", "Username:", "Password:")
        for row, (label, value) in enumerate(zip(labels, data)):
            lbl = tk.Label(self, text=label)
            lbl.grid(row=row, column=0, sticky=tk.W)
            ent = tk.Entry(self)
            ent.insert(0, value)
            ent.grid(row=row, column=1, sticky=tk.E)

        lbl = tk.Label(self, text="User Access:")
        lbl.grid(row=3, column=0, sticky=tk.W)
        self.options = tk.StringVar(self, "User")

        self.userAccessDrop = ttk.OptionMenu(self,
            self.options,
            "User", # starting value
            "User", "Admin", # options
            )
        self.userAccessDrop.config(width=10)
        self.userAccessDrop.grid(row=len(labels), column=1, sticky=tk.E)

class UsersDetailsEditPage(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.title("Edit User Details")
        self.option_add("*Font", 'TkDefaultFont')

        self.noteBook = ttk.Notebook(self)

        for user in users:
            self.noteBook.add(UserFrame(self, user), text=user[2])
        self.noteBook.pack()

        self.resizable(width=False, height=False)

It's really not functionally any different from what you have, just neater code (which actually makes a huge difference in coding time). 实际上,它在功能上与您所拥有的并没有什么不同,只是代码更整洁(实际上在编码时间上有很大的不同)。 Note I also got rid of the evil wildcard import and condensed your code a bit. 注意,我还摆脱了邪恶的通配符导入,并简化了您的代码。 Remember, if you are copying and pasting code blocks you are doing the computer's job. 请记住,如果要复制和粘贴代码块,则是在执行计算机的工作。 I also moved you to Entry widgets, which are a single line Text widget. 我也将您移到了Entry小部件,它们是单行的Text小部件。 Also, try to avoid the "convenience" initializing and laying out a widget on the same line. 此外,请尝试避免在同一行上初始化窗口小部件并将其布置在“方便”位置。 It's ugly and it leads to bugs. 这很丑陋,并且会导致错误。

I used 'self' in for the "self.options" and "self.userAccessDrop", but since we subclassed the Frame, "self" now refers to the Frame instance. 我在“ self.options”和“ self.userAccessDrop”中使用了“ self”,但是由于我们将Frame子类化,因此“ self”现在是指Frame实例。 In other words it's the same as my above block where I used "frame.options". 换句话说,这与我上面使用“ frame.options”的代码块相同。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM