Problem beim beenden einer Funktion

Fragen zu Tkinter.
Antworten
DrW3sk3r
User
Beiträge: 18
Registriert: Dienstag 16. April 2013, 19:39

Halli Hallo,
ich habe ein Problem dazu müsst ihr erst das Script lesen.

Code: Alles auswählen

#!/usr/bin/env python
#coding: utf-8
from Tkinter import *

root = Tk()
def start():
     for i in range(0,1000):
           print(i)

def stop():
     return start

startbtn = Button(root, text="Start", command=start)
startbtn.pack()

stopbtn = Button(root, text="Stop", command=stop)
stopbtn.pack()

root.mainloop()

Mein Problem ist wenn ich den Startbutton drücke fängt er an zu Zählen. Aber wenn ich Stop drücke passiert nicht und er Zählt weiter.

Ich wollte wissen wie kann ich die Funktion Start mit dem Stopbutton beenden?

Ich freue mich auf jede Antwort
BlackJack

@DrW3sk3r: So funktionieren GUIs nicht. Die Funktion wird von der GUI-Hauptschleife aufgerufen, die dafür zuständig ist, dass auf Schaltflächen reagiert wird und die GUI aktualisiert wird. Solange die Funktion also läuft, kann logischerweise die Hauptschleife nicht laufen. Die geht erst weiter wenn die Funktion am Ende angekommen ist und die Kontrolle wieder dorthin abgibt.

Eine Möglichkeit regelmässig etwas zu tun, zum Beispiel eine Zahl hochzuzählen und auszugeben ist die `after()`-Methode auf Widgets. Damit kann man eine Funktion oder Methode angeben die nach einer angegebenen Zeit von der GUI-Hauptschleife aufgerufen wird. Die kann dann *einen* Schritt machen, und sich zum Beispiel selber wieder für einen Aufruf für den nächsten Schritt vormerken lassen. Da man sich hier Zustände über mehrere Aufrufe hinweg merken muss (läuft der Zähler gerade, welche Zahl ist aktuell), ist eine idiomatische Lösung eine mit einer Klasse die das kapselt. Für GUI-Programmierung sollte man IMHO *vorher* schon halbwegs sicher in der objektorientierten Programmierung sein.
DrW3sk3r
User
Beiträge: 18
Registriert: Dienstag 16. April 2013, 19:39

Das heist also ich kann diese dann nicht stoppen und muss warten bis diese durch ist damit die Haufunktion wieder laufen kann.
Korrigiere mich wenn ich falsch liege

Aber ist möglich oder?
BlackJack

@DrW3sk3r: Wenn eine Funktion läuft kann sie sich nur selber stoppen, denn wenn sie läuft, dann läuft ja *der* Code und kein anderer. (Threading lasse ich hier mal aussen vor, weil das wenn man es nicht wirklich braucht unnötige Probleme mit sich bringt. Insbesondere mit GUIs.)

Was für eine „Haufunktion”? Und *was* ist jetzt möglich (oder nicht)?

Edit:

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import print_function
import Tkinter as tk


class Application(object):
    def __init__(self, parent):
        self.parent = parent
        self.number_iterator = None
        self.start_button = tk.Button(parent, text='Start', command=self.start)
        self.start_button.pack()
        self.stop_button = tk.Button(
            parent, text='Stop', state=tk.DISABLED, command=self.stop
        )
        self.stop_button.pack()

    def _count(self):
        try:
            if self.number_iterator:
                print(next(self.number_iterator))
        except StopIteration:
            self.stop()
        else:
            self.parent.after_idle(self._count)

    def start(self):
        assert self.number_iterator is None
        self.start_button['state'] = tk.DISABLED
        self.stop_button['state'] = tk.NORMAL
        self.number_iterator = iter(range(10000))
        self.parent.after_idle(self._count)

    def stop(self):
        self.start_button['state'] = tk.NORMAL
        self.stop_button['state'] = tk.DISABLED
        self.number_iterator = None


def main():
    root = tk.Tk()
    _application = Application(root)
    root.mainloop()


if __name__ == '__main__':
    main()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi DrW3sk3r

Hier noch eine weitere Variante mit 'after()' in einer Klasse:

Code: Alles auswählen

#!/usr/bin/env python
#coding: utf-8

from functools import partial

try:
    #~~ For Python 2.x
    import Tkinter as tk
except ImportError:
    #~~ For Python 3.x
    import tkinter as tk

TIME_INTERVAL = 100 # 100ms
MAX_COUNT = 10000
FONT_READOUT = ("Helvetica", 20, "bold")
BG_READOUT = 'khaki1'
FG_READOUT = 'blue'

class MyCounter(tk.Frame):
    
    def __init__(self, parent_widget, interval=TIME_INTERVAL,
        max_count=MAX_COUNT, **options):
            
        self.interval = interval
        self.max_count = max_count
        
        self.counter = 0
        self.run = False

        tk.Frame.__init__(self, parent_widget, **options)

        self.build_counter_readout()
        self.build_command_buttons()
        self.cycler()
        
    def build_command_buttons(self):
        button_frame = tk.Frame(self, bg=BG_READOUT)
        button_frame.pack(fill='x', ipadx=2, ipady=2)
        
        button_names = ["Start", "Stop", "Reset"]
        for button_name in button_names:
            button = tk.Button(button_frame, text=button_name)
            button.pack(side='left', expand=True)
            button.bind('<Button-1>', partial(
                self.command_button_callback, button_name))
            
    def build_counter_readout(self):
        self.readout_var = tk.IntVar()
        tk.Label(self, textvariable=self.readout_var, font=FONT_READOUT,
            bg=BG_READOUT, fg=FG_READOUT, width=12).pack(fill='x')

    def command_button_callback(self, button_name, args):
        if button_name == "Start" and not self.run:
            self.run = True
        if button_name == "Stop":
            self.run = False
        if button_name == "Reset":
            self.counter = 0
            self.readout_var.set(self.counter)
            
    def cycler(self):
        if self.run and self.counter < self.max_count:
            self.counter += 1
        self.readout_var.set(self.counter)
            
        self.after(self.interval, self.cycler)

def main():
    root = tk.Tk()

    MyCounter(root, 1, relief='raised', bd=1).pack(padx=2, pady=(2, 0))
    MyCounter(root, relief='raised', bd=1).pack(padx=2, pady=(2, 0))
    MyCounter(root, 500, 100, relief='raised', bd=1).pack(padx=2, pady=(2, 0))

    root.mainloop()
    
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
Antworten