【问题标题】:Tkinter Button to creat entries用于创建条目的 Tkinter 按钮
【发布时间】:2021-01-18 11:51:06
【问题描述】:

我正在尝试学习 tkinter,但遇到了一个小问题。 我创建了一个非常简单的窗口,在“Activity:”、“Time Spend:”顶部有 2 条消息,在窗口底部有一个“+”按钮。

from tkinter import *

root = Tk()
root.geometry("274x520+868+240")
root.minsize(120, 1)
root.maxsize(3284, 1068)
root.resizable(0, 0)
root.title("Learning")
root.configure(background="black")


def new_entry():
    n = [n for n in range(30, 490, 30)]

    for i in n:
        e1 = Entry(root)
        e2 = Entry(root)
        e1.place(y=i, width=133)
        e2.place(x=141, y=i, width=137)

        print(e1, e2)
        return e1, e2


b1 = Button(root)
b1.place(y=499, width=276)
b1.configure(text="+")
b1.configure(command=new_entry)
b1.configure(background="darkgrey")

msg1 = Message(root)
msg1.place(width=133, height=29)
msg1.configure(text="Activity:")
msg1.configure(background="darkgrey")

msg2 = Message(root)
msg2.place(x=141, width=137, height=29)
msg2.configure(text="Time Spend:")
msg2.configure(background="darkgrey")

root.mainloop()

该按钮应该在每次单击时创建两个相邻的条目,但是如果我单击该按钮,它将创建一次条目,再次单击它不会在窗口上创建条目,而只是创建这在我的终端:

.!entry .!entry2
.!entry3 .!entry4
.!entry5 .!entry6
.!entry7 .!entry8 

如果我删除 "return e1,e2" 语句,所有条目都会在终端和窗口中创建,只需单击 1 次按钮,而不是 2 乘 2 创建每次点击按钮。

如果我删除 "print(e1,e2)" 语句,单击按钮将只创建 2 个条目一次,并且不会在终端中显示任何内容。

创建新条目时应留出一点空间,直到到达 Button 的上边界(在本例中为 32 个条目,16 行)。

谁能解释一下为什么 msg1 显示错误(它没有居中并且分成两行),但是 msg2 很好,它们具有相同的规格??

【问题讨论】:

    标签: python-3.x tkinter button


    【解决方案1】:

    一旦到达return 语句,您的代码就会停止,因此您的循环永远不会超过第一次迭代。

    另一方面,如果您删除 return 语句,则无法停止循环,因此它会一直运行,直到创建所有小部件为止。

    我采用了一种使用生成器来解决您的问题的方法,这样您就可以使用一个函数来生成条目,而不是使用函数 new_entry(),而另一个函数会在调用生成器时放置条目。

    我还在小部件生成时稍微简化了您的代码,并更改了一个拼写错误(spent 而不是spend)。我还将from tkinter import * 替换为import tkinter as tk,以免污染您的命名空间。

    import tkinter as tk
    
    root = tk.Tk()
    root.geometry("274x520+868+240")
    root.minsize(120, 1)
    root.maxsize(3284, 1068)
    root.resizable(0, 0)
    root.title("Learning")
    root.configure(background="black")
    
    
    def entry_generator():
        for i in range(30, 490, 30):
            yield place_entry(i)
    
    
    def place_entry(i):
        e1 = tk.Entry(root)
        e2 = tk.Entry(root)
        e1.place(y=i, width=133)
        e2.place(x=141, y=i, width=137)
        print(e1, e2)
    
    
    ne = entry_generator()
    b1 = tk.Button(root, command=lambda: next(ne), text='+', background='darkgrey')
    b1.place(y=499, width=276)
    
    msg1 = tk.Label(root, text='Activity:', background='darkgrey')
    msg1.place(width=133, height=29)
    
    msg2 = tk.Label(root, text='Time Spent:', background='darkgrey')
    msg2.place(x=141, width=137, height=29)
    
    root.mainloop()
    

    【讨论】:

    • 感谢您的帮助,我不熟悉您编写它的方式(创建小部件),但我会尝试弄清楚。你对 msg1 也有任何解决方案吗?即使使用您的版本,它仍然存在相同的问题。
    • @Aru 您可以使用Label 而不是Message,那么它应该可以工作 - 我刚刚更改了我的解决方案以反映这一点
    • hmm.. 很奇怪,但它有效,谢谢。据说当在 Message() 中创建文本时默认为“居中”,但无论如何。
    • @Aru 我试着让我的代码更明确一点,这样更容易理解。基本上发生的事情是函数entry_generator 是一种称为生成器对象的东西。生成器对象具有每次调用next(ne) 时都会返回循环的下一个元素的属性。所以当你第一次打电话给next(ne) 时,你得到的是i=30。下次i=60等等。
    • @Aru 我认为这是因为由于窗口的尺寸,Message 小部件确定没有足够的空间容纳整行,因此它会自动进行行拆分。如果您的窗口更大,那么Message 也可以。 Label 不会自动进行行拆分,所以你没有这个问题 :)
    【解决方案2】:
    def new_entry():
        n = [n for n in range(30, 490, 30)]
    
        for i in n:
            e1 = Entry(root)
            e2 = Entry(root)
            e1.place(y=i, width=133)
            e2.place(x=141, y=i, width=137)
    
            print(e1, e2)
            return e1, e2 ```
    

    return 是问题所在。看下面的示例代码:

    def iterate():
        for i in range(10):
            print(i)
            return i
    val = iterate()
    print(val)
    

    当你运行它时,它会打印:

    0
    0
    

    因为,return 使函数立即停止并返回一些东西。 如果您真的必须返回每个值,则可以创建一个列表,将内容附加到其中,然后在 循环之后返回该列表:

    def iterate():
        arr = []
        for i in range(10):
            print(i)
            arr.append(i)
        return arr
    val = iterate()
    print(val)
    

    将打印:

    0
    1
    2
    ...
    10
    [0, 1, 2, ... 10]
    

    或使用yield 关键字(它将返回值而不使循环停止):

    ```python
    def iterate():
        for i in range(10):
            print(i)
            yield i
    val = iterate()
    print(val)
    print([i for i in val])
    

    将打印:

    0
    1
    2
    ...
    10
    <generator object iterate at 0x7fb64e584f68> 
    [0, 1, 2, 3 ... 10]
    

    对于yieldval 将是一个生成器对象,您必须再次对其进行迭代以从中获取值。 但是,由于您的代码中的任何地方都没有使用返回值,因此您只需删除 return e1, e2

    【讨论】:

    • 谢谢,我正要研究那个“产量”的东西
    【解决方案3】:

    另一种实现方法可能是保留条目计数并将计数乘以Entry 小部件的高度

    这是一个例子:

    count = 0
    
    def new_entry():
        global count
        e1 = Entry(root)
        e2 = Entry(root)
    
        count += 1
        y_pos = count*e1.winfo_reqheight()
        e1.place(x=0, y=y_pos*1.5, width=133) # change the multiplication factor to change the padding b/w entry
        e2.place(x=141, y=y_pos*1.5, width=137) # change the multiplication factor to change the padding b/w entry
    
        print(e1, e2)
    

    还请注意,对此类程序使用网格布局可能会更好。

    【讨论】:

    • 是否有解释差异的页面,或帮助我定位小部件?我编写小部件的方式是迄今为止我学到的唯一方式
    • @Aru Here 看看。
    猜你喜欢
    • 2016-05-03
    • 1970-01-01
    • 2016-07-31
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 2016-04-28
    • 2016-12-27
    • 1970-01-01
    相关资源
    最近更新 更多