如何立即杀死睡眠线程和主要过程?

时间:2014-11-10 15:03:29

标签: python multithreading events tkinter window

我写了一个小应用程序,将股票市场滚动条滚动到Tkinter窗口,并使用线程类每分钟更新股票价值。

如果我关闭了窗口主进程没有停止,那么我已经实现了一种方法来关闭窗口并停止线程。但是当我关闭窗口时,主进程会延迟停止到下一次调用theading.run()方法。

我怎样才能实现即时关闭流程?

代码:

# -*- coding: UTF-8 -*-

import tkinter as tk
import tkinter.messagebox
import time
import threading
from random import randint as randint, uniform as randlimit


# Here starts the program working process, until here was the GUI
# CONSTANTS
CHAR_UP = "\u25B2"
CHAR_DOWN = "\u25BC"
CHAR_EVEN = "="
UPDATE_TIME = 60


# INITIAL DATA, this must be changed to implement the load of a external source
stock_market = [["GOOG", "587.25", CHAR_UP, "(+12.14)"],
                ["AAPL", "237.14", CHAR_UP, "(+7.25)"],
                ["GTAT", "87.47", CHAR_DOWN, "(-1.18)"],
                ["KNDI", "167.32", CHAR_UP, "(+6.85)"],
                ["ORCL", "482.91", CHAR_DOWN, "(-24.65)"],
                ["FBOK", "327.67", CHAR_DOWN, "(-11.78)"],
                ["TWTR", "842.41", CHAR_UP, "(+15.45)"]]


class AplicationTkinter(tk.Frame):
    """
    Class of tkinter.Frame subclass, Initializes the GUI
    constants:
        SPEED, the delay in millisecs of the scroll
    attributes:
        parent, the root Tk object
    """

    SPEED = 250

    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent = parent
        self._initGUI()
        self._scroll_ticker()
        self.parent.protocol("WM_DELETE_WINDOW",self.stop)
        # or toplevel.protocol(...

    def _initGUI(self):
        """
        initGUI, draws the layout.
        """
        # changes the window icon
        self.parent.iconbitmap("tabla.ico")
        self.parent.title("Stock Exchange Ticker")
        # fix a status bar at the bottom of the window, for future improvements
        self.status_bar = tk.Label(self.parent, text="", bd=1, relief=tk.SUNKEN,
                                anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        # content Frame for entry, for future improvements
        self.frame = tk.Frame(self.parent)
        self.frame.pack()
        self.var_entry = tk.StringVar()
        self.entry = tk.Entry(self.frame, textvariable=self.var_entry)
        self.entry.pack()
        self.var_entry.set("a default value")
        str_ent_1 = self.entry.get()
        # content LabelFrame to show the ticker scrolling line of text
        self.label_frame = tk.LabelFrame(self.parent,
                                         text="Ventana de Resultados")
        self.label_frame.pack()
        # creates an instance of the StockMarket class for contents the data
        self.market_one = StockMarket(stock_market)
        # the scrolling line of Text for show the data
        self.txt_ticker_widget = tk.Text(self.label_frame, background='black',
                                         height=1, width=56, wrap="none")
        self.txt_ticker_widget.pack(side=tk.TOP, fill=tk.X)
        self.txt_ticker_widget.tag_configure("up", foreground="green")
        self.txt_ticker_widget.tag_configure("down", foreground="red")
        self.txt_ticker_widget.tag_configure("even", foreground="white")
        self.tag = {CHAR_DOWN: "down", CHAR_EVEN: "even", CHAR_UP: "up"}

    def _scroll_ticker(self):
        """
        scroll_ticker, inserts character by character in the Text widget
        """
        self.txt_ticker_widget.configure(state=tk.NORMAL)
        self.txt_ticker_widget.insert(tk.END,
                                      self.market_one.get_next_character(),
                                      self.tag[self.market_one.get_tag()])
                                      # TODO simplify
        self.txt_ticker_widget.see(tk.END)
        self.txt_ticker_widget.configure(state=tk.DISABLED)
        self.txt_ticker_widget.after(self.SPEED, self._scroll_ticker)
        # recursive each interval of millisecs, constant SPEED

    def stop(self):
        if tk.messagebox.askokcancel("Quit?", "Are you sure you want to quit?"):
            # self.destroy()
            print("STOPPING !!")
            self.market_one.thread_updating.stop()
            self.destroy()
            self.parent.quit()

class StockTicker():
    """
    Class StockTicker, handle each stock symbol and their data
    attributes:
        symbol, string, the abbreviature of the securitie
        price, string, the current price of the securitie
        direction, string(1), is a character that indicates its las fix price
            went up, down or even
        change, string, is the value of the last change surrounded by '()',
            the first character is '+' or '-'
    """
    def __init__(self, list_data):
        self.symbol, self.price, self.direction, self.change = list_data

    def update_ticker(self):
        """
        update_ticker, update the securitie price, direction and
            change with random values
        """
        flt_price = float(self.price)
        if randint(0, 9) == 0:
            self.direction = CHAR_EVEN
        else:
            increase_percent = randlimit(-5, 5)
            # TODO implementar normalvariate(0, 0.02) o gauss(0, 0.02)
            flt_change = flt_price * increase_percent / 100
            flt_new_price = flt_price + flt_change
            self.price = "{:.2f}".format(flt_new_price)
            if flt_change < 0:
                self.direction = CHAR_DOWN
            elif flt_change == 0:
                self.direction = CHAR_EVEN
            else:
                self.direction = CHAR_UP
            self.change = "({:+.2f})".format(flt_change)

    def ticker_to_text(self):
        """
        ticker_to_text, returns a formatted string with all the data of
            the securitie.
        """
        return " |  {} {} {} {} ".format(self.symbol, self.price,
                                         self.direction, self.change)


class StockMarket():
    """
    Class StockMarket, creates and handle a list of StockTicker objects,
        and provide to the GUI of stuff for the scroll ticker
    attributes:
        smarket, list of StockTicker objects
        thread_actualizar, Thread object to update the stock market
            each time interval
    """
    def __init__(self, l_inicial):
        self.tickers = []
        self.index = 0
        self._load(l_inicial)
        self.current_ticker = self._get_one_ticker()
        self.thread_updating = UpdateThread(self)
        self.thread_updating.start()

    def _load(self, l_inicial):
        """
        load_market, load the list with StockTicker object taking the data from
            the initial source data.
        """
        for data_ticker in l_inicial:
            simple_ticker = StockTicker(data_ticker)
            self.tickers.append(simple_ticker)

    def update_market(self):
        """
        update_market, update the objects of the list
        """
        for ticker in self.tickers:
            ticker.update_ticker()

    def _get_one_ticker(self):
        """
        get_one_ticker, getter function to return one securitie data in text
            format and rotates to the next one
        """
        self.one_ticker = self.tickers.pop(0)
        self.tickers.append(self.one_ticker)
        self.index = 0
        return self.one_ticker.ticker_to_text()

    def get_next_character(self):
        """
        get_next_character, returns a character of one securitie
            (if the securitie data is exhausted retrieve another securitie)
            data to the GUI.
           """
        if self.index == len(self.current_ticker):
            self.current_ticker = self._get_one_ticker()
            self.index = 0
        character_symbol = self.current_ticker[self.index:self.index+1]
        self.index += 1
        return character_symbol

    def get_tag(self):
        return self.one_ticker.direction


class UpdateThread(threading.Thread):
    """
    Class UpdateThread(), subclass of Thread, handle the time to the next
        update of the stock market values
    args:
        market_1, a StockMarket class object to update
    attributes:
        my_check, string for debugging purpouses, it'll be implemented the
            source data management the_market, StockMarket object that will
            be updated
    """
    def __init__(self, market_1):
        self.my_check = " CHECK "   # TODO replace with initial source data.
        self.the_market = market_1
        self.is_quit = False
        threading.Thread.__init__(self)

    def run(self):
        """
        run, overrides the Thread run method, and calls the update_market
            method of StockMarket class each interval
        """
        time.sleep(UPDATE_TIME)
        self.the_market.update_market()
        print(" UPDATED!!!")    # for debugging
        if not self.is_quit:
            self.run()

    def stop(self):
        """
        stop, for stopping the thread when event occurs
        """
        self.is_quit = True


# STARTS THE PROGRAM
def main():
    the_window = tk.Tk()
    aplication = AplicationTkinter(the_window)
    # init the GUI process
    the_window.mainloop()

if __name__ == '__main__':
    main()

0 个答案:

没有答案