Tkinter में एक बटन कमांड के लिए तर्क कैसे पारित करें?


175

मान लीजिए कि मेरे पास Buttonपायथन में टिंकर के साथ बनाया गया है:

import Tkinter as Tk
win = Tk.Toplevel()
frame = Tk.Frame(master=win).grid(row=1, column=1)
button = Tk.Button(master=frame, text='press', command=action)

actionजब मैं बटन दबाता हूं तो विधि को कहा जाता है, लेकिन क्या होगा यदि मैं विधि के लिए कुछ तर्क पारित करना चाहता हूं action?

मैंने निम्नलिखित कोड के साथ कोशिश की है:

button = Tk.Button(master=frame, text='press', command=action(someNumber))

यह सिर्फ विधि को तुरंत लागू करता है, और बटन दबाने से कुछ भी नहीं होता है।


4
फ्रेम = Tk.Frame (मास्टर = जीत) .grid (पंक्ति = 1, स्तंभ = 1) # Q. अब फ्रेम का मूल्य क्या है?
noob oddy

जवाबों:


265

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

यह है कि आप इसे लैम्ब्डा के साथ कैसे करेंगे (ध्यान दें कि कार्यात्मक मॉड्यूल में करीने का कुछ कार्यान्वयन भी है, इसलिए आप इसका उपयोग भी कर सकते हैं:

button = Tk.Button(master=frame, text='press', command= lambda: action(someNumber))

11
आप अभी भी आवरण विधि लिख रहे हैं, आप इसे केवल इनलाइन कर रहे हैं।
३:११

53
यह काम नहीं करता है यदि someNumber वास्तव में एक चर है जो लूप के अंदर मूल्यों को बदलता है जो कई बटन बनाता है। फिर प्रत्येक बटन अंतिम मान के साथ एक्शन () को कॉल करेगा जिसे कुछ नम्बरन को सौंपा गया है और जब बटन बनाया गया था तब उसका मूल्य नहीं था। partialइस मामले में काम करता है समाधान ।
स्क्रेच

1
यह मेरे लिए बहुत अच्छा काम किया। हालाँकि, आप यह भी बता सकते हैं कि ओपी का बयान क्यों "This just invokes the method immediately, and pressing the button does nothing"होता है?
टॉमी

17
@Scrontch मुझे आश्चर्य है कि आपके द्वारा बताए गए जाल में कितने नौसिखिए टिंकर उपयोगकर्ता कभी महसूस नहीं करते थे! किसी भी हाल में एक कर सकते हैं पर कब्जा वर्तमान मूल्य मुहावरा का उपयोग कर callback=lambda x=x: f(x)के रूप मेंfs = [lambda x=x: x*2 for x in range(5)] ; print [f() for f in fs]
gboffi

1
@Voo का क्या मतलब है "हालांकि पुराने स्कूल के अजगर लोग शायद मेमने के लिए डिफ़ॉल्ट पैरामीटर असाइनमेंट से चिपके रहेंगे"? मुझे काम करने के लिए लंबोदर नहीं मिला और इस तरह अब आंशिक रूप से उपयोग किया जाता है।
क्लेमर शुट्टे

99

यह इस तरह partialसे मानक पुस्तकालय फंक्शनल से उपयोग करके भी किया जा सकता है :

from functools import partial
#(...)
action_with_arg = partial(action, arg)
button = Tk.Button(master=frame, text='press', command=action_with_arg)

33
या इससे भी कम:button = Tk.Button(master=frame, text='press', command=partial(action, arg))
क्लेमर शुट्टे

Necro'ing के लिए खेद है, लेकिन आप दो या अधिक तर्कों के मामले में ऐसा कैसे करेंगे?
मैशपोटैटो

5
action_with_args = partial(action, arg1, arg2... argN)
बोलोगन

मैं यह तरीका अपनाता हूं क्योंकि लैंबडा मेरे लिए काम नहीं करता।
ज़ावेन जरीन

19

उदाहरण GUI:

मान लीजिए कि मेरे पास GUI है:

import tkinter as tk

root = tk.Tk()

btn = tk.Button(root, text="Press")
btn.pack()

root.mainloop()

जब एक बटन दबाया जाता है तो क्या होता है

देखें कि कब btnदबाया जाता है यह अपने स्वयं के फ़ंक्शन को कॉल करता है जो button_press_handleनिम्न उदाहरण में बहुत समान है :

def button_press_handle(callback=None):
    if callback:
        callback() # Where exactly the method assigned to btn['command'] is being callled

साथ में:

button_press_handle(btn['command'])

आप बस सोच सकते हैं कि commandविकल्प को सेट किया जाना चाहिए, जिस पद्धति को हम कॉल करना चाहते हैं, उसी के संदर्भ callbackमें button_press_handle


एक विधि ( कॉलबैक ) कॉलिंग जब बटन दबाया जाता है

बिना तर्क के

अगर printबटन दबाया जाता है तो मैं कुछ करना चाहता था तो मुझे सेट करने की आवश्यकता होगी:

btn['command'] = print # default to print is new line

पर ध्यान दें कमी के ()साथ printविधि है जो अर्थ है कि में छोड़ दिया जाता है: "यह पद्धति का नाम है जो मैं तुम्हें जब दबाया कॉल करना चाहते है लेकिन । यह सिर्फ यह बहुत ही तत्काल कॉल नहीं करते" हालाँकि, मैंने इसके लिए कोई भी तर्क पारित नहीं किया, printइसलिए जब भी इसे बिना तर्क के छापा जाता है तो इसे मुद्रित किया जाता है।

साथ मेंतर्क के

अब यदि मैं उस विधि के लिए भी तर्क देना चाहता हूं जिसे मैं चाहता हूं कि जब बटन दबाया जाए तो मैं अनाम कार्यों का उपयोग कर सकता हूं, जो लंबोदर स्टेटमेंट के साथ बनाया जा सकता है , इस मामले में printअंतर्निहित विधि के लिए, निम्न की तरह :

btn['command'] = lambda arg1="Hello", arg2=" ", arg3="World!" : print(arg1 + arg2 + arg3)

बटन दबाए जाने पर कई तरीकों को कॉल करना

बिना तर्क के

आप lambdaकथन का उपयोग करके भी इसे प्राप्त कर सकते हैं लेकिन इसे बुरा व्यवहार माना जाता है और इस प्रकार मैं इसे यहाँ शामिल नहीं करूँगा। अच्छी प्रथा एक अलग विधि को परिभाषित करने के लिए है multiple_methods, जो कि वांछित तरीकों को कॉल करती है और फिर इसे बटन प्रेस में कॉलबैक के रूप में सेट करती है:

def multiple_methods():
    print("Vicariously") # the first inner callback
    print("I") # another inner callback

तर्क के साथ

अन्य विधियों को कॉल करने के लिए तर्क (ओं) को पारित करने के लिए, फिर से lambdaकथन का उपयोग करें , लेकिन पहले:

def multiple_methods(*args, **kwargs):
    print(args[0]) # the first inner callback
    print(kwargs['opt1']) # another inner callback

और फिर सेट करें:

btn['command'] = lambda arg="live", kw="as the" : a_new_method(arg, opt1=kw)

कॉलबैक से रिटर्निंग ऑब्जेक्ट (ओं)

साथ ही आगे की टिप्पणी है कि callbackवास्तव में नहीं कर सकते हैं returnक्योंकि यह केवल अंदर कहा जाता है button_press_handleके साथ callback()के रूप में करने का विरोध किया return callback()। यह होता है returnलेकिन नहीं कहीं भी है कि समारोह के बाहर। इस प्रकार आपको वस्तु (एस) को संशोधित करना चाहिए जो वर्तमान दायरे में पहुंच योग्य हैं।


वैश्विक वस्तु संशोधन के साथ पूरा उदाहरण

नीचे दिए गए उदाहरण से btnहर बार बटन दबाए जाने पर पाठ को बदलने वाली विधि को कॉल किया जाएगा :

import tkinter as tk

i = 0
def text_mod():
    global i, btn           # btn can be omitted but not sure if should be
    txt = ("Vicariously", "I", "live", "as", "the", "whole", "world", "dies")
    btn['text'] = txt[i]    # the global object that is modified
    i = (i + 1) % len(txt)  # another global object that gets modified

root = tk.Tk()

btn = tk.Button(root, text="My Button")
btn['command'] = text_mod

btn.pack(fill='both', expand=True)

root.mainloop()

आईना


10

फ़ंक्शन तर्कों के लिए डिफ़ॉल्ट मान प्रदान करने की पायथन की क्षमता हमें एक रास्ता देती है।

def fce(x=myX, y=myY):
    myFunction(x,y)
button = Tk.Button(mainWin, text='press', command=fce)

देखें: http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/extra-args.html

अधिक बटनों के लिए आप एक फ़ंक्शन बना सकते हैं जो एक फ़ंक्शन देता है:

def fce(myX, myY):
    def wrapper(x=myX, y=myY):
        pass
        pass
        pass
        return x+y
    return wrapper

button1 = Tk.Button(mainWin, text='press 1', command=fce(1,2))
button2 = Tk.Button(mainWin, text='press 2', command=fce(3,4))
button3 = Tk.Button(mainWin, text='press 3', command=fce(9,8))

4
इससे समस्या का समाधान नहीं होता है। क्या होगा अगर आप तीन बटन बना रहे हैं जो सभी एक ही फ़ंक्शन को कॉल करते हैं, लेकिन अलग-अलग तर्क पारित करने की आवश्यकता है?
ब्रायन ओकले

आप एक फंक्शन बना सकते हैं जो एक फंक्शन लौटाता है।
मार्केन्यूज़का

मुझे पता है कि यह किसी भी अधिक सक्रिय नहीं है, लेकिन मैं stackoverflow.com/questions/35616411/… से यहां से जुड़ा हुआ हूं , यह ठीक उसी तरह काम करता है जैसे लैम्ब्डा एक्सप्रेशन का उपयोग करके, आप प्रत्येक बटन के लिए एक फ़ंक्शन को उसी तरह से परिभाषित कर सकते हैं जैसे कि बनाना प्रत्येक बटन के लिए एक लैम्ब्डा अभिव्यक्ति।
तदह मैकडॉनल्ड्स-जेनसेन

पहले कोड उदाहरण को एक लूप में रखना जो बदलते रहता है myXऔर myYपूरी तरह से काम करता है धन्यवाद।
तदह मैकडॉनल्ड्स-जेनसेन

3

मैट थॉम्पसन पर बिल्डिंग का जवाब: एक वर्ग को कॉल करने योग्य बनाया जा सकता है ताकि इसे एक समारोह के बजाय इस्तेमाल किया जा सके:

import tkinter as tk

class Callback:
    def __init__(self, func, *args, **kwargs):
        self.func = func
        self.args = args
        self.kwargs = kwargs
    def __call__(self):
        self.func(*self.args, **self.kwargs)

def default_callback(t):
    print("Button '{}' pressed.".format(t))

root = tk.Tk()

buttons = ["A", "B", "C"]

for i, b in enumerate(buttons):
    tk.Button(root, text=b, command=Callback(default_callback, b)).grid(row=i, column=0)

tk.mainloop()

2

इसका कारण यह है कि यह विधि तुरंत लागू करता है और बटन को दबाने से ऐसा कुछ भी नहीं होता है जिसका action(somenumber)मूल्यांकन किया जाता है और इसके वापसी मूल्य को बटन के लिए कमांड के रूप में जिम्मेदार ठहराया जाता है। इसलिए यदि actionआपको यह बताने के लिए कुछ प्रिंट करता है कि यह चला गया है और वापस आ गया है None, तो आप बस actionइसके रिटर्न मूल्य और दिए गए का मूल्यांकन करने के लिए दौड़ते हैंNone बटन के लिए कमांड के रूप में जाता है।

विभिन्न तर्कों के साथ फ़ंक्शन को कॉल करने के लिए बटन के लिए आप वैश्विक चर का उपयोग कर सकते हैं, हालांकि मैं इसकी अनुशंसा नहीं कर सकता:

import Tkinter as Tk

frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
frame.grid(row=2,column=2)
frame.pack(fill=Tk.X, padx=5, pady=5)
def action():
    global output
    global variable
    output.insert(Tk.END,variable.get())
button = Tk.Button(master=frame, text='press', command=action)
button.pack()
variable = Tk.Entry(master=frame)
variable.pack()
output = Tk.Text(master=frame)
output.pack()

if __name__ == '__main__':
    Tk.mainloop()

मैं क्या करूँगा classजिसकी वस्तुओं में हर चर आवश्यक होगा और उन्हें आवश्यकतानुसार बदलने के तरीके होंगे:

import Tkinter as Tk
class Window:
    def __init__(self):
        self.frame = Tk.Frame(width=5, height=2, bd=1, relief=Tk.SUNKEN)
        self.frame.grid(row=2,column=2)
        self.frame.pack(fill=Tk.X, padx=5, pady=5)

        self.button = Tk.Button(master=self.frame, text='press', command=self.action)
        self.button.pack()

        self.variable = Tk.Entry(master=self.frame)
        self.variable.pack()

        self.output = Tk.Text(master=self.frame)
        self.output.pack()

    def action(self):
        self.output.insert(Tk.END,self.variable.get())

if __name__ == '__main__':
    window = Window()
    Tk.mainloop()


2

सबसे अच्छी बात यह है कि मेमने का उपयोग निम्नानुसार है:

button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))

