Schleife per Button beenden

Fragen zu Tkinter.
Antworten
DMD-OL
User
Beiträge: 168
Registriert: Samstag 26. Dezember 2015, 16:21
Wohnort: Oldenburg (Oldenburg)

Montag 8. Januar 2018, 20:13

hi leute,
nach schon bekommener Hilfe kann ich mein Problem leider immer noch nicht ganz lösen.
(viewtopic.php?f=1&t=41780&p=318904&hilit=DMD#p318904)

Mein Problem ist, daß ich gern eine for-Schleife per Button Click sofort beenden möchte (was sich leider für mich
als komplizierter rausstellt als erwartet.)
Ich habe da auch in weiteren Forumsbeiträgen nicht wirklich was gefunden. :(
Und zwar lese ich eine 3 GB große Textdatei von Datanorm (zur Erstellung einer Materialdatenbank)
ein und speicher diese Zeile für Zeile in eine Datenbank. Das Auslesen der Textdatei geschieht immer
Schrittweise mit 50000 bytes.
Leider bin ich kein Informatiker und damit auch ein wenig überfordert, da mir eine zündende Idee fehlt.
Mein bisheriger Laiencode:

Code: Alles auswählen

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

import Tkinter
import os
import ctypes
import codecs
from contextlib import closing
import fileinput
import tkMessageBox
import os.path
import sqlite3
import ttk
import datetime

user32 = ctypes.windll.user32
screenwidth = user32.GetSystemMetrics(0)
screenheight = user32.GetSystemMetrics(1)
middlewidth = user32.GetSystemMetrics(0)/2
middleheight = user32.GetSystemMetrics(1)/2

desktopFile = os.path.expanduser("~\\Desktop")
path_grund = ("\\").join([desktopFile,"Handy-Datenbank"])
fname = ("\\").join([path_grund,"DATANORM"])
path_folder = ("\\").join([path_grund,"DATENBANK"])
SQL_Stammdaten = '%s\\Material_Stammdaten.db' %(path_folder)

def stammdaten_Verwalten(fname,path_folder,SQL_Stammdaten):

    mat_fenster = Tkinter.Tk()
    mat_fenster.title('DMD-DATA.soft')
    verhael_width = float(screenwidth)/float(700)
    verhael_height = float(screenheight)/float(500)
    sizew = screenwidth / verhael_width
    sizeh =  screenheight / verhael_height
    a = middlewidth - (sizew/2) - 50
    b = middleheight - (sizeh/2) - 50
    mat_fenster.wm_geometry("%dx%d+%d+%d" % (sizew, sizeh, a, b))
    mat_fenster.attributes("-topmost", True)
    mat_fenster.attributes('-toolwindow', True)

    l_mat1 = Tkinter.Label(mat_fenster,text=("11. 'MATERIAL-STAMMDATEN'"), font=('Arial', 11, 'bold underline'))
    l_mat1.place(relx=.06, rely=.05, anchor="w")
    l_mat2 = Tkinter.Label(mat_fenster,text=('11.1. Material-Stammdaten updaten'), font=('Arial', 9, 'underline'))
    l_mat2.place(relx=.08, rely=.11, anchor="w")

    datanorm = Tkinter.StringVar()
    e_mat9 = Tkinter.Entry(mat_fenster,textvariable=datanorm, width=32, relief="sunken", borderwidth=3, fg='#000000000', justify='left')
    e_mat9.place(relx=.23, rely=.29, anchor="w")
    datanorm.set('DATANORM.002')

    def update_Datanorm(VariableName,lengthVar):
        def chunks(file,filesize,size):
            while 1:
                startat=fh.tell()
                fh.seek(size,1)
                data=fh.readline()
                yield startat,fh.tell()-startat
                if not data:
                    break

        nameDatei = VariableName.get()
        if len(nameDatei) != 0:
            verlauf = 0
            if (os.path.exists(fname)) == True:
                updateDatei = ("\\").join([fname,nameDatei])
                if os.path.isfile(updateDatei):
                    filesize = int(os.path.getsize(updateDatei))
                    size = 50000
                    try:
                        mat_fenster.destroy()
                    except:
                        pass

                    popup = Tkinter.Tk()
                    popup.title('DMD-DATA.soft')
                    verhael_width = float(screenwidth)/float(400)
                    verhael_height = float(screenheight)/float(260)
                    sizew = screenwidth / verhael_width
                    sizeh =  screenheight / verhael_height
                    a = middlewidth - (sizew/2) - 50
                    b = middleheight - (sizeh/2) - 50
                    popup.wm_geometry("%dx%d+%d+%d" % (sizew, sizeh, a, b))
                    popup.attributes("-topmost", True)

                    def popup_Abbrechen():

                        #mit Click auf diesen Button, würde ich gern die Schleife unten (for index in data:) abbrechen

                        popup.destroy()

                    b_pop1 = Tkinter.Button(popup, text=("Abbrechen"), width=15, font=('Arial', 9),
                    relief="raised", borderwidth=3, fg='#000000', justify='center',command=popup_Abbrechen)
                    b_pop1.place(relx=.5, rely=.85, anchor="c")

                    try:

                        #
                        #hier wird die Datenbank erstellt
                        #hab ich rausgelassen
                        #create_Stammdaten(SQL_Stammdaten)
                        #

                        con=sqlite3.connect(SQL_Stammdaten)
                        fh=codecs.open(updateDatei, 'rb', 'latin-1')
                        for ele in chunks(fh,filesize,size):
                            progressstart = int(ele[0])
                            progressend = int(ele[1])
                            kjsek = str(progressstart)+" byte(s) / "+str(filesize)+" byte(s)"

                            rest = filesize - progressstart
                            osejmx = str(progressend)+ " byte(s)"
                            if rest < progressend:
                                osejmx = str(rest)+ " byte(s)"

                            popup.update()
                            fh.seek(progressstart)
                            data=fh.read(progressend).splitlines()

                            #
                            #hier wird an eine Funktion zum Speichern in Datenbank: Stammdaten übergeben
                            #hab ich aber erstmal weggelassen ...
                            #

                            #als Ersatz dieses:
                            for index in data:
                                print index
                                #diese Schleife würde ich gern durch button click unterbrechen können



                        fh.close()
                        con.close()

                    except IOError as e:
                        print e

                    except Exception as e1:
                        print e1

            else:
                print "Die Datei existiert nicht"
        else:
           print "Das Eingabefeld darf nicht leer sein"

    b_mat11 = Tkinter.Button(mat_fenster, text = '--> Starten', width=12, relief="raised", borderwidth=3, fg="#000000", justify='center', command=lambda:update_Datanorm(datanorm,10))
    b_mat11.place(relx=.6, rely=.29, anchor="w")

    mat_fenster.mainloop()

stammdaten_Verwalten(fname,path_folder,SQL_Stammdaten)
Wie schon gesagt, würde ich gern per Click auf "Abbrechen" die for-Schleife beenden.
Kann ich die Schleife in einem Thread laufen lassen und dann den Thread beenden oder macht man das am Besten mit einer globalen Variablen???
Das Problem ist für mich das ich in Tkinter schrittweise eine Schleife öffne; d.h. das Fenster und die Schleife sollen beide gleichzeitig laufen und abgebrochen werden können.
Das Öffnen/Starten von Fenster und Schleifen funktioniert erstmal schon.
Sirius3
User
Beiträge: 7580
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 8. Januar 2018, 20:39

@DMD-OL: wie groß und wo ein Fenster liegt, sollte man dem Inhalt und dem System überlassen, vor allem dann, wenn man dafür so spezielle Funktionen braucht. Um zwei Elemente zusammenzufügen verwendet man nicht join mit einer expliziten zweielementigen Liste; und Pfade setzt man mit os.join zusammen. Warum verwendest Du für SQL_Stammdaten plötzlich %?

Nimm pack oder grid und nicht place. So funktioniert Dein Programm exakt nur auf Deinem System mit Deiner Bildschirmauflösung. Verschachtelte Funktionen sind selten sinnvoll, weil sie so nicht testbar sind. update_datamon, chunks, etc gehören alle auf Modulebene. Acht Einrückebenen sind dadurch auch definitiv zu viel.

Statt while 1 -> while True:. Strings mit format und nicht mit + zusammenstückeln.
Es darf nur ein Tk-Objekt geben, weitere Fenster mit TopLevel. Keine nakten excepts. Lies die Datei Zeilenweise und nicht so unendlich kompliziert chunkweise, dreifach mit seek und dem ganzen Quatsch.

So ist das unlesbar.

Nimm einen Thread statt update, frag regelmäßig nach einem Abbruch-Event, benutze keine Globalen Variablen.
Antworten