2013-09-06 3 views
0

아래 코드에서 입력 widget이 비어 있고 Submit 버튼을 누른 경우에 self.e2 entry widget에 입력 된 데이터의 유효성을 부분적으로 검증했습니다. ValueError가 생성되었습니다. "ValueError : 밑이 10 인 int()에 대한 리터럴이 올바르지 않습니다." ValueError가 트랩 된 후 엔트리 위젯으로 포커스를 되돌려 주도록 프로그램에 인식시키고 싶습니다.빈 Entry Widget에서 생성 된 ValueError를 tkinter에서 생성하는 방법

is_valid_int 및 invalid_int 메소드를 사용하여이 작업을 시도했지만 작동하지 않습니다.

from tkinter import * 
from tkinter import ttk 
from tkinter.scrolledtext import * 

class DailyOrderGUI: 
    def __init__(self, parent): 
     #Data entring frame 
     self.frame = Frame(parent, bg = "grey") 
     self.frame.grid(row=0) 
     self.label1 = Label(self.frame, text = "Mrs CackleBerry's Egg Ordering System", wraplength = 200, bg="grey", font=("Comic Sans MS", "14", "bold")) 
     self.label1.grid(row = 0, columnspan = 3, padx = 5, pady = 5) 
     self.superegg_img = PhotoImage(file = "images/superegg.gif") 
     self.label5 = Label(self.frame, bg="grey", image = self.superegg_img) 
     self.label5.grid(row = 0, column= 3, padx = 5, pady = 5) 
     self.v = StringVar() 
     self.v.set("Monday") 
     self.label2 = Label(self.frame, text = "Which day are you ordering for?", bg="grey", font=("Arial", "12", "bold")) 
     self.label2.grid(row = 1, columnspan = 4, sticky = W) 
     self.rb1 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Monday", text = "Monday") 
     self.rb1.grid(row = 2, column = 0, sticky = W) 
     self.rb2 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Tuesday", text = "Tuesday") 
     self.rb2.grid(row = 2, column = 1, sticky = W) 
     self.rb3 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Wednesday", text = "Wednesday") 
     self.rb3.grid(row = 2, column = 2, sticky = W) 
     self.rb4 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Thursday", text = "Thursday") 
     self.rb4.grid(row = 2, column = 3, sticky = W) 
     self.rb5 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Friday", text = "Friday") 
     self.rb5.grid(row = 3, column = 0, sticky = W) 
     self.rb6 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Saturday", text = "Saturday") 
     self.rb6.grid(row = 3, column = 1, sticky = W) 
     self.rb7 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Sunday", text = "Sunday") 
     self.rb7.grid(row = 3, column = 2, sticky = W) 
     self.label3 = Label(self.frame, text = "Customer's Name:?(Press \"Orders Complete\" to finish)", bg="grey", font=("Arial", "12", "bold")) 
     self.label3.grid(row = 4, columnspan = 4,padx = 5, sticky = W) 
     self.e1 = Entry(self.frame, width = 30) 
     self.e1.grid(row = 5, columnspan = 4, sticky = W, padx = 5, pady=3) 
     self.e1.focus() 
     self.label4 = Label(self.frame, text = "How many eggs being ordered:?", bg="grey", font=("Arial", "12", "bold")) 
     self.label4.grid(row = 6, columnspan = 4,padx = 5,sticky = W) 

     integer = self.create_integer_widget() 

     self.btn1 = Button(self.frame, text = "Submit") 
     self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W) 
     self.btn1.bind("<Button-1>", self.get_orders) 
     self.btn2 = Button(self.frame, text = "Orders Complete", command = self.show_summary_result) 
     self.btn2.grid(row = 8, column = 3, padx = 5, pady = 3, sticky = E+W) 

     #Summary Frame 
     self.summ_frame = Frame(parent, bg = "grey") 
     self.summ_frame.grid(row=0) 
     self.summ_label1 = Label(self.summ_frame, text = "Mrs CackleBerry's Egg Ordering System", bg="grey", font=("Comic Sans MS", "14", "bold")) 
     self.summ_label1.grid(row = 0, columnspan = 4, padx = 5, pady = 5) 
     self.scrolled_display = ScrolledText(self.summ_frame, width = 50, height = 10, bg="thistle", font=("Times New Roman", "12")) 
     self.scrolled_display.grid(row = 1, columnspan = 2, padx = 5, pady = 20, sticky = W) 
     self.data_entry_btn = Button(self.summ_frame, text = "Back to Data Entry", command = self.show_data_entry_frame) 
     self.data_entry_btn.grid(row = 2, column = 0, sticky = SE, padx = 5, pady = 20) 

     self.egg_orders=[] 

     self.show_data_entry_frame() 

    def create_integer_widget(self): 
     self.e2 = ttk.Entry(self.frame, width = 10, validate='key') 
     self.e2['validatecommand'] = (self.frame.register(self.is_valid_int), '%P') 
     self.e2['invalidcommand'] = (self.frame.register(self.invalid_int), '%W') 
     self.e2.grid(row = 7, columnspan = 4, sticky = W, padx = 5, pady=3) 
     self.e2.bind("<Return>", self.get_orders) 
     return self.e2 

    def is_valid_int(self, txt): 
     # txt - value in %P 
     if not txt:   # do not accept empty string 
      return False 

     try: 
      int(txt) 
      return True  # accept integer 

     except ValueError: # not an integer 
      return False 

    def invalid_int(self, widgetName): 
     # called automatically when the 
     # validation command returns 'False' 

     # get entry widget 

     widget = self.frame.nametowidget(widgetName) 

     # clear entry 
     widget.delete(0, END) 

     # return focus to integer entry 
     widget.focus_set() 
     widget.bell() 

    def show_data_entry_frame(self): 
     self.summ_frame.grid_remove() 
     self.frame.grid() 
     root.update_idletasks() 

    def show_summary_result(self): 
     self.frame.grid_remove() 
     self.summ_frame.grid() 
     root.update_idletasks() 
     self.scrolled_display.delete('1.0', END) 
     if len(self.egg_orders) == 0: 
      self.scrolled_display.insert(END, "No Orders") 
     else: 
      total = 0 
      self.scrolled_display.insert(END, "Orders for " + self.v.get() + "\n") 
      for i in range(len(self.egg_orders)): 
       total += self.egg_orders[i].num_eggs 
       self.scrolled_display.insert(END, str(self.egg_orders[i]) + "\n") 
      self.scrolled_display.insert(END, "" + "\n") 
      self.scrolled_display.insert(END, "Summary for " + self.v.get() + "\n") 
      self.scrolled_display.insert(END, "" + "\n") 
      self.scrolled_display.insert(END, "Total eggs: " + str(total) + "\n") 
      self.scrolled_display.insert(END, "Dozens required: " + str(self.get_dozens(total)) + "\n") 
      average = 0 
      if len(self.egg_orders) > 0: 
       average = total/len(self.egg_orders) 
      self.scrolled_display.insert(END, "Average number of eggs per customer: {0:.1f}".format(average) + "\n") 

    def get_orders(self, event): 
     """ 
     Collects order information - name, number of eggs in a loop 
     """ 
     self.name = self.e1.get() 
     self.no_eggs = self.e2.get() 
     self.e1.delete(0, END) 
     self.e2.delete(0, END) 
     self.e1.focus() 
     self.egg_orders.append(EggOrder(self.name, self.no_eggs)) 

    def get_dozens (self, total): 
     """ 
     returns whole number of dozens required to meet required number of eggs 
     """ 
     num_dozens = total//12 
     if total%12 != 0: 
      num_dozens += 1 
     return num_dozens 