2

मुझे बहुत देर हो चुकी है, लेकिन यहाँ इसे पूरा करने का एक बहुत ही सरल तरीका है।

import tkinter as tk
def function1(param1, param2):
    print(str(param1) + str(param2))

var1 = "Hello "
var2 = "World!"
def function2():
    function1(var1, var2)

root = tk.Tk()

myButton = tk.Button(root, text="Button", command=function2)
root.mainloop()

आप बस उस फ़ंक्शन को लपेटते हैं जिसे आप किसी अन्य फ़ंक्शन में उपयोग करना चाहते हैं और बटन प्रेस पर दूसरे फ़ंक्शन को कॉल करते हैं।


जैसा कि आपके कोड ने var1और var2मुख्य मॉड्यूल में डाल दिया है , आप function1बिल्कुल छोड़ सकते हैं और printस्टेटमेंट डाल सकते हैं function2। क्या आप अन्य स्थितियों का उल्लेख करते हैं जो मुझे नहीं मिलती हैं?
ब्रोम

2

लैम्ब्डा सभी अच्छी तरह से और अच्छे हैं, लेकिन आप यह भी कोशिश कर सकते हैं (जो लूप btw के लिए काम करता है):

root = Tk()

dct = {"1": [*args], "2": [*args]}
def keypress(event):
    *args = dct[event.char]
    for arg in args:
        pass
