【问题标题】:Having multiple-page GUI in Python with several buttons在 Python 中具有多个按钮的多页 GUI
【发布时间】:2014-04-23 23:00:07
【问题描述】:

我目前正在尝试为工作中的任务实现 GUI。我找到了一些开源代码(见下文),我们在其中制作了一个有 3 个页面的 GUI,可以使用下一个/上一个按钮在页面之间切换。如果您运行代码,您将看到每个按钮等的作用。

但是,当您运行代码并单击“count++”按钮时,总计数会增加 1而不是单个页面的计数(例如,在第 1 页并单击 count++ 4次,仍然计算第 2 页或第 3 页、第 4 页,而不是零)。当我尝试更新每个页面上每个文本框中的文本(应该是点击次数)时,也会出现同样的问题,因为它不会更新。我不确定如何真正访问 每个单独页面的文本框

关于从这里去哪里有什么建议吗?从长远来看,我希望有一个向下滚动的菜单,其中的选择将被放在每个单独的文本框架上。

谢谢,

import ttk
from Tkinter import *
import tkMessageBox

class Wizard(object, ttk.Notebook):
    def __init__(self, master=None, **kw):
        npages = kw.pop('npages', 3)
        kw['style'] = 'Wizard.TNotebook'
        ttk.Style(master).layout('Wizard.TNotebook.Tab', '')
        ttk.Notebook.__init__(self, master, **kw)

        self._children = {}

        self.click_count = 0
        self.txt_var = "Default"

        for page in range(npages):
            self.add_empty_page()

        self.current = 0
        self._wizard_buttons()

    def _wizard_buttons(self):
        """Place wizard buttons in the pages."""
        for indx, child in self._children.iteritems():
            btnframe = ttk.Frame(child)
            btnframe.pack(side='left', fill='x', padx=6, pady=4)

            txtframe = ttk.Frame(child)
            txtframe.pack(side='right', fill='x', padx=6, pady=4)

            nextbtn = ttk.Button(btnframe, text="Next", command=self.next_page)
            nextbtn.pack(side='top', padx=6)

            countbtn = ttk.Button(txtframe, text="Count++..", command=self.update_click) 
            countbtn.grid(column=0,row=0)

            txtBox = Text(txtframe,width = 50, height = 20, wrap = WORD)            
            txtBox.grid(column=1,row=0)
            txtBox.insert(0.0, self.txt_var)

            rstbtn = ttk.Button(btnframe, text="Reset count!", command=self.reset_count)
            rstbtn.pack(side='top', padx=6)

            if indx != 0:
                prevbtn = ttk.Button(btnframe, text="Previous",
                    command=self.prev_page)
                prevbtn.pack(side='right', anchor='e', padx=6)

                if indx == len(self._children) - 1:
                    nextbtn.configure(text="Finish", command=self.close)

    def next_page(self):
        self.current += 1

    def prev_page(self):
        self.current -= 1

    def close(self):
        self.master.destroy()

    def add_empty_page(self):
        child = ttk.Frame(self)
        self._children[len(self._children)] = child
        self.add(child)

    def add_page_body(self, body):
        body.pack(side='top', fill='both', padx=6, pady=12)

    def page_container(self, page_num):
        if page_num in self._children:
            return self._children[page_num]
        else:
            raise KeyError("Invalid page: %s" % page_num)

    def _get_current(self):
        return self._current

    def _set_current(self, curr):
        if curr not in self._children:
            raise KeyError("Invalid page: %s" % curr)

        self._current = curr
        self.select(self._children[self._current])

    current = property(_get_current, _set_current)

    def update_click(self):
        self.click_count += 1
        message = "You have clicked %s times now!" % str(self.click_count)
        tkMessageBox.showinfo("monkeybar", message)
        self.txt_var = "Number of clicks: %s" % str(self.click_count) #this will not change the text in the textbox!

    def reset_count(self):
        message = "Count is now 0."
        #ctypes.windll.user32.MessageBoxA(0, message, "monkeybar", 1)
        tkMessageBox.showinfo("monkeybar", message)
        self.click_count = 0

def combine_funcs(*funcs):
    def combined_func(*args, **kwargs):
        for f in funcs:
            f(*args, **kwargs)
        return combined_func

def demo():
    root = Tk()

    nbrpages = 7    

    wizard = Wizard(npages=nbrpages)
    wizard.master.minsize(400, 350)
    wizard.master.title("test of GUI")
    pages = range(nbrpages)

    for p in pages:
        pages[p] = ttk.Label(wizard.page_container(p), text='Page %s'%str(p+1))
        wizard.add_page_body(pages[p])

    wizard.pack(fill='both', expand=True)
    root.mainloop()

if __name__ == "__main__":
    demo()

【问题讨论】:

  • 要以便携的方式打开对话框,您可以使用tkMessageBox。首先,import tkMessageBox,然后使用tkMessageBox.showinfo(title, message) 打开它们。这将减轻想要运行您的代码的非 Windows 贡献者。
  • 注意!感谢@FabienAndre 的评论

标签: python user-interface tkinter ttk


【解决方案1】:

您的update_click 方法对您的向导的click_count 属性进行操作。如果您想要不同的计数,您可以为您的页面创建一个类,因此每个对象将管理自己的计数,或者管理多个计数器,例如在一个列表中,就像您处理 _children 列表一样。

对于前一种情况,您可以创建一个继承 ttk.Frame 的页面类,并将 _wizard_buttons 循环的主体作为构造函数。在后一种情况下,您可以尝试这样的事情

class Wizard(object, ttk.Notebook):
    def __init__(self, master=None, **kw):
        [...]
        #replace self.click_count = 0 with
        self.click_counters = [0 for i in range(npages)]

    def update_click(self):
        self.click_counters[self.current] += 1
        # and so on...

关于文本小部件更新,您 can not handle it though a variable,它适用于 Entry(单行文本字段),但不适用于 Text(多行,富文本字段)。如果您继续使用Text,您似乎想要的通常方法是

text.delete(1.0, END)
text.insert(END, content)

【讨论】:

  • 听起来很合理,但我无法弄清楚如何实际访问每个页面(或子页面),从而为每个页面创建一个类...@FabienAndre
  • 谢谢@FabienAndre!确实是非常聪明的解决方案,模仿了 _children-list 方法。
猜你喜欢
  • 1970-01-01
  • 2018-03-09
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 2019-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多