Python/tkinter:按对话框中的确定会破坏其中的信息

发布于 2025-02-11 08:36:31 字数 2102 浏览 4 评论 0原文

我正在使用Python/tkinter进行GUI,我发现了一种奇怪的行为。

我正在构建一个非常小的对话框,以选择我的应用程序的语言。然后,关闭它时,我发现对话框中的“结果”变量已经消失。

这是片段:

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

class LanguageDialog(Dialog):
    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.selected_language = tk.StringVar()
        self.result = 'en'  # default value

    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])
        self.result = self.lang_dict[self.selected_language.get()]

    def body(self, master):
        self.selected_language = tk.StringVar()
        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    root.mainloop()

我相信我对如何使用对话框有一些误解。在调试时,我看到了对话框触发了一些destrot()方法,但是似乎它可能再次出现到初始化器并执行该

self.result = 'en'

行,即使我没有通过languateialog()再次创建或调用对话框。

我在网络上搜索了类似的示例,发现他们正在以相同的方式使用对话框,例如在这里

I'm using Python/tkinter for a GUI and I found a strange behaviour.

I'm building a very small dialog for selecting the language for my app. Then when closing it, I find that my 'result' variable in the dialog is gone.

Here's the snippet:

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

class LanguageDialog(Dialog):
    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.selected_language = tk.StringVar()
        self.result = 'en'  # default value

    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])
        self.result = self.lang_dict[self.selected_language.get()]

    def body(self, master):
        self.selected_language = tk.StringVar()
        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    root.mainloop()

I believe I have some misconception on how to use the dialog. While debugging I saw the dialog triggers some destroy() method, but it seems like it is probably coming again to the initializer and executing the

self.result = 'en'

line, even though I didn't create or invoke the dialog again through LanguageDialog().

I searched the web for similar examples and found that they are using the dialog in the same way, for example, here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

坏尐絯 2025-02-18 08:36:31

如果您查看simpledialog.dialog类的源代码,您会发现wait_window()是在对话框的末尾执行的。代码>试图像模态对话框一样制作窗口。

SO super().__ init __(...)内部lankingialog .__ Int __()在关闭对话框之前不会返回。关闭对话框时,self.result将重置为'en'。

您应该将行移动,self.result ='en''''body()的开头(就像self.selected_language),然后删除__ INIT __()函数。

以下是修改的代码:

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

class LanguageDialog(Dialog):
    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }

    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])
        self.result = self.lang_dict[self.selected_language.get()]

    def body(self, master):
        self.selected_language = tk.StringVar()
        # initial self.result to 'en' here
        self.result = 'en'  # default value

        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    root.withdraw() # hide the root window
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    #root.mainloop() # don't need to call mainloop()

If you look into the source code of simpledialog.Dialog class, you will find that wait_window() is executed at the end of Dialog.__init__() which tries to make the window like a modal dialog.

So super().__init__(...) inside LanguageDialog.__init__() will not return until the dialog is closed. When the dialog is closed, self.result is reset to 'en'.

You should move the line, self.result = 'en' into the beginning of body() (just like self.selected_language) and then remove the __init__() function.

Below is the modified code:

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

class LanguageDialog(Dialog):
    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }

    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])
        self.result = self.lang_dict[self.selected_language.get()]

    def body(self, master):
        self.selected_language = tk.StringVar()
        # initial self.result to 'en' here
        self.result = 'en'  # default value

        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    root.withdraw() # hide the root window
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    #root.mainloop() # don't need to call mainloop()
美羊羊 2025-02-18 08:36:31

我用一个全局变量解决了它不是最好的方法,但这就是我现在可以提出的,下面的代码。希望可以帮助您。

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

value_global = 'en'

class LanguageDialog(Dialog):

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.selected_language = tk.StringVar()
        self.result = value_global  # default value

    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }



    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])

        self.result = self.lang_dict[self.selected_language.get()]
        global value_global
        value_global= self.result


    def body(self, master):
        self.selected_language = tk.StringVar()
        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    root.mainloop()

I solved it with a global variable not the best way but that's what I could come up now, the code below.Hope it helps you.

import tkinter as tk
from tkinter.simpledialog import Dialog
from tkinter import ttk, LEFT, ACTIVE
from tkinter.ttk import Button, Frame

value_global = 'en'

class LanguageDialog(Dialog):

    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.selected_language = tk.StringVar()
        self.result = value_global  # default value

    lang_dict = {
        'italiano': 'it',
        'español': 'es',
        'english': 'en',
        'galego': 'gl',
    }



    def _on_cmb_change(self, event):
        """
            Keeps updated the result variable with the code I want in the end
        """
        print(self.lang_dict[self.selected_language.get()])

        self.result = self.lang_dict[self.selected_language.get()]
        global value_global
        value_global= self.result


    def body(self, master):
        self.selected_language = tk.StringVar()
        ops = tuple(self.lang_dict.keys())
        cmb_lang = ttk.Combobox(self, values=ops, state='readonly',
                                textvariable=self.selected_language)
        cmb_lang.pack(side=tk.TOP)

        cmb_lang.bind('<<ComboboxSelected>>', self._on_cmb_change)

    def buttonbox(self):
        """add standard button box.

        override if you do not want the standard buttons
        """

        box = Frame(self)

        w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
        w.pack(side=LEFT, padx=5, pady=5)

        self.bind("<Return>", self.ok)

        box.pack()

if __name__ == '__main__':
    root = tk.Tk()
    d = LanguageDialog(root)
    print(f'After the dialog, {d.result}')
    root.mainloop()
尐籹人 2025-02-18 08:36:31

我也有类似的问题,您不需要制作全局变量。这就是我解决这个问题的方式,我在制作本地属性之后称之为超级,例如,您可以使用一个助手方法,该方法获取所有不应该是simpledialog.dialog class的参数。

在帮手内部,您将这些参数分配给类属性,例如 init 方法的左右按钮的文本

def helper(self, b_left, b_right, message):
   self.mes = message
   self.b_left = b_left
   self.b_right = b_right

方法,请确保您调用self.helper(带有args)在调用super()。 init ()之前,

class MyDialog(simpledialog.Dialog):
  def __init__(self, master, b_left, b_right, message):
    self.helper(b_left, b_right, message) # call it before super! important
    super().__init__(parent=master)

  def helper(self, b_left, b_right, message):
    self.mes = message
    self.b_left = b_left
    self.b_right = b_right

  def body(self, master):
    # do your changes

  def buttonbox(self):
    # do your changes

在制作班级本地属性后,请致电超级。如果您不这样的类,则将从simpledialog.dialog类属性接触并引起错误。

I had a similar problem you do not need to make a global variable. This is how I solved this I called the super after I made my local attributes for example you can have a helper method which takes all the arguments which are not supposed to be part of simpledialog.Dialog class.

Inside the helper you assign those arguments to they class attributes like the text for the button on left and right

def helper(self, b_left, b_right, message):
   self.mes = message
   self.b_left = b_left
   self.b_right = b_right

Inside the init method make sure you call the self.helper(with the args) before you call the super().init()

class MyDialog(simpledialog.Dialog):
  def __init__(self, master, b_left, b_right, message):
    self.helper(b_left, b_right, message) # call it before super! important
    super().__init__(parent=master)

  def helper(self, b_left, b_right, message):
    self.mes = message
    self.b_left = b_left
    self.b_right = b_right

  def body(self, master):
    # do your changes

  def buttonbox(self):
    # do your changes

It is very important that you call the super after you make your local attributes for the class. If you don't the class you are inheriting from simpledialog.Dialog class attribute's will interfare and cause errors.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文