【问题标题】:Python Tkinter dynamic window not working properlyPython Tkinter 动态窗口无法正常工作
【发布时间】:2021-08-16 20:30:36
【问题描述】:

我正在尝试为自己制作一个财务计算器。到目前为止,我没有任何重大问题,但现在我被卡住了,无法弄清楚出了什么问题。 我是这个世界的新手,所以不要为我蹩脚的编码技巧生气哈哈! 我用python制作了sqlite数据库,在这一步中,我试图拉一列并动态地为每个值制作按钮。我成功地迈出了这一步,但我的 TopLevel 窗口没有调整它应该如何调整大小。造成这个问题的原因是我希望在与根窗口相同的位置打开 TopLevel,但我不知道我在哪里犯了错误。 这是我的代码,我删除了大部分不重要的小部件,并自动输入到数据库中,这样你们就可以检查动态按钮的创建。希望您了解我的问题,如果您需要更多解释,我会尽力而为。 大多数代码变量都在我的语言上,希望这不是问题,我不知道为什么我粘贴代码时缩进会混乱。

from tkinter import *
import sqlite3

conn = sqlite3.connect('Test.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS OTPLATA_NA_RATE
         ([ID] INTEGER PRIMARY KEY,[Opis] text, [Iznos_rate] integer, [Broj_rata] text, [Datum_kupnje] text)''')
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "a", 500, "2", "2021-08-10"))
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "b", 500, "2", "2021-08-10"))
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "c", 500, "2", "2021-08-10"))
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "d", 500, "2", "2021-08-10"))
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "e", 500, "2", "2021-08-10"))
c.execute("INSERT INTO OTPLATA_NA_RATE VALUES (?, ?, ?, ?, ?);", (None, "f", 500, "2", "2021-08-10"))


class FinancialCalc:
def __init__(self, master):
    # Start window:
    self.master = master
    self.master.title("Kalkulator troška")
    self.master.geometry("300x300")
    self.master.resizable(False, False)

    self.otplata_na_rate_button = Button(master, text="Otplata na rate", width=15,
                                         command=self.otplata_na_rate_deiconify)
    self.otplata_na_rate_button.place(x=95, y=155)

    # TopLevel window
    self.onr_top = Toplevel()
    self.onr_top.title("Kalkulator troška")
    self.onr_top.withdraw()

def otplata_na_rate_deiconify(self):
    # Otplata_na_rate TopLevel:
    self.master.withdraw()
    self.onr_top.deiconify()
    self.onr_top.protocol("WM_DELETE_WINDOW", lambda: (self.master.deiconify(), self.onr_top.withdraw()))
    # Pull data from db and creating dynamic buttons (depends how many items are in db)
    c.execute('SELECT Opis FROM OTPLATA_NA_RATE')
    lista_opisa_rata = list()
    for opis in c:
        lista_opisa_rata.append(opis[0])
    kolona = 0
    red = 0
    for opis in lista_opisa_rata:
        rata_button = Button(self.onr_top, text=opis, width=10)
        rata_button.grid(row=red, column=kolona, pady=5, padx=5)
        kolona += 1
        if kolona == 3:
            red += 1
            kolona = 0

    w = self.onr_top.winfo_width()
    h = self.onr_top.winfo_height()
    x = self.master.winfo_x()
    y = self.master.winfo_y()
    print(w, h)
    self.onr_top.geometry("%dx%d+%d+%d" % (w, h, x, y))


 root = Tk()
 my_gui = FinancialCalc(root)
 root.mainloop()

【问题讨论】:

  • 你试过使用self.master.winfo_rootx()self.master.winfo_rooty()吗?此外,您不需要 %dx%d 内的 "%dx%d+%d+%d"
  • @TheLizzard 嘿伙计,坐标和定位都很好,没有问题,但是 TopLevel 窗口的高度和宽度有问题。不知何故,两者都是 200,200,但我没有设置几何参数
  • 只需使用self.onr_top.geometry(f"+{x}+{y}")。您无需在每次调用.geometry 时指定宽度/高度。如果它有效,我会写一个解释为什么你的方法不起作用。
  • @TheLizzard 天哪,伙计!那有什么问题?

标签: python-3.x tkinter


【解决方案1】:

在您的代码中,您在窗口中创建新小部件后调用了.winfo_width()。这会发送事件以展开窗口,但直到 tkinter 有时间更新后才会显示。

在您的代码中,您可以在 self.onr_top.winfo_width() 之前添加 self.onr_top.update(),它可能会起作用。

另一种解决方案是使用winfo_reqwidth() 而不是winfo_width()

但最简单的解决方案是使用:

self.onr_top.geometry(f"+{x}+{y}")

使用.geometry 时,您可以指定widthxheightwidthxheight+x+y 或仅指定+x+y

【讨论】:

  • docs 会建议使用 .update_idletasks() 如果有人这样做而不是 .update()
  • 感谢伙伴的解释,您只是节省了我尝试修复它的时间,就像我在决定在这里提问之前所做的那样:P。救生员!
  • @Matiiss 这也可行,但.update() 会造成.update_idletasks() 不会造成的麻烦的情况很少见。
  • @TheLizzard 有趣的是在docs 中据说.update() 可能会导致一些意外的循环(我从未经历过),但还有一些其他文章关于为什么使用.update() 不好, .update_idletasks 不过略有不同,它不会更新所有内容,因此风险较小?
  • @Matiiss .update 的唯一问题是,如果您从函数调用 .update,它可以发送偶数并触发相同的函数(如果它已绑定)。大多数时候都很好,但有时(比如在我的代码中),代码会操纵敏感变量,您可能不会期望它们会改变。
猜你喜欢
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 2021-05-12
  • 2017-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
相关资源
最近更新 更多