টিন্টারের ইভেন্ট লুপের পাশাপাশি আপনি কীভাবে নিজের কোড চালাবেন?


119

আমার ছোট ভাই সবেমাত্র প্রোগ্রামিংয়ে intoুকছে, এবং তার বিজ্ঞান ফেয়ার প্রকল্পের জন্য, তিনি আকাশে পাখির ঝাঁকের একটি অনুকরণ করছেন। তিনি তার কোড লিখিত অধিকাংশ অর্জিত হচ্ছে, এবং এটি চমত্কারভাবে কাজ করে, কিন্তু পাখি সরানো প্রয়োজন প্রতি মুহূর্তে

টিনকিটার অবশ্য নিজের ইভেন্ট লুপের জন্য সময়কে হোগ করে, এবং তাই তার কোডটি চলবে না। এরকম root.mainloop()রান রান এবং চলমান রাখে এবং একমাত্র জিনিস এটা রান ইভেন্ট হ্যান্ডলার হয়।

মেইনলুপের পাশাপাশি তার কোড চালানোর কোনও উপায় আছে (মাল্টিথ্রেডিং ছাড়াই এটি বিভ্রান্তিকর এবং এটি সহজ রাখা উচিত), এবং যদি হয় তবে এটি কী?

এই মুহুর্তে, তিনি একটি কুরুচিপূর্ণ হ্যাক নিয়ে এসেছিলেন এবং তার move()ফাংশনটি বেঁধে <b1-motion>রেখেছেন, যাতে যতক্ষণ না সে বোতামটি ধরে রাখে এবং মাউসটি উইগল করে, কাজ করে। তবে আরও ভাল উপায় হতে পারে।

উত্তর:


140

বস্তুটিতে afterপদ্ধতিটি ব্যবহার করুন Tk:

from tkinter import *

root = Tk()

def task():
    print("hello")
    root.after(2000, task)  # reschedule event in 2 seconds

root.after(2000, task)
root.mainloop()

afterপদ্ধতির জন্য এখানে ঘোষণা এবং ডকুমেন্টেশন রয়েছে :

def after(self, ms, func=None, *args):
    """Call function once after given time.

    MS specifies the time in milliseconds. FUNC gives the
    function which shall be called. Additional parameters
    are given as parameters to the function call.  Return
    identifier to cancel scheduling with after_cancel."""

29
যদি আপনি টাইমআউট 0 হওয়ার জন্য নির্দিষ্ট করে থাকেন তবে টাস্ক সমাপ্তির সাথে সাথে ইভেন্ট লুপটিতে ফিরে আসবে। আপনার কোডটি যতবার সম্ভব চালানো যায় এটি অন্যান্য ইভেন্টগুলিকে অবরুদ্ধ করবে না।
নাথান

[এক্স] বোতামটি ক্লিক করার পরে ওপেনসিভি এবং টিন্টার একসাথে কাজ করার জন্য কয়েক ঘন্টা চেষ্টা করে আমার চুল টেনে নেওয়ার পরে, উইন 32 গুই-ফিনড উইন্ডো (কিছুই নয়, 'উইন্ডো শিরোনাম') চালিয়ে গেল! আমি এ জাতীয়
নুব

এটি সেরা বিকল্প নয়; যদিও এটি এই ক্ষেত্রে কাজ করে, এটি বেশিরভাগ স্ক্রিপ্টগুলির জন্য ভাল নয় (এটি কেবল প্রতি 2 সেকেন্ডে চলে), এবং নাথন পোস্ট করেছেন এমন পরামর্শ অনুসারে টাইমআউট 0 হওয়ার জন্য নির্ধারণ করা হয়েছে কারণ টিনকিটার ব্যস্ত না থাকাকালীন এটি চালিত হয় (যা পারে কিছু জটিল প্রোগ্রামে সমস্যা সৃষ্টি করে)। threadingমডিউল সঙ্গে থাকা ভাল ।
বেনামে

59

সমাধান বিয়ন্সের পোস্ট করেছে ফলাফল একটি মধ্যে "RuntimeError: বিভিন্ন appartment থেকে Tcl কলিং" বার্তা আমার কম্পিউটারে (তাহলে RedHat এন্টারপ্রাইজ 5, পাইথন 2.6.1)। বজর্ন সম্ভবত এই বার্তাটি অর্জন করতে পারেন নি, যেহেতু, আমি এক জায়গায় যাচাই করেছি , টিন্টারের সাথে থ্রেডিং ভুলভাবে অপ্রত্যাশিত এবং প্ল্যাটফর্ম নির্ভর।

সমস্যাটি app.start()টাকার জন্য একটি উল্লেখ হিসাবে গণনা করা হচ্ছে বলে অ্যাপটিতে টক উপাদান রয়েছে Tk আমি এটি app.start()একটি self.start()অভ্যন্তরের সাথে প্রতিস্থাপন করে ঠিক করেছি __init__। আমি এটিও তৈরি করেছিলাম যাতে সমস্ত টাকার রেফারেন্স হয় ফাংশনেরmainloop() অভ্যন্তরে থাকে যা কল করে বা যে ফাংশন বলে তার ভিতরে ফাংশন থাকে যা কল করে mainloop()(এটি "পৃথক অ্যাপার্টমেন্ট" ত্রুটি এড়াতে স্পষ্টতই সমালোচিত))

