2012-04-06 104 views
4

我在星期一開始使用Python進行編程。我很喜歡學習它。但我堅持試圖瞭解如何在tkinter菜單之間切換時避免遞歸!我相信這是一個非常基本的問題,我感謝你們對這個問題的無知,但我一直無法在其他地方找到答案。Tkinter - RuntimeError:超過最大遞歸深度

我現在做什麼,最終,給我的錯誤:RuntimeError:最大遞歸深度,同時調用Python對象

這是超出我目前使用的模式。更新:下面的代碼現在是一個完整的,孤立的副本,再現我面臨的問題! :D

from tkinter import * 

def mainmenu(): 
    global frame, root 

    frame.destroy() 

    frame = Frame() 
    frame.pack() 

    button1 = Button(frame, text="anothermenulikethis", command = anothermenulikethis) 
    button2 = Button(frame, text="anothermenulikethis", command = anothermenulikethis) 
    button3 = Button(frame, text="mainmenu", command = mainmenu) 

    button1.pack(side=LEFT) 
    button2.pack(side=LEFT) 
    button3.pack(side=LEFT) 

    root.mainloop() 

def anothermenulikethis(): 
    global frame, root 

    frame.destroy() 

    frame = Frame() 
    frame.pack() 

    button1 = Button(frame, text="mainmenu", command = mainmenu) 
    button2 = Button(frame, text="mainmenu", command = mainmenu) 
    button3 = Button(frame, text="anothermenulikethis", command = anothermenulikethis) 

    button1.pack(side=LEFT) 
    button2.pack(side=LEFT) 
    button3.pack(side=LEFT) 

    root.mainloop() 

root = Tk() 
root.title("Recursive Menu Problem Isolation") 
root.geometry("1200x600") 
frame = Frame() 

mainmenu() 

它一切正常,直到它從最大遞歸深度的不可避免的失敗。如果任何人都可以提出一個更好的做法,或者有一個更好的做法的例子,我很想學習。 PS:我已經看過並試圖增加遞歸深度,但我覺得這是一個窮人的解決方案,以解決我的方法的根本問題。

謝謝大家。

按照要求,這裏是回溯:

Exception in Tkinter callback 
Traceback (most recent call last): 
    File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/tkinter/__init__.py", line 1399, in __call__ 
    return self.func(*args) 
    File "/Users/diligentstudent/Desktop/menutest.py", line 11, in mainmenu 
    button1 = Button(frame, text="anothermenulikethis", command = anothermenulikethis) 
    File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/tkinter/__init__.py", line 2028, in __init__ 
    Widget.__init__(self, master, 'button', cnf, kw) 
    File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/tkinter/__init__.py", line 1958, in __init__ 
    (widgetName, self._w) + extra + self._options(cnf)) 
    File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/tkinter/__init__.py", line 1043, in _options 
    v = self._register(v) 
    File "/Library/Frameworks/Python.framework/Versions/3.2/lib/python3.2/tkinter/__init__.py", line 1079, in _register 
    f = CallWrapper(func, subst, self).__call__ 
RuntimeError: maximum recursion depth exceeded 
+0

你能發佈stacktrace嗎?需要知道哪個函數導致遞歸深度異常。 – 2012-04-06 05:30:54

+0

我已根據請求發佈追蹤。 :) – 2012-04-06 05:57:05

回答

7

只有一個mainloop()是需要處理Tkinter的GUI。

雖這麼說,我覺得你只需要類結構的一個例子:

from tkinter import Tk,Button 

class Application(Tk): 

    def say_hi(self): 
     print('Hello world?!') 

    def close_app(self): 
     self.destroy() 

    def create_Widgets(self): 
     self.quitButton = Button(self, width=12, text='Quit', bg='tan', 
        command=self.close_app) 
     self.quitButton.grid(row=0, column=0, padx=8, pady=8) 

     self.helloButton = Button(self, width=12, text='Hello', 
        command=self.say_hi) 
     self.helloButton.grid(row=0, column=1, padx=8, pady=8) 

    def __init__(self): 
     Tk.__init__(self) 
     self.title('Hello world!') 
     self.create_Widgets() 

app = Application() 
app.mainloop() 

爲了避免與其他模塊可能存在的衝突,有些人喜歡進口喜歡這個
(寫明這裏的一切來自):

import tkinter as tk 

class Application(tk.Tk): 

    def __init__(self): 
     tk.Tk.__init__(self) 
     self.title('Hello world!') 

     self.quitButton = tk.Button(self, width=12, text='Quit', bg='tan', 
        command=self.close_app) 
     self.quitButton.grid(row=0, column=0, padx=8, pady=8) 

     self.helloButton = tk.Button(self, width=12, text='Hello', 
        command=self.say_hi) 
     self.helloButton.grid(row=0, column=1, padx=8, pady=8) 

    def say_hi(self): 
     print('Hello world?!') 

    def close_app(self): 
     self.destroy() 

app = Application() 
app.mainloop() 

正如你所看到的,創建控件可以很容易地在__init__

發生

我決定根據我在過去一個月裏學到的內容做出一個更實用/有教育意義的例子。雖然這樣做我有一點啓示:並非所有事情都需要一個自我。在一個班的前綴!對於tkinter類來說尤其如此,因爲您並未將其作爲主程序中的對象進行操作。大多數你需要自我。當你打算在後面的某個方法中使用某些東西時,前綴。前面的例子顯示瞭如何任何東西(如按鈕)可以接受自我。前綴,即使完全沒有必要。