class EggOrder: 

    price_per_doz = 6.5 
    def __init__(self, name, num_eggs): 
     self.name = name 
     self.num_eggs = int(num_eggs) 


    def calc_price(self): 
     self.price = EggOrder.price_per_doz/12 * self.num_eggs 
     return self.price 

    def __str__(self): 
     return("{} ordered {} eggs. The price is ${:.2f}".format(self.name, self.num_eggs , self.calc_price())) 



#main routine 
if __name__== "__main__": 
    root = Tk() 
    root.title("Mrs Cackleberry's Egg Ordering Program") 
    frames = DailyOrderGUI(root) 
    root.mainloop() 
+1

거기에'try/except'가 표시되지 않습니다. 보통이 종류의 오류를 처리하는 데 사용됩니다. 당신이 그것을 사용하지 않는 이유가 있습니까? – kindall

+1

또한 오류를 설명하지 마십시오. 실제 추적을 게시하십시오. 서면으로, 우리는 당신이 그 오류를 얻을 수 있습니다 짐작하기 위해 코드의 전체 무리를 발굴해야합니다. – abarnert

+0

또한, 관련 코드가 없으며 GIF 파일에 대한 외부 종속성이없는 삭제 된 버전 인 [SSCCE] (http://sscce.org)를 주면 코드를 디버그하는 것이 훨씬 쉽습니다 등 – abarnert

답변

2

"제출"을 클릭하면 어떻게되는지 추적 해 봅시다.

첫째 :

self.btn1 = Button(self.frame, text = "Submit") 
self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W) 
self.btn1.bind("<Button-1>", self.get_orders) 