অবশেষে, আমি কলব্যাক সহ একটি প্রোটোকল হ্যান্ডলার যুক্ত করেছি, যেহেতু এটি ছাড়াই প্রোগ্রামটি ত্রুটি সহ প্রস্থান করে যখন ব্যবহারকারী দ্বারা টাউন উইন্ডোটি বন্ধ হয়ে যায়।

সংশোধিত কোডটি নিম্নরূপ:

# Run tkinter code in another thread

import tkinter as tk
import threading

class App(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.start()

    def callback(self):
        self.root.quit()

    def run(self):
        self.root = tk.Tk()
        self.root.protocol("WM_DELETE_WINDOW", self.callback)

        label = tk.Label(self.root, text="Hello World")
        label.pack()

        self.root.mainloop()


app = App()
print('Now we can continue running code while mainloop runs!')

for i in range(100000):
    print(i)

আপনি runপদ্ধতিতে যুক্তিগুলি কীভাবে পাস করবেন ? কীভাবে করব তা আমি বুঝতে পারি না ...
থিওডাক্টর

5
সাধারণত আপনি আর্গুমেন্টগুলি পাস করতেন __init__(..), selfrun(..)
এগুলিতে রাখতেন

1
রুটটি একেবারে দেখা যাচ্ছে না, এই সতর্কতাটি দেয়: AR সতর্কতা: এনএস উইন্ডো টেনে আনার অঞ্চলগুলি কেবলমাত্র মূল থ্রেডে অবৈধ করা উচিত! এটি ভবিষ্যতে একটি ব্যতিক্রম ছুঁড়ে ফেলবে `
বব ববস্টার

1
এই মন্তব্যটি আরও অনেক স্বীকৃতির দাবিদার। অ্যামেজিং।
ড্যানিয়েল রেহানিয়ান

এটি জীবন রক্ষাকারী। জিআইআই এর বাইরের কোডটি টিন্টার থ্রেডটি বেঁচে থাকার জন্য পরীক্ষা করা উচিত যদি আপনি গি থেকে একবার বেরোনোর ​​সময় পাইথন স্ক্রিপ্ট থেকে বেরিয়ে আসতে সক্ষম না হন। এরকম কিছুwhile app.is_alive(): etc
এম

20

আপনার নিজের লুপটি লেখার সময়, সিমুলেশনের মতো (আমি ধরে নিই), আপনাকে updateফাংশনটি কল করতে হবে যা যা করে তা করতে হবে mainloop: উইন্ডোটি আপনার পরিবর্তনগুলি আপডেট করে তবে আপনি এটি আপনার লুপে করেন।

def task():
   # do something
   root.update()

while 1:
   task()  

10
এই ধরণের প্রোগ্রামিং সম্পর্কে আপনাকে খুব সাবধানতা অবলম্বন করতে হবে । যদি কোনও ইভেন্ট taskডাকা হওয়ার কারণ হয়ে থাকে আপনি নেস্টেড ইভেন্ট লুপগুলি শেষ করবেন এবং এটি খারাপ। ইভেন্ট লুপগুলি কীভাবে কাজ করে তা আপনি পুরোপুরি বুঝতে না পারলে আপনার কোনও updateমূল্যে কল করা এড়ানো উচিত ।
ব্রায়ান ওকলে

আমি এই কৌশলটি একবার ব্যবহার করেছি - ঠিক আছে তবে আপনি এটি কীভাবে করেন তার উপর নির্ভর করে আপনার ইউআইতে কিছুটা হতবাক হতে পারে।
jldupont

6

অন্য বিকল্পটি হ'ল টিন্টিটারকে একটি পৃথক থ্রেডে চালিত করা। এটি করার একটি উপায় হ'ল:

import Tkinter
import threading

class MyTkApp(threading.Thread):
    def __init__(self):
        self.root=Tkinter.Tk()
        self.s = Tkinter.StringVar()
        self.s.set('Foo')
        l = Tkinter.Label(self.root,textvariable=self.s)
        l.pack()
        threading.Thread.__init__(self)

    def run(self):
        self.root.mainloop()


app = MyTkApp()
app.start()

# Now the app should be running and the value shown on the label
# can be changed by changing the member variable s.
# Like this:
# app.s.set('Bar')

যদিও সাবধান থাকুন, মাল্টিথ্রেডেড প্রোগ্রামিং শক্ত এবং আপনার নিজের পায়ে গুলি করা সত্যিই সহজ। উদাহরণস্বরূপ আপনি উপরের নমুনা শ্রেণীর সদস্য ভেরিয়েবলগুলি পরিবর্তন করার সময় আপনাকে সতর্কতা অবলম্বন করতে হবে যাতে আপনি টিনকিনারের ইভেন্ট লুপটির সাথে বাধা না পান।


3
নিশ্চিত না যে এটি কাজ করতে পারে। সেরকম কিছু চেষ্টা করলাম এবং আমি "রানটাইম’রার: মূল থ্রেড মূল লুপটিতে নেই"।
jldupont

5
jldupont: আমি পেয়েছি "রানটাইমআরার: বিভিন্ন অ্যাপার্টমেন্ট থেকে কলিং টিসিএল" (সম্ভবত অন্য সংস্করণে একই ত্রুটি)। ফিক্সটি __init __ () এ নয়, রান () তে টাকা শুরু করার ছিল। এর অর্থ এই যে আপনি একই থ্রেড টাকা initialising হয় আপনি mainloop () কল করুন।
mgiuca

2

এটি জিপিএস রিডার এবং ডেটা উপস্থাপক হবে কি এটির প্রথম কার্যকারী সংস্করণ। খুব কম ত্রুটি বার্তাগুলি সহ টিনকিটার একটি খুব ভঙ্গুর জিনিস। এটি স্টাফ রাখে না এবং কেন বেশি সময় দেয় তা জানায় না। একজন ভাল WYSIWYG ফর্ম বিকাশকারী থেকে আসা খুব কঠিন। যাইহোক, এটি একটি ছোট রুটিন সেকেন্ডে 10 বার চালায় এবং একটি ফর্মের তথ্য উপস্থাপন করে। এটি ঘটতে কিছুক্ষণ সময় নিল। যখন আমি 0 এর টাইমার মান চেষ্টা করেছিলাম, ফর্মটি কখনই আসেনি। আমার মাথা এখন ব্যথা! প্রতি সেকেন্ডে 10 বা তার বেশি বার আমার পক্ষে যথেষ্ট। আমি আশা করি এটি অন্য কাউকে সাহায্য করবে। মাইক মোড়

import tkinter as tk
import time

def GetDateTime():
  # Get current date and time in ISO8601
  # https://en.wikipedia.org/wiki/ISO_8601 
  # https://xkcd.com/1179/
  return (time.strftime("%Y%m%d", time.gmtime()),
          time.strftime("%H%M%S", time.gmtime()),
          time.strftime("%Y%m%d", time.localtime()),
          time.strftime("%H%M%S", time.localtime()))

class Application(tk.Frame):

  def __init__(self, master):

    fontsize = 12
    textwidth = 9

    tk.Frame.__init__(self, master)
    self.pack()

    tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth,
             text='Local Time').grid(row=0, column=0)
    self.LocalDate = tk.StringVar()
    self.LocalDate.set('waiting...')
    tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth,
             textvariable=self.LocalDate).grid(row=0, column=1)

    tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth,
             text='Local Date').grid(row=1, column=0)
    self.LocalTime = tk.StringVar()
    self.LocalTime.set('waiting...')
    tk.Label(self, font=('Helvetica', fontsize), bg = '#be004e', fg = 'white', width = textwidth,
             textvariable=self.LocalTime).grid(row=1, column=1)

    tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth,
             text='GMT Time').grid(row=2, column=0)
    self.nowGdate = tk.StringVar()
    self.nowGdate.set('waiting...')
    tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth,
             textvariable=self.nowGdate).grid(row=2, column=1)

    tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth,
             text='GMT Date').grid(row=3, column=0)
    self.nowGtime = tk.StringVar()
    self.nowGtime.set('waiting...')
    tk.Label(self, font=('Helvetica', fontsize), bg = '#40CCC0', fg = 'white', width = textwidth,
             textvariable=self.nowGtime).grid(row=3, column=1)

    tk.Button(self, text='Exit', width = 10, bg = '#FF8080', command=root.destroy).grid(row=4, columnspan=2)

    self.gettime()
  pass

  def gettime(self):
    gdt, gtm, ldt, ltm = GetDateTime()
    gdt = gdt[0:4] + '/' + gdt[4:6] + '/' + gdt[6:8]
    gtm = gtm[0:2] + ':' + gtm[2:4] + ':' + gtm[4:6] + ' Z'  
    ldt = ldt[0:4] + '/' + ldt[4:6] + '/' + ldt[6:8]
    ltm = ltm[0:2] + ':' + ltm[2:4] + ':' + ltm[4:6]  
    self.nowGtime.set(gdt)
    self.nowGdate.set(gtm)
    self.LocalTime.set(ldt)
    self.LocalDate.set(ltm)

    self.after(100, self.gettime)
   #print (ltm)  # Prove it is running this and the external code, too.
  pass

root = tk.Tk()
root.wm_title('Temp Converter')
app = Application(master=root)

w = 200 # width for the Tk root
h = 125 # height for the Tk root

# get display screen width and height
ws = root.winfo_screenwidth()  # width of the screen
hs = root.winfo_screenheight() # height of the screen

# calculate x and y coordinates for positioning the Tk root window

#centered
#x = (ws/2) - (w/2)
#y = (hs/2) - (h/2)

#right bottom corner (misfires in Win10 putting it too low. OK in Ubuntu)
x = ws - w
y = hs - h - 35  # -35 fixes it, more or less, for Win10

#set the dimensions of the screen and where it is placed
root.geometry('%dx%d+%d+%d' % (w, h, x, y))

root.mainloop()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.