有些東西這個例子顯示:

pack()grid()可以在同一個界面,只要它們不共享一個主使用。

•字體大小更改時,可以使文本小部件不展開。

•如何切換打開和關閉選定文本的粗體標記。

•如何在屏幕上真正居中GUI。(more information here)

•如何使Toplevel窗口出現在相對於主窗口的相同位置。

•有兩種方法可以防止Toplevel窗口被破壞,所以只需要創建一次。

•正確設置ctrl + a(全選)功能。

import tkinter as tk 
import tkFont 

class Application(tk.Tk): 

    def __init__(self): 
     tk.Tk.__init__(self) 
     self.title('T-Pad') 

    # Menubar 

     menubar = tk.Menu(self) 

     filemenu = tk.Menu(menubar, tearoff=0) 
     filemenu.add_command(label="Exit", command=self.close_app) 
     menubar.add_cascade(label="File", menu=filemenu) 

     formatmenu = tk.Menu(menubar, tearoff=0) 
     formatmenu.add_command(label="Font", command=self.show_sizeWin) 
     menubar.add_cascade(label="Format", menu=formatmenu) 

     self.config(menu=menubar) 

    # Bold Button 

     boldButton = tk.Button(self, width=12, text='Bold', 
           command=self.make_bold) 
     boldButton.pack() 

    # Text widget, its font and frame 

     self.defaultFont = tkFont.Font(name="defFont") 

     textFrame = tk.Frame(self, borderwidth=1, relief="sunken", 
          width=600, height=600) 

     textFrame.grid_propagate(False) # ensures a consistent GUI size 
     textFrame.pack(side="bottom", fill="both", expand=True) 


     self.mText = tk.Text(textFrame, width=48, height=24, wrap='word', 
          font="defFont") 
     self.mText.grid(row=0, column=0, sticky="nsew") 

    # Scrollbar and config 

     tScrollbar = tk.Scrollbar(textFrame, command=self.mText.yview) 
     tScrollbar.grid(row=0, column=1, sticky='nsew', pady=1) 

     self.mText.config(yscrollcommand=tScrollbar.set) 

    # Stretchable 

     textFrame.grid_rowconfigure(0, weight=1) 
     textFrame.grid_columnconfigure(0, weight=1) 

    # Bold Tag 

     self.bold_font = tkFont.Font(self.mText, self.mText.cget("font")) 
     self.bold_font.configure(weight="bold") 
     self.mText.tag_configure("bt", font=self.bold_font) 

    # Center main window 

     self.update_idletasks() 

     xp = (self.winfo_screenwidth()/2) - (self.winfo_width()/2) - 8 
     yp = (self.winfo_screenheight()/2) - (self.winfo_height()/2) - 30 
     self.geometry('{0}x{1}+{2}+{3}'.format(self.winfo_width(), self.winfo_height(), 
                       xp, yp)) 

    # Font Size Window (notice that self.sizeWin is given an alias) 

     sizeWin = self.sizeWin = tk.Toplevel(self, bd=4, relief='ridge') 

     self.sizeList = tk.Listbox(sizeWin, width=10, height=17, bd=4, 
           font=("Times", "16"), relief='sunken') 

     self.sizeList.grid() 

     doneButton = tk.Button(sizeWin, text='Done', command=sizeWin.withdraw) 
     doneButton.grid() 

     for num in range(8,25): 
      self.sizeList.insert('end', num) 

     sizeWin.withdraw() 

     sizeWin.overrideredirect(True) # No outerframe! 
     # Below is another way to prevent a TopLevel window from being destroyed. 
     # sizeWin.protocol("WM_DELETE_WINDOW", self.callback) 

    # Bindings 
     # Double click a font size in the Listbox 
     self.sizeList.bind("<Double-Button-1>", self.choose_size) 
     self.bind_class("Text", "<Control-a>", self.select_all) 

## def callback(self): 
##  self.sizeWin.withdraw() 

    def select_all(self, event): 
     self.mText.tag_add("sel","1.0","end-1c") 

    def choose_size(self, event=None): 
     size_retrieved = self.sizeList.get('active') 
     self.defaultFont.configure(size=size_retrieved) 
     self.bold_font.configure(size=size_retrieved) 

    def show_sizeWin(self): 
     self.sizeWin.deiconify() 
     xpos = self.winfo_rootx() - self.sizeWin.winfo_width() - 8 
     ypos = self.winfo_rooty() 
     self.sizeWin.geometry('{0}x{1}+{2}+{3}'.format(self.sizeWin.winfo_width(), 
               self.sizeWin.winfo_height(), xpos, ypos)) 

    def make_bold(self): 
     try: 
      current_tags = self.mText.tag_names("sel.first") 
      if "bt" in current_tags: 
       self.mText.tag_remove("bt", "sel.first", "sel.last") 
      else: 
       self.mText.tag_add("bt", "sel.first", "sel.last") 
     except tk.TclError: 
      pass 

    def close_app(self): 
     self.destroy() 

app = Application() 
app.mainloop() 
+0

Ohhhhhh!是的,這正是我尋找的模式!非常感謝! :D – 2012-04-06 06:17:06

+0

@ADiligentStudent我的榮幸!我添加了一個稍微修改的版本。 – 2012-04-06 06:34:45

+0

@ADiligentStudent我再次更新。這次有一個實際的例子,包括你想要製作的Toplevel(二級)窗口。 – 2012-04-07 06:41:58

相關問題