for i in range(10):
    root.bind(str(i), keypress)

यह काम करता है क्योंकि जब बंधन सेट होता है, तो एक कुंजी प्रेस एक तर्क के रूप में घटना को पारित करता है। फिर आप इवेंट event.charको "1" या "यूपी" ect प्राप्त करने के लिए कॉल कर सकते हैं । यदि आपको ईवेंट विशेषताओं के अलावा किसी तर्क या कई तर्कों की आवश्यकता है। बस उन्हें संग्रहीत करने के लिए एक शब्दकोश बनाएं।


2

मैंने पहले भी इस समस्या का सामना किया है। आप सिर्फ लैम्ब्डा का उपयोग कर सकते हैं:

button = Tk.Button(master=frame, text='press',command=lambda: action(someNumber))

1

कमांड फ़ंक्शन को प्रवेश डेटा पास करने के लिए एक लैम्ब्डा का उपयोग करें यदि आपके पास बाहर ले जाने के लिए अधिक क्रियाएं हैं, तो इस तरह (मैंने इसे सामान्य बनाने की कोशिश की है, इसलिए बस अनुकूलित करें):

event1 = Entry(master)
button1 = Button(master, text="OK", command=lambda: test_event(event1.get()))

def test_event(event_text):
    if not event_text:
        print("Nothing entered")
    else:
        print(str(event_text))
        #  do stuff

यह बटन फ़ंक्शन के लिए ईवेंट में जानकारी पास करेगा। इसको लिखने के और भी कई तरीके हो सकते हैं, लेकिन यह मेरे लिए काम करता है।


1

जेसनपी - कुछ चीजें ...

यदि आप एक लूप में एक बटन चिपकाते हैं तो इसे बार-बार बनाया जाएगा ... जो कि शायद आप नहीं चाहते हैं। (एसा हो सकता हे)...

जब इसे हमेशा अंतिम इंडेक्स मिलता है तो लैम्बडा ईवेंट चलते हैं जब आप उन्हें क्लिक करते हैं - जब प्रोग्राम शुरू होता है। मुझे यकीन नहीं है कि 100% आप क्या कर रहे हैं, लेकिन हो सकता है कि जब यह बनाया जाता है तब मान को संग्रहीत करने का प्रयास करें, इसे बाद में लैंबडा बटन से कॉल करें।

उदाहरण: (इस कोड का उपयोग न करें, सिर्फ एक उदाहरण)

for entry in stuff_that_is_happening:
    value_store[entry] = stuff_that_is_happening

तो आप कह सकते हैं ...।

button... command: lambda: value_store[1]

उम्मीद है की यह मदद करेगा!


1

एक आसान तरीका कॉन्फ़िगर करने के लिए किया जाएगा buttonके साथ lambdaनिम्नलिखित वाक्य रचना की तरह:

button['command'] = lambda arg1 = local_var1, arg2 = local_var2 : function(arg1, arg2)

1

पश्चाताप के लिए: आप कुछ समान प्राप्त करने के लिए कक्षाओं का भी उपयोग कर सकते हैं। उदाहरण के लिए:

class Function_Wrapper():
    def __init__(self, x, y, z):
        self.x, self.y, self.z = x, y, z
    def func(self):
        return self.x + self.y + self.z # execute function

बटन तो बस द्वारा बनाया जा सकता है:

instance1 = Function_Wrapper(x, y, z)
button1  = Button(master, text = "press", command = instance1.func)

यह दृष्टिकोण आपको सेटिंग के आधार पर फ़ंक्शन तर्कों को बदलने की अनुमति देता है instance1.x = 3


1

आपको उपयोग करने की आवश्यकता है lambda:

button = Tk.Button(master=frame, text='press', command=lambda: action(someNumber))

1

लैम्ब्डा का उपयोग करें

import tkinter as tk

root = tk.Tk()
def go(text):
    print(text)

b = tk.Button(root, text="Click", command=lambda: go("hello"))
b.pack()
root.mainloop()

उत्पादन:

hello
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.