मैं पायथन टिंकर प्रोग्राम में विंडो क्लोज इवेंट ('X' बटन पर क्लिक करने वाला उपयोगकर्ता) कैसे संभाल सकता हूं?
मैं पायथन टिंकर प्रोग्राम में विंडो क्लोज इवेंट ('X' बटन पर क्लिक करने वाला उपयोगकर्ता) कैसे संभाल सकता हूं?
जवाबों:
टिंकर प्रोटोकॉल हैंडलर नामक एक तंत्र का समर्थन करता है । यहाँ, शब्द प्रोटोकॉल का तात्पर्य अनुप्रयोग और विंडो प्रबंधक के बीच पारस्परिक क्रिया से है। सबसे अधिक इस्तेमाल किया जाने वाला प्रोटोकॉल कहा जाता है WM_DELETE_WINDOW
, और यह परिभाषित करने के लिए उपयोग किया जाता है कि उपयोगकर्ता द्वारा विंडो प्रबंधक का उपयोग करके स्पष्ट रूप से विंडो बंद करने पर क्या होता है।
आप इस प्रोटोकॉल के लिए एक हैंडलर स्थापितprotocol
करने के लिए विधि का उपयोग कर सकते हैं (विजेट एक या विजेट होना चाहिए ):Tk
Toplevel
यहाँ आपके पास एक ठोस उदाहरण है:
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
Tkinter
एक सबमॉड्यूल संदेश बॉक्स नहीं था। मैंने इस्तेमाल कियाimport tkMessageBox as messagebox
मैट ने करीब बटन का एक क्लासिक संशोधन दिखाया है।
अन्य पास विंडो को कम से कम बटन है।
आप होने से इस व्यवहार reproduced कर सकते हैं iconify विधि
होना प्रोटोकॉल विधि का दूसरा तर्क।
विंडोज 7 और 10 पर परीक्षण किया गया कार्य उदाहरण यहां दिया गया है:
# Python 3
import tkinter
import tkinter.scrolledtext as scrolledtext
root = tkinter.Tk()
# make the top right close button minimize (iconify) the main window
root.protocol("WM_DELETE_WINDOW", root.iconify)
# make Esc exit the program
root.bind('<Escape>', lambda e: root.destroy())
# create a menu bar with an Exit command
menubar = tkinter.Menu(root)
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Exit", command=root.destroy)
menubar.add_cascade(label="File", menu=filemenu)
root.config(menu=menubar)
# create a Text widget with a Scrollbar attached
txt = scrolledtext.ScrolledText(root, undo=True)
txt['font'] = ('consolas', '12')
txt.pack(expand=True, fill='both')
root.mainloop()
इस उदाहरण में हम उपयोगकर्ता को दो नए निकास विकल्प देते हैं:
क्लासिक फ़ाइल → बाहर निकलें, और Escबटन भी ।
Tkinter गतिविधि के आधार पर, और विशेष रूप से Tkinter.after का उपयोग करते समय, इस गतिविधि को रोकना destroy()
- यहां तक कि प्रोटोकॉल (), एक बटन आदि का उपयोग करके - इस गतिविधि को परेशान करेगा ("त्रुटि निष्पादित करते समय") बजाय इसे समाप्त करने के। । लगभग हर मामले में सबसे अच्छा समाधान एक ध्वज का उपयोग करना है। यहां इसका उपयोग करने का एक सरल, मूर्खतापूर्ण उदाहरण दिया गया है (हालांकि मैं निश्चित हूं कि आप में से अधिकांश को इसकी आवश्यकता नहीं है! :)
from Tkinter import *
def close_window():
global running
running = False # turn off while loop
print( "Window closed")
root = Tk()
root.protocol("WM_DELETE_WINDOW", close_window)
cv = Canvas(root, width=200, height=200)
cv.pack()
running = True;
# This is an endless loop stopped only by setting 'running' to 'False'
while running:
for i in range(200):
if not running:
break
cv.create_oval(i, i, i+1, i+1)
root.update()
यह ग्राफिक्स गतिविधि को अच्छी तरह से समाप्त करता है। आपको केवल running
सही जगह पर जांच करने की आवश्यकता है ।
मैं अपना ध्यान इस ओर लाने के लिए अपॉस्तोलोस द्वारा उत्तर देना चाहता हूं। यहाँ स्पष्ट विवरण और उदाहरण कोड के साथ वर्ष 2019 में पायथन 3 के लिए और अधिक विस्तृत उदाहरण दिया गया है।
destroy()
(या कस्टम विंडो क्लोजिंग हैंडलर बिल्कुल भी नहीं है) यूजर के बंद होने पर विंडो और उसके सभी रनिंग कॉलबैक को तुरंत नष्ट कर देगा।यह आपके लिए खराब हो सकता है, आपकी वर्तमान टिंकर गतिविधि पर निर्भर करता है, और विशेष रूप से tkinter.after
(आवधिक कॉलबैक) का उपयोग करते समय। आप एक कॉलबैक का उपयोग कर रहे होंगे जो कुछ डेटा को संसाधित करता है और डिस्क पर लिखता है ... उस स्थिति में, आप स्पष्ट रूप से चाहते हैं कि डेटा लेखन अचानक समाप्त हुए बिना समाप्त हो जाए।
इसके लिए सबसे अच्छा उपाय है कि आप एक ध्वज का उपयोग करें। इसलिए जब उपयोगकर्ता विंडो बंद करने का अनुरोध करता है, तो आप उस ध्वज को चिह्नित करते हैं, और फिर उस पर प्रतिक्रिया करते हैं।
(ध्यान दें: मैं सामान्य रूप से GUIs को अच्छी तरह से समझाया कक्षाओं और अलग-अलग वर्कर थ्रेड्स के रूप में डिज़ाइन करता हूं, और मैं निश्चित रूप से "ग्लोबल" का उपयोग नहीं करता हूं (मैं इसके बजाय क्लास इंस्टेंस वेरिएबल्स का उपयोग करता हूं), लेकिन इसका मतलब प्रदर्शित करने के लिए एक सरल, स्ट्रिप-डाउन उदाहरण है जब उपयोगकर्ता विंडो बंद करता है तो Tk अचानक आपके आवधिक कॉलबैक को मारता है ...)
from tkinter import *
import time
# Try setting this to False and look at the printed numbers (1 to 10)
# during the work-loop, if you close the window while the periodic_call
# worker is busy working (printing). It will abruptly end the numbers,
# and kill the periodic callback! That's why you should design most
# applications with a safe closing callback as described in this demo.
safe_closing = True
# ---------
busy_processing = False
close_requested = False
def close_window():
global close_requested
close_requested = True
print("User requested close at:", time.time(), "Was busy processing:", busy_processing)
root = Tk()
if safe_closing:
root.protocol("WM_DELETE_WINDOW", close_window)
lbl = Label(root)
lbl.pack()
def periodic_call():
global busy_processing
if not close_requested:
busy_processing = True
for i in range(10):
print((i+1), "of 10")
time.sleep(0.2)
lbl["text"] = str(time.time()) # Will error if force-closed.
root.update() # Force redrawing since we change label multiple times in a row.
busy_processing = False
root.after(500, periodic_call)
else:
print("Destroying GUI at:", time.time())
try: # "destroy()" can throw, so you should wrap it like this.
root.destroy()
except:
# NOTE: In most code, you'll wanna force a close here via
# "exit" if the window failed to destroy. Just ensure that
# you have no code after your `mainloop()` call (at the
# bottom of this file), since the exit call will cause the
# process to terminate immediately without running any more
# code. Of course, you should NEVER have code after your
# `mainloop()` call in well-designed code anyway...
# exit(0)
pass
root.after_idle(periodic_call)
root.mainloop()
यह कोड आपको दिखाएगा कि WM_DELETE_WINDOW
हैंडलर चलता है, जबकि हमारा रिवाज periodic_call()
काम / छोरों के बीच में व्यस्त है!
हम कुछ अतिरंजित .after()
मूल्यों का उपयोग करते हैं: 500 मिलीसेकंड। यह सिर्फ आपके लिए बहुत आसान बनाने के लिए है, जो कि समय-समय पर व्यस्त रहने के दौरान बंद होने के बीच के अंतर को देखने के लिए है, या नहीं ... यदि आप संख्याओं को अपडेट करते समय बंद करते हैं, तो आप देखेंगे कि आपके आवधिक कॉल के दौरान क्याWM_DELETE_WINDOW
हुआ था " व्यस्त प्रसंस्करण: सच है ”। यदि आप संख्याओं को रोकते हैं, तो (जिसका अर्थ है कि आवधिक कॉलबैक उस समय संसाधित नहीं हो रहा है), आप देखते हैं कि यह "व्यस्त नहीं" होने के दौरान हुआ।
वास्तविक दुनिया के उपयोग में, आपका .after()
कोई व्यक्ति 30-100 मिलीसेकंड का उपयोग करेगा, जिसके पास एक उत्तरदायी GUI होगा। यह केवल आपको प्रदर्शन को समझने में मदद करने के लिए एक प्रदर्शन है, जो कि Tk के डिफ़ॉल्ट के खिलाफ खुद को बचाने के लिए "व्यवहार बंद करते समय सभी कार्यों को तुरंत बाधित करता है।"
संक्षेप में: WM_DELETE_WINDOW
हैंडलर को एक ध्वज सेट करें , और फिर उस ध्वज को समय-समय पर और मैन्युअल रूप .destroy()
से खिड़की की जांच करें जब वह सुरक्षित हो (जब आपका ऐप सभी काम के साथ हो)।
पुनश्च: आप उपयोगकर्ता WM_DELETE_WINDOW
से पूछने के लिए भी उपयोग कर सकते हैं कि क्या वे वास्तव में खिड़की बंद करना चाहते हैं; और यदि वे उत्तर नहीं देते हैं, तो आप ध्वज को सेट नहीं करते हैं। यह बहुत सरल है। आप बस अपने में एक संदेश बॉक्स दिखाते हैं WM_DELETE_WINDOW
और उपयोगकर्ता के उत्तर के आधार पर ध्वज सेट करते हैं।
सरल संस्करण का प्रयास करें:
import tkinter
window = Tk()
closebutton = Button(window, text='X', command=window.destroy)
closebutton.pack()
window.mainloop()
या यदि आप अधिक कमांड जोड़ना चाहते हैं:
import tkinter
window = Tk()
def close():
window.destroy()
#More Functions
closebutton = Button(window, text='X', command=close)
closebutton.pack()
window.mainloop()
from tkinter import*
root=Tk()
exit_button=Button(root,text="X",command=root.quit)
root.mainloop()