그래서, self.get_orders를 호출합니다.

self.no_eggs = self.e2.get() 
# ... 
self.egg_orders.append(EggOrder(self.name, self.no_eggs)) 

그리고 EggOrder.__init__ 함수 내에서 당신이있어 : 그리고 그 함수의 마지막 줄은

오류가 발생하는 경우 아마도입니다
self.num_eggs = int(num_eggs) 

. self.e2.get()는 빈 문자열을 반환 할 때

(당신이 대신 오류 문자열의 역 추적을 게시 더라면 그 모든 작업이 필요했을 것이다 있습니다.) 그래서


을, 당신은 전화 끝 int('')이고 그 값은 ValueError입니다.

사전에 가능성을 확인하려고하지 않는 한 (거의 좋은 아이디어는 아닙니다) try:/except ValueError: 어딘가에 있어야합니다. 문제는 어디에 있습니까? 네가하고 싶은 일에 달렸어. 당신이 빈 EggOrder을 만들려면

, 당신은 EggOrder.__init__ 내부에 그것을 할 것 :

try: 
    self.num_eggs = int(num_eggs) 
except ValueError: 
    self.num_eggs = 0 

을 다른 한편으로는, 당신이 전혀 EggOrder을 만들려면, 당신은 내부에 그것을 할 것 self.get_orders :

try: 
    order = EggOrder(self.name, self.no_eggs) 
except ValueError: 
    # pop up an error message, log something, call self.invalid_int, whatever 
else: 
    self.egg_orders.append(order) 
물론

당신은 아마 전에이 을 수행 할 파괴적인 것들 (, 등). 당신이 invalid_int 전화를 원한다면


또한,있는 그대로, 당신은 그것에게 self.e2 위젯의 이름을 전달해야 할 것입니다. 당신이 그것을주지 않았기 때문에, 위젯에 대해 물어봐야 할 .1234567890과 같이 동적이고 예측 불가능한 것이 될 것입니다. 그래서 위젯을 그 이름으로 다시 볼 수 있습니다.

def invalid_int(self, widgetName): 
    widget = self.frame.nametowidget(widgetName) 
    self.handle_invalid_int(widget) 
def handle_invalid_int(self, widget): 
    widget.delete(0, END) 
    # etc. 

그럼 당신은 그냥 handle_invalid_int(self.e2)를 호출 할 수 있습니다 :이 같은 핵심 기능, 뭔가를 고려하는 것이 더 간단 할 것이다.


한편 올바른 유효성 입력을 확인하기 위해 유효성 검사 기능을 추가하려고 시도했습니다.

is_valid_int은 정상적으로 작동합니다. 그러나 if not txt 부분은 완전히 불필요합니다. int(txt)은 숫자가 아닌 문자열을 처리하는 것과 같은 방식으로 이미 빈 문자열을 처리합니다.

그리고 당신이 그것을 구부리는 방식도 효과가 있습니다.

그러나 다른 임의의 위젯을 다른 곳에서 클릭 할 때가 아니라 유효성 검사 기능이 항목 위젯에 대한 각 편집시 실행됩니다. 예를 들어, 항목에 문자를 입력하려고하면 입력 할 수있는대로 문자가 지워집니다.

그래서, 당신이 그 권리를 완료했습니다 (... 당신이 123a456를 입력하면 당신이 또는 당신이 원하는하지 않을 수있다, 456하지 123456하게 될 겁니다 참고), 그러나 당신이하고 싶었던 게 아니에요 .

관련 문제