【问题标题】:python 3, tkinter NonType errorpython 3,tkinter NoneType 错误
【发布时间】:2018-08-05 06:03:00
【问题描述】:

我阅读了很多关于出现NonType 错误的人的帖子,因为他们尝试在定义tk widget 变量的同一行上使用.pack().grid().place()

示例

execute = tk.Button(text="Start", command=lambda:
Elements.ClickApp()).place(x=20, y=250, height=20, width=50)

响应是 A,不能使用 2 个函数,而且 B 无论如何难以在一行中阅读。我开始(不情愿地)接受.pack().grid().place() 的附加行,但现在遇到了附加行(甚至不起作用)。如:

T = tk.Entry()
T.bind("<Key>", Elements.Tbox)
T.place(x=20, y=230, height=20, width=50)

这三行不仅不能放在一行,这是我想要的..而且代码甚至不起作用。相反,按下的第一个按钮被忽略,然后第二个按钮(及以后)触发Elements.Tbox

相反,必须进一步增加换行符:

sv = tk.StringVar()
sv.trace("w", lambda name, index, mode, sv=sv: Elements.Tbox(sv))
T = tk.Entry(textvariable=sv)
T.place(x=20, y=230, height=20, width=50)

然后在第一次按下按钮时正确触发Elements.Tbox

有没有办法,(可能是lambda)这些新行可以减少? ...在处理大量小部件时,以这种方式对小部件进行分组更容易阅读。我发现这比单独的行更具可读性。

更新

我已经在这个问题的答案中包含了示例代码......尽管标记为正确的答案可能是更好的建议。如果有人需要这样做或类似的事情,您可以执行以下操作:

条目小部件示例:

EntryBox = tk.Entry().place().pack().grid() 结合使用

(lambda g: [(EntryBox.place(x=0, y=0, height=20, width=190)) for g['EntryBox'] in [tk.Entry()]])(globals())

【问题讨论】:

  • 您总是可以使用; 在一行中输入多个表达式,就像在 C 中一样,但我怀疑这是一个好方法。
  • 不清楚你在问什么。你从问一个问题开始,然后转而问一些不同的问题,最终得到完全不同的问题。请考虑重写您的问题以提出一件事,并使用能够准确重现您的问题的代码。
  • 我会考虑重写它...但是很清楚...我想缩短代码的第一个示例...如果不可能,我想缩短第二个代码示例(并让它工作)......如果不可能,我想缩短第三个代码示例。
  • 您可以在第三个示例中删除 "T=" 并将 Entry 和 place 放在一行上,因为您可以使用/获取 StringVar 并且不要在其他任何地方使用对 Entry 的引用。如果您有一大组小部件,请使用 for 或函数来创建它们,而不是单独创建它们。
  • 为什么在按钮中的命令不起作用时担心代码行数?我没能在你的咆哮中找到一个问题,因此投票决定关闭它。

标签: tkinter nonetype pack


【解决方案1】:

如果我理解正确,您想将这三行减少为行数更少的内容:

T = tk.Entry()
T.bind("<Key>", Elements.Tbox)
T.place(x=20, y=230, height=20, width=50)

简短的回答是,你不能。至少,不会使代码更难理解,这是软件开发的反模式。

原因只是像 python 这样的动态语言编程的一个基本方面:您不能在对象存在之前引用它们。因此,一个小部件必须存在才能调用packplacegridbind。鉴于这些函数返回 None,您不能像在其他语言中那样链接它们。

您可能想像这样组合第一和第三个语句:

T = tk.Entry().place(x=20, y=230, height=20, width=50)

那也行不通。原因是T 会被设置为None,导致以后无法引用widget。这是因为在 python 中,x().y() 返回 y() 的值,因此对于 Entry().grid()grid 总是返回 `None。

根据我的经验,您永远不应该将小部件创建和小部件布局命令组合在一起。相反,在一组中创建您的小部件,然后将它们布置在另一组中。绑定通常也是如此。

为什么?因为通常当您需要解决布局问题时,它涉及更改多个小部件的选项,因此将它们组合在一起很方便。

根据我的经验,将执行类似操作的代码组合在一起,而不是将与同一对象相关的所有语句组合在一起,GUI 代码更易于阅读和管理。

例如:

x = tk.Entry(...)
y = tk.Button(...)
z = tk.Label(...)

x.grid(...)
y.grid(...)
z.grid(...)

x.bind(...)
y.bind(...)
z.bind(...)

当然,这不是硬性规定。目标应该始终是清晰的,有时将小部件的创建和布局放在一起是有意义的,尽管这通常是在您只处理单个小部件时。

如果您想创建一堆参数几乎相同的相同小部件,而不是尽可能多地塞在一行上,您应该创建一个辅助函数。

例如,在您的情况下,您可能想要创建一个 create_entry 函数:

def create_entry(master, x, y, width, height, callback):
    entry = tk.Entry(master)
    entry.bind("<Key>", callback)
    entry.place(x=x, y=y, height=20, width=20)
    return entry

这样,您现在拥有了梦寐以求的单线解决方案:

T = create_entry(root, 20, 230, 20, 50, Elements.Tbox)
U = create_entry(root, 20, 290, 20, 50, Elements.Tbox)
V = create_entry(root, 20, 290, 20, 50, Elements.Tbox)
...

【讨论】:

  • 是否可以使用lambdaT = tk.Entry()pack()grid()place() 组合成一行?我正在尝试查看是否可以在一行中“初始化”每个小部件。
  • @Rhys:你可以把它放在线上,但是你会失去以后引用小部件的能力,因为x().grid()返回grid()的结果,grid,@987654345 @ 和 place 都返回 Null。就像我在回答中所写的那样,根据我的经验,最好将它们分开。随着时间的推移,它将使您的代码更容易调试和修改。
  • 嗯,好的,我会把你的答案标记为正确的。我问这个问题的原因是......我写了一个大型 Qt4 程序并在 2 年后重新访问它。我已经像您的 第二个示例 一样初始化了这些小部件......但发现它变得越来越混乱,就像“野鹅追逐”一样。因此,对于 tkinter,我一直试图从一开始就防止这个潜在的问题。我的示例 3 展示了如何在初始化阶段开始增加代码的复杂性
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-20
  • 1970-01-01
  • 2014-01-18
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
相关资源
最近更新 更多