2009-04-08 6 views
6

मेरे पास मेन्यूबटन है, जिसे क्लिक करने पर स्ट्रिंग के विशिष्ट अनुक्रम वाले मेनू को प्रदर्शित करना चाहिए। वास्तव में उस अनुक्रम में कौन से तार हैं, हम रनटाइम तक नहीं जानते हैं, इसलिए पॉप अप करने वाले मेनू को उस पल में उत्पन्न किया जाना चाहिए। यहाँ मैं क्या है:गतिशील रूप से Tkinter में एक मेनू बनाते हैं। (लैम्ब्डा एक्सप्रेशन?)

class para_frame(Frame): 
    def __init__(self, para=None, *args, **kwargs): 
     # ... 

     # menu button for adding tags that already exist in other para's 
     self.add_tag_mb = Menubutton(self, text='Add tags...') 

     # this menu needs to re-create itself every time it's clicked 
     self.add_tag_menu = Menu(self.add_tag_mb, 
           tearoff=0, 
           postcommand = self.build_add_tag_menu) 

     self.add_tag_mb['menu'] = self.add_tag_menu 

    # ... 

    def build_add_tag_menu(self): 
     self.add_tag_menu.delete(0, END) # clear whatever was in the menu before 

     all_tags = self.get_article().all_tags() 
     # we don't want the menu to include tags that already in this para 
     menu_tags = [tag for tag in all_tags if tag not in self.para.tags] 

     if menu_tags: 
      for tag in menu_tags: 
       def new_command(): 
        self.add_tag(tag) 

       self.add_tag_menu.add_command(label = tag, 
               command = new_command) 
     else: 
      self.add_tag_menu.add_command(label = "<No tags>") 

महत्वपूर्ण हिस्सा तहत सामान है "अगर menu_tags:" - मान लीजिए menu_tags सूची है [ 'ढेर', 'अधिक', 'प्रवाह']। तो फिर मैं क्या करना चाहते हैं प्रभावी रूप से यह है:

def add_tag_stack(): 
    self.add_tag('stack') 

और इतने पर:

self.add_tag_menu.add_command(label = 'stack', command = add_tag_stack) 
self.add_tag_menu.add_command(label = 'over', command = add_tag_over) 
self.add_tag_menu.add_command(label = 'flow', command = add_tag_flow) 

जहां add_tag_stack() के रूप में परिभाषित किया गया है।

समस्या, चर 'टैग' 'टैग मान' ढेर 'पर ले जाता है और फिर मूल्य' पर 'और इतने पर, और जब तक का मूल्यांकन नहीं हो new_command कहा जाता है, जिस पर चर बात है 'बस' प्रवाह 'है। तो जोड़ा गया टैग हमेशा मेनू पर आखिरी वाला होता है, इससे कोई फर्क नहीं पड़ता कि उपयोगकर्ता क्या क्लिक करता है।

मैं मूल रूप से लैम्ब्डा का उपयोग कर रहा था, और मैंने सोचा था कि उपरोक्त कार्य को स्पष्ट रूप से परिभाषित करना शायद बेहतर काम कर सकता है। किसी भी तरह से समस्या होती है। मैंने चर 'टैग' की प्रतिलिपि (या तो "current_tag = टैग" या प्रतिलिपि मॉड्यूल का उपयोग करके) की कोशिश की है, लेकिन यह इसे हल नहीं करता है। मुझे यकीन नहीं है क्यों।

मेरा दिमाग "eval" जैसी चीज़ों के प्रति घूमना शुरू कर रहा है, लेकिन मुझे आशा है कि कोई व्यक्ति एक चालाक तरीके से सोच सकता है जिसमें ऐसी भयानक चीजें शामिल नहीं हैं।

बहुत धन्यवाद!

(मामले में यह प्रासंगिक है, Tkinter .__ version__ रिटर्न '$ संशोधन: 67,083 $' और Windows XP पर अजगर 2.6.1 का उपयोग कर रहा हूँ।)

उत्तर

6

सबसे पहले, आपकी समस्या Tkinter से कोई लेना देना नहीं है, यह सबसे अच्छा है यदि आप इसे अपनी समस्या का प्रदर्शन करने वाले कोड के एक साधारण टुकड़े को कम करते हैं, तो आप इसके साथ अधिक आसानी से प्रयोग कर सकते हैं। यहां आप जो कर रहे हैं उसका सरलीकृत संस्करण यहां मैंने प्रयोग किया है। मैं छोटे परीक्षण मामले को लिखना आसान बनाने के लिए, मेनू के स्थान पर एक निर्देश को प्रतिस्थापित कर रहा हूं।

items = ["stack", "over", "flow"] 
map = { } 

for item in items: 
    def new_command(): 
     print(item) 

    map[item] = new_command 

map["stack"]() 
map["over"]() 
map["flow"]() 

अब, जब हम इस पर अमल, जैसा कि आप ने कहा, हम पाते हैं:

flow 
flow 
flow 

यहां मुद्दा यह है दायरे से अजगर की धारणा है। विशेष रूप से, for कथन एक नए स्तर का दायरा पेश नहीं करता है, न ही item के लिए एक नया बाध्यकारी; इसलिए यह लूप के माध्यम से प्रत्येक बार item चर अद्यतन कर रहा है, और new_command() फ़ंक्शंस सभी एक ही आइटम का जिक्र कर रहे हैं।

आपको item एस के प्रत्येक के लिए एक नया बाध्यकारी के साथ, एक नया स्तर का दायरा पेश करना है।

stack 
over 
flow 
+0

ठीक है मैंने सोचा कि शायद टिंकर-विशिष्ट समाधान हो सकता है। कोई कह रहा है "नहीं, नहीं, जिस तरह से आप यह करते हैं वह विशेष कार्य है Tkinter.somethingOrOther()" मदद के लिए धन्यवाद! – MatrixFrog

+0

कोई समस्या नहीं! मैं बस यह इंगित करना चाहता था कि समस्या का एक छोटा सा उदाहरण अलग करने का प्रयास करना एक अच्छा पहला कदम है, यह देखने के लिए कि यह एक भाषा मुद्दा है या एक एपीआई मुद्दा है। –

2

बात इस तरह का Tkinter में काफी एक आम समस्या है , मुझे लगता है।

(उचित बिंदु पर) इस प्रयास करें:

def new_command(tag=tag): 
    self.add_tag(tag) 
+0

मुझे नहीं पता कि यह क्यों काम करता है, लेकिन यह करता है! हालांकि मुझे दूसरे उत्तर की विस्तृत व्याख्या पसंद है, लेकिन मैं इसका उपयोग करूंगा क्योंकि यह थोड़ा छोटा है। धन्यवाद! – MatrixFrog

+0

मुझे लगता है कि यह फ़ंक्शन तर्क सूची में टैग = टैग डिफ़ॉल्ट तर्क के कारण काम करता है। ऐसा करने से फ़ंक्शन स्कोप में नाम 'टैग' होता है, जो आवेदक के दायरे में मूल्य टैग को इंगित करता है। अगर मैं गलत हूं तो कृपया मुझे सही करें, मैं वर्तमान में इसी तरह के स्कॉइंग प्रश्नों से जूझ रहा हूं। –

+0

मूल रूप से, 'x में .. ..' निर्माण पाइथन में कुछ स्थानों में से एक है जहां एक नाम (x) रिबाउंड होता है। इसलिए आपको एक नया नाम बनाना होगा जिसमें उचित बिंदु पर एक्स के समान मूल्य हो। आप इसे 'टैग = टैग' के साथ करते हैं जिसका फ़ंक्शन परिभाषा पर मूल्यांकन किया जाता है, और बाद में फ़ंक्शन निष्पादन पर नहीं। –

0

मैं एक था: यदि आप पूर्ववर्ती कार्यक्रम में स्थानापन्न, आप इच्छित परिणाम प्राप्त

for item in items: 
    def item_command(name): 
     def new_command(): 
      print(name) 
     return new_command 

    map[item] = item_command(item) 

अब,: ऐसा करने के लिए सबसे आसान तरीका है एक नया कार्य परिभाषा में लपेट के लिए है समान त्रुटि सूची में केवल अंतिम आइटम दिखाया गया था। lambda के बाद x=i की स्थापना

command=lambda x=i: f(x)

नोट द्वारा ठीक किया गया। यह असाइनमेंट आपके स्थानीय चर i को आपके command के f(x) फ़ंक्शन में सही बनाता है। उम्मीद है, यह सरल उदाहरण मदद करेगा:

# Using lambda keyword to create a dynamic menu. 
import tkinter as tk 

def f(x): 
    print(x) 

root = tk.Tk() 
menubar = tk.Menu(root) 
root.configure(menu=menubar) 
menu = tk.Menu(menubar, tearoff=False) 
l = ['one', 'two', 'three'] 
for i in l: 
    menu.add_command(label=i, command=lambda x=i: f(x)) 
menubar.add_cascade(label='File', menu=menu) 
root.mainloop() 
संबंधित मुद्दे