Tkinter Fenster nach 5 Minuten automatisch schliessen

Fragen zu Tkinter.
Antworten
flambo
User
Beiträge: 10
Registriert: Mittwoch 7. März 2012, 15:05

Hallo zusammen,
Ich habe ein Python-Script geschrieben, welches MAC-Adressen aus einer Text-Datei ausliest und alle unbekannten in einem Tkinter Fenster meldet. Das Script starte ich alle 5 Minuten mit einer Windows Aufgabe neu.
Das Problem: Wenn das Tkinter Fenster mit den unbekannten MAC-Adressen erscheint, kann das Script erst wieder ausgeführt werden wenn das Fenster geschlossen wird. Ich möchte aber das Fenster nicht jedesmal von Hand schliessen sondern, dass es automatisch nach einer Zeit von etwa 5 Minuten geschlossen wird. Nur habe ich keine Ahnung wie ich das lösen will..

Ich bin für jede Hilfe dankbar!!

Der Code sieht so aus (nicht ganzer Code):

Code: Alles auswählen

if (len(untrusted) > 0) and (len(unknownlog) > 0):
    datenstr = ""
    for entry in unknownlog:
        t = time.strftime("%d.%m.%Y um %H:%M:%S Uhr")
        timestamp = str(time.time())
        daten = (timestamp,t,entry[0],entry[1],entry[2],entry[3],entry[4],entry[5],entry[6],"not trusted")
        datenstr += "\n""\nIP-Address:\t"+entry[0]+"\nHost-Name:\t"+entry[1]+"\nMAC-Address:\t"+entry[2]+"\nResponse Time:\t"+entry[3]+"\nLogged User:\t"+entry[4]+"\nOperating System:\t"+entry[5]+"\nNIC-Vendor:\t"+entry[6]+"\n" 
        csvwriter1.writerow(daten)
    
    inf = "ACHTUNG!! Es wurde fremde Hardware erkannt!"
    class App:
      def __init__(self, master):
        lab=Label(root,text=inf,font=("Arial", 16))
        lab.pack()
        self.label = Label(root,justify=LEFT,padx=20,text=t,font=("Arial", 11))
        self.label.pack()
        self.label = Label(root,justify=LEFT,padx=10,text=datenstr,font=("Arial", 11))
        self.label.pack()
        frame = Frame(master)
        frame.pack()
        self.slogan = Button(frame,justify=LEFT,padx=10,
                             text="Mehr Informationen in Netscan",font=("Arial", 10),
                             command=self.start_tool)
        self.slogan.pack(side=LEFT)
        self.slogan = Button(frame,justify=LEFT,padx=10,
                             text="Log-File",font=("Arial", 10),
                             command=self.start_log)
        self.slogan.pack(side=LEFT)
        self.button = Button(frame,justify=LEFT,padx=10,
                             text="Close", fg="red",font=("Arial", 10),
                             command=root.destroy)
        self.button.pack(side=LEFT)
      def start_tool(self):
        import os
        os.startfile("netscan.exe")
      def start_log(self):
        import os
        os.startfile("log.txt")
        
    logfile2.close()    
    root = Tk()
    root.title("Fremde Hardware entdeckt!")
    app = App(root)
    root.mainloop()
BlackJack

@flambo: Du kannst mit der `after()`-Methode auf `Tkinter`-Widgets Code zeitverzögert aufrufen lassen.

Dein Quelltext sieht ziemlich wild aus. Klammern um Bedingungen bei ``if`` sind in Python unnötig. Die Bedingung liesse sich auch deutlich kompakter einfach als ``if untrusted and unknownlog:`` ausdrücken.

Die „Indexerei” bei `entry` ist ziemlich ausschweifend — das kann man sicher auch ohne ausdrücken. Zum Beispiel mit der `tuple()`-Funktion und mit Zeichenkettenformatierung. Zeichenketten und Werte mit ``+`` zusammen setzen ist BASIC und kein Python. ;-)

Die Definition der Klasse steht an einer eigenartigen Stelle. Und man käme hier auch ohne Klasse aus.

Importe sollten am Anfang des Moduls stehen, damit man sieht welche Abhängigkeiten es gibt.

Per Konvention wird pro Ebene um vier Leerzeichen eingerückt.
flambo
User
Beiträge: 10
Registriert: Mittwoch 7. März 2012, 15:05

BlackJack hat geschrieben:@flambo: Du kannst mit der `after()`-Methode auf `Tkinter`-Widgets Code zeitverzögert aufrufen lassen.
Hmm aber damit wird das Fenster nur zeitverzögert gestartet und nicht geschlossen. Oder sehe ich das falsch? Das Fenster soll schon sofort erscheinen aber nach einer bestimmten Zeit wieder verschwinden...

Übrigens ich bin ein Python-Anfänger und habe nicht wirklich viel Ahnung... xD Daher dieser wilde Code^^
BlackJack

@flambo: Du übergibst der Methode ein aufrufbares Objekt. Was da passiert ist also ganz Deine Sache. Du musst halt etwas aufrufen lassen was das Fenster schliesst.

Mal Deinen Quelltextabschnitt etwas sauberer (ungetestet):

Code: Alles auswählen

import os
import time
import Tkinter as tk
from functools import partial
from itertools import imap, izip

# 
# ...
# 

def main():
    # 
    # ...
    # 
    
    if untrusted and unknownlog:
        keys = [
            'IP-Address', 'Host-Name', 'MAC-Address', 'Response Time',
            'Logged User', 'Operating System', 'NIC-Vendor',
        ]
        texts = list()
        for entry in imap(tuple, unknownlog):
            texts.append(
                '\n'.join('%s:\t%s' % (k, v) for k, v in izip(keys, entry))
            )
            
            time_text = time.strftime('%d.%m.%Y um %H:%M:%S Uhr')
            csv_writer.writerow(
                (str(time.time()), time_text)
                + entry
                + ('not trusted',)
            )
        
        logfile2.close()
        
        root = tk.Tk()
        root.title('Fremde Hardware entdeckt!')
        
        tk.Label(
            root,
            text='ACHTUNG!! Es wurde fremde Hardware erkannt!',
            font=('Arial', 16)
        ).pack()
        tk.Label(
            root, justify=tk.LEFT, padx=20, text=time_text, font=('Arial', 11)
        ).pack()
        tk.Label(
            root,
            justify=tk.LEFT,
            padx=10,
            text='\n\n'.join(texts),
            font=('Arial', 11)
        ).pack()
        
        frame = Frame(root)
        frame.pack()
        tk.Button(
            frame,
            justify=tk.LEFT,
            padx=10,
            text='Mehr Informationen in Netscan',
            font=('Arial', 10),
            command=partial(os.startfile, 'netscan.exe')
        ).pack(side=tk.LEFT)
        tk.Button(
            frame,
            justify=tk.LEFT,
            padx=10,
            text='Log-File',
            font=('Arial', 10),
            command=partial(os.startfile, 'log.txt')
        ).pack(side=tk.LEFT)
        tk.Button(
            frame,
            justify=tk.LEFT,
            padx=10,
            text='Close',
            fg='red',
            font=('Arial', 10),
            command=root.destroy
        ).pack(side=tk.LEFT)

        root.mainloop()


if __name__ == '__main__':
    main()
Wobei man da sicher Teile von in Funktionen auslagern sollte. Selbst dieser ausschnitt ist für meinen Geschmack etwas zu lang und er macht zu viel verschiedenes.
mugen-Type-R
User
Beiträge: 4
Registriert: Sonntag 27. Juni 2010, 15:01

Vielleicht mit Timer probieren?
Beim Starten deines Scripts die Fkt. ende einbauen, dass diese auch gestartet wird.
Nach der eingegebener Zeit wird dann das Fenster geschloßen.
Falls zu lange dauern wird, kannst dann hinterher immer noch mit deinem Close-Button beenden.

Code: Alles auswählen

def ende():
  time.sleep(x) # -> Programm hält x Sekunden an bzw. wird dann nach Ablauf der Zeit geschloßen
  root.destroy()
nomnom
User
Beiträge: 487
Registriert: Mittwoch 19. Mai 2010, 16:25

Nein, das funktioniert schon mit `after`. Bei time.sleep() würde die Oberfläche einfrieren.

Code: Alles auswählen

import sys

from tkinter import *

root = Tk()
sign = Label(root, text='Hallo!')
sign.pack()
root.after(5000, sys.exit)
root.mainloop()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi flambo

Hier etwas zu herumspielen:

Code: Alles auswählen

import os
import time
import Tkinter as tk
   
INFO = "ACHTUNG!! Es wurde fremde Hardware erkannt!"
LOG_FETCH_CYCLE = 500 # 0.5s
APP_WIN_HIDE_TIME = 5000 # 5s
SIM_EVENT_TIME = 10000 # 10s
  
class App:
        
    def __init__(self, master):
        
        self.master = master
        
        self.untrusted = ''
        self.unknownlog = ''
        
        self.info_lab = tk.Label(master, text=INFO,font=("Arial", 16))
        self.info_lab.pack(padx=10, pady=5)
        
        self.time_var = tk.StringVar()
        self.time_label = tk.Label(master, justify='left', font=("Arial", 11),
            textvariable=self.time_var)
        self.time_label.pack(pady=5)
        
        self.data_var = tk.StringVar()
        self.data_label = tk.Label(master, justify='left', padx=10,
            font=("Arial", 11), textvariable=self.data_var)
        self.data_label.pack()
        
        frame = tk.Frame(master)
        frame.pack()
        
        self.slogan = tk.Button(frame,justify='left',padx=10,
            text="Mehr Informationen in Netscan",font=("Arial", 10),
            command=self.start_tool)
        self.slogan.pack(side='left')
        
        self.slogan = tk.Button(frame, justify='left', padx=10, text="Log-File",
            font=("Arial", 10), command=self.start_log)
        self.slogan.pack(side='left')
        
        self.button = tk.Button(frame, justify='left', padx=10, text="Close",
            fg="red",font=("Arial", 10), command=app_win.destroy)
        self.button.pack(side='left')
    
    def log_fetcher(self):
        if (len(self.untrusted) > 0) and (len(self.unknownlog) > 0):
            datenstr = ""
            self.deiconfy_app_win()
            for entry in self.unknownlog:
                t = time.strftime("%d.%m.%Y um %H:%M:%S Uhr")
                self.time_var.set(t)
                #timestamp = str(time.time())
                #daten = (timestamp,t,entry[0],entry[1],entry[2],entry[3],entry[4],entry[5],entry[6],"not trusted")
                #datenstr += "\n""\nIP-Address:\t"+entry[0]+"\nHost-Name:\t"+entry[1]+"\nMAC-Address:\t"+entry[2]+"\nResponse Time:\t"+entry[3]+"\nLogged User:\t"+entry[4]+"\nOperating System:\t"+entry[5]+"\nNIC-Vendor:\t"+entry[6]+"\n"
                #app.time_var.set(datenstr)
                #csvwriter1.writerow(daten)
            
            self.master.focus_force()
            self.hide_app_win()
            
            
            #~~ For simulation purpose only!    
            self.untrusted = ''
            self.unknownlog = ''
        print 'Fetch log'    
        self.master.after(LOG_FETCH_CYCLE, self.log_fetcher)

    def hide_app_win(self):
        self.master.after(APP_WIN_HIDE_TIME, self.master.withdraw)
        
    def deiconfy_app_win(self):
        self.master.deiconify()
            
    def start_tool(self):
        os.startfile("netscan.exe")
        
    def start_log(self):
        os.startfile("log.txt")

def log_event_simulator():
    #~~ For simulation purpose only!
    app.untrusted = 'True'
    app.unknownlog = 'True'
    
    app_win.after(SIM_EVENT_TIME,  log_event_simulator)
    
app_win = tk.Tk()
app_win.title("Fremde Hardware entdeckt!")

app = App(app_win)
app.log_fetcher()

log_event_simulator()
app.hide_app_win()

app_win.mainloop()
Das Hauptfenster wird 5s gezeigt. Verschwindet dann bis der Simulator nach weiteren 5s (insgesamt 10s) ein Log-Event auslöst. Die Anwendung läuft so zu sagen im Hintergrund. Kann nur durch aktivieren der Schaltfäche 'Close' abgeschalten werden!

Gruß wuf :wink:
Take it easy Mates!
flambo
User
Beiträge: 10
Registriert: Mittwoch 7. März 2012, 15:05

Phoa besten Dank für eure grosszügige Hilfe!! Ich habe es jetzt mit after gelöst und alle anderen Vorschläge werde ich auch noch ausprobieren.
Antworten