GUI permanent geöffnet lassen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Zubi
User
Beiträge: 10
Registriert: Donnerstag 29. November 2018, 13:35

Hallo zusammen,

ich habe ein Problem mit meiner GUI:
Wenn ich mein Programm aus dem Terminal öffne und ich durch ein Button ein Unterfenster öffne, dieses dann wieder schließe, beendet sich das komplette Programm und ich muss es wieder neu starten.
Ich möchte aber, dass das Hauptfenster permanent offen bleibt.

Ich hab am ende des Programms schon ein hauptFenster.mainloop() drin deshalb verwundert mich das etwas.

Ich hoffe jemand von euch kann mir weiterhelfen.

LG Zubi
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Zubi: Da machst Du wohl irgendetwas falsch in dem Programm das wir nicht kennen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Zubi
User
Beiträge: 10
Registriert: Donnerstag 29. November 2018, 13:35

Na dann hier mal das Programm:

Code: Alles auswählen

#-*- coding: utf-8 -*-

from Tkinter import *
from tkMessageBox import *
#from tkinter import *
#from tkinter.messagebox import *
#from tkinter import messagebox

import time
import math
import csv
import os
import pigpio
import codecs
import sys
import unicodecsv as csv

stdout_encoding = sys.stdout.encoding or sys.getfilesystemencoding()
fs_encoding = sys.getfilesystemencoding()

from neopixel import *

LED_COUNT = 40
LED_PIN = 18
LED_FREQ_HZ = 800000
LED_DMA = 5
LED_BRIGHTNESS = 255
LED_INVERT = False

strip = Adafruit_NeoPixel (LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS)
strip.begin()

csv.DictWriter.writerow = lambda self, row: self.writer.writerow([f.encode('utf-8') for f in self._dict_to_list(row)])

#--------Ereignisbehandlung----------------------

global input_num

#--------------------LED's Ansteuern-------------------------

def led(fach):
    with open("LED_Matrix.csv", "r") as file:
        for line in file:
            leddata = line.strip().split(";")
            
            if fach in leddata:
                a = leddata[1]
                b = leddata[2]
                break
    print(a)
    print(b)
        
    #for i in range (a, b):
        #strip.setPixelColorRGB(i,255,0,0)
        #strip.show()
        
#----------------------Alle LED's AUS-------------------------
        
def ledOut():
    print("LED AUS")
    for i in range (LED_COUNT):
        strip.setPixelColorRGB(i,0,0,0)
        strip.show()

#-----------------------Neuen Artikel anlegen----------------------
    
def new():                                          
    def quit():
        eingabeFenster.quit()
        eingabeFenster.destroy()
        
    def check():
        with codecs.open("Artikel.csv", "r", "utf-8") as csvfile:      #Datei wird zum lesen geoeffnet
    
            for line in csvfile:                       #Alle Daten in der CSV-Datei durchgehen
                
                data = line.strip().split(";")      #Daten in eine Liste umformen und an ; Trennen
                if entryNumber.get() in data or entryKoordinate.get() in data:       #ist eingegebene Artikelnummer in der Liste "data"
                    
                    vorhanden()                     #fenster mit dem hinweis dass Artikel schon vorhanden
                    eingabeFenster.quit()           #Eingabefenster wird wieder geschlossen
                    eingabeFenster.destroy()        # "
                    break
        with open ("Artikel.csv", "ab") as csvfile:
            fieldnames = ["Fachkoordinate", "Artikelnummer"]
            writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=";")
            writer.writerow({"Fachkoordinate": entryKoordinate.get(), "Artikelnummer": entryNumber.get()})
            showinfo('Hinweis', 'Artikel wurde angelegt')
                    
            eingabeFenster.quit()
            eingabeFenster.destroy()
            
    #, "utf-8"
    #------------------Neue Artikelnummer anlegen--------------------------------------
    
    eingabeFenster=Toplevel(hauptFenster)   # Mit der Class Toplevel ein neues Fenster oeffnen
    eingabeFenster.title("Eingabe neuer Artikel") # Titel des neuen Fensters bestimmen
    eingabeFenster.geometry("600x300")  # Groesse des Fensters festlegen
    checkButton=Button(eingabeFenster, text=u"Bestätigen", fg="black", bg="green", font="Verdana 20", command=check)   
    checkButton.place(x=20, y=200, width=210, height=50)
    quitButton=Button(eingabeFenster, text="Abbruch", fg="black", bg="red", font="Verdana 20", command=quit)   
    quitButton.place(x=350, y=200, width=210, height=50)
    entryKoordinate = Entry(master=eingabeFenster, font='Verdana 20', relief='raised', takefocus='')   
    entryKoordinate.place(x=290, y=20, width=300, height=40)
    entryNumber = Entry(master=eingabeFenster, font='Verdana 20', relief='raised', takefocus='')   
    entryNumber.place(x=290, y=80, width=300, height=40)
    fachLabel=Label(eingabeFenster, text="Fach", fg="white", bg="dark blue", font="Verdana 18")
    fachLabel.place(x=10, y=20, width=200, height=40)
    artikelLabel=Label(eingabeFenster, text="Artikelnummer", fg="white", bg="dark blue", font="Verdana 18")
    artikelLabel.place(x=10, y=80, width=200, height=40)
      
def vorhanden():
    showinfo('Hinweis','Artikel bereits vorhanden!')
    
def ArtikelnichtVorhanden():
    showinfo("Hinweis", "Artikel Nicht vorhanden!")

#---------------------Artikel und Fach Loeschen------------------------------
def delete():
    if askyesno('Hinweis', u'Artikel wirklich löschen?'):
        artikel = entrynumberscanLabel.get()
        with codecs.open("Artikel.csv", "r", "utf-8") as csvfile:      #Datei wird zum lesen geoeffnet
            for line in csvfile:                       #Alle Daten in der CSV-Datei durchgehen
                data = line.strip().split(";")      #Daten in eine Liste umformen und an "," Trennen
    
                if artikel in data:                 #wenn Artikel gefunden wird dieser uebersprungen und nicht in Backup geschrieben
                    continue
                else:
                    with open("Backup_Artikel.csv", "ab") as csvfile:    #Backupdatei wird erstellt ohne den zu loeschenden Artikel
                        fieldnames = ["Fachkoordinate", "Artikelnummer"]
                        writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=";")
                        writer.writerow({"Fachkoordinate": data[0], "Artikelnummer": data[1]})
            
            os.remove("Artikel.csv")                #Alte Artikel-Datenbank wird geloescht      
                       
        with codecs.open("Backup_Artikel.csv", "r", "utf-8") as csvfile:
            for line in csvfile:
                data = line.strip().split(";")
                
               
                with open("Artikel.csv", "ab") as csvfile:   #Neue Artikel-Datenbank wird erstellt
                    fieldnames = ["Fachkoordinate", "Artikelnummer"]
                    writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=";")
                    writer.writerow({"Fachkoordinate": data[0], "Artikelnummer": data[1]})
                                
        os.remove("Backup_Artikel.csv")                 #Backup wird wieder geloescht
        showinfo("Hinweis", u"Artikel wurde gelöscht")
        entrynumberscanLabel.delete(0,END)   
                
    else:
        showinfo('Nein', 'Abgebrochen')
    
#-----------------reaktion auf Tastatureingabe-----------------------
    
def key(event):
    if(event.char != chr(13)):
        input_num.set(input_num.get() + event.char)
        num.set(input_num.get())
    else:
        num.set(input_num.get())
        input_num.set('')

#------------------Artikel suchen / Regalfach Suchen------------------
        
def search():
    
    ledOut()                                   #Bei erneuter Suche LED -> AUS
    lastcoo.set(coo.get())
    artikel = entrynumberscanLabel.get()
    i = False
    with codecs.open("Artikel.csv", "r", "utf-8") as csvfile:      #Datei wird zum lesen geoeffnet
        for line in csvfile:                       #Alle Daten in der CSV-Datei durchgehen
            data = line.strip().split(";")      #Daten in eine Liste umformen und an ; Trennen
            
            if artikel in data:                 #ist eingegebene Artikelnummer in der Liste "data"
                coo.set(data[0])                #laesst Fach in GUI anzeigen
                led(data[0])
                i = True
                break
            else:
                continue                        
            
        if i == False:
            ArtikelnichtVorhanden()
            
    entrynumberscanLabel.delete(0,END)
    
     
def handsearch():
    def handquit():
        eingabeFenster.quit()
        eingabeFenster.destroy()
        
    def handcheck():
        with codecs.open("Artikel.csv", "r", "utf-8") as csvfile:
            for line in csvfile:
                data = line.strip().split(";")
                
                if handentryNumber.get() in data[1]:
                    handcoo.set(data[0])
                    handnum.set(data[1])
                    break
                else:
                    ArtikelnichtVorhanden()
                    break
                    
            handentryNumber.delete(0,END)
                    
        
    eingabeFenster=Toplevel(hauptFenster)   # Mit der Class Toplevel ein neues Fenster oeffnen
    eingabeFenster.title("Artikel von Hand Eingeben") # Titel des neuen Fensters bestimmen
    eingabeFenster.geometry("1180x700")  # Groesse des Fenster festlegen
    
#-----------------------Artikelnummer Eingabe--------------------------------    

    handartikelLabel=Label(eingabeFenster, text="Eingabe Artikelnummer", fg="white", bg="dark blue", font="Verdana 18")
    handartikelLabel.place(x=10, y=20, width=300, height=80)
    handentryNumber = Entry(master=eingabeFenster, font='Verdana 28', relief='raised', takefocus='')   
    handentryNumber.place(x=350, y=20, width=400, height=80)
    handcheckButton=Button(eingabeFenster, text="Suchen", fg="black", bg="green", font="Verdana 20", command=handcheck)  
    handcheckButton.place(x=790, y=20, width=250, height=80)

#-----------------------Fachbezeichnung Ausgabe---------------------------------

    handfachLabel=Label(eingabeFenster, text="Fachbezeichnung", fg="white", bg="dark blue", font="Verdana 18")
    handfachLabel.place(x=10, y=200, width=300, height=80)
    handcoordinateLabel=Label(eingabeFenster, textvariable= handcoo, fg="black", bg="white", font="Verdana 28", relief="groove")
    handcoordinateLabel.place(x=350, y=200, width=400, height=80)
    handquitButton=Button(eingabeFenster, text="Abbruch", fg="black", bg="red", font="Verdana 20", command=handquit)   
    handquitButton.place(x=790, y=200, width=250, height=80)
    
#----------------------Ausgabe Vollstaendige Artikelinformation-------------------
    
    handfachLabel2=Label(eingabeFenster, text="Ausgabe der ganzen Artikelinformation", fg="white", bg="dark blue", font="Verdana 18")
    handfachLabel2.place(x=10, y=400, width=1160, height=80)
    handnumberLabel=Label(eingabeFenster, textvariable= handnum, fg="black", bg="white", font="Verdana 16", relief="groove")
    handnumberLabel.place(x=10, y=500, width=1160, height=80)

#-------Hauptfenster initalisieren---------------------
#Bildschirmaufloesung 10"  1280x800 Pixel

hauptFenster =Tk( )                                 # Erstellen eines Hauptfenster
hauptFenster.title(u"POD Aufträge")                  # Fenster benannt
hauptFenster.geometry("1180x700")                   # Aufloesung angepasst
hauptFenster.bind("<Key>", key)                     # Tastatur mit einbinden

#------------Variablen initalisieren------------------------

num=StringVar()
coo=StringVar()
input_num = StringVar()
lastcoo=StringVar()
handcoo=StringVar()
handnum=StringVar()

#------------Frames erstellen----------------------------

leftFrame=Frame (hauptFenster) # Linker Frame
rightFrame=Frame (hauptFenster) # Rechter Frame

#-----------Buttons erstellen---------------------------

deleteButton=Button (leftFrame, text="Artikel entfernen", fg="black", bg="red", font="Verdana 22", command=delete)
deleteButton.place(x=10, y=10, width=300, height=130)

newButton=Button(leftFrame, text="Artikel neu anlegen", fg="black", bg="green", font="Verdana 22", command=new)
newButton.place(x=10, y=190, width=300, height=130)

handsearchButton=Button(rightFrame, text="Tastatureingabe", fg="black", bg="orange", font="Verdana 20", command=handsearch)   
handsearchButton.place(x=10, y=400, width=600, height=70)

#-------------Labels erstellen-------------------------------

rightFrame.place(x=500, y=10, width=700, height=700)
leftFrame.place(x=10, y=10, width=480, height=700)

numberLabel=Label(rightFrame, text="Artikelnummer", fg="white", bg="dark blue", font="Verdana 28")
numberLabel.place(x=10, y=10, width=600, height=50)

coordinateLabel=Label(rightFrame, text="Koordinate Regal", fg="white", bg="dark blue", font="Verdana 28")
coordinateLabel.place(x=10, y=240, width=600, height=50)

entrynumberscanLabel = Entry(master=hauptFenster, font='Verdana 28', relief='raised', takefocus='')
entrynumberscanLabel.place(x=510, y=80, width=600, height=70)

searchButton=Button(hauptFenster, text="Suchen", fg="black", bg="green", font="Verdana 20", command=search)   
searchButton.place(x=700, y=170, width=210, height=50)

coordinatescanLabel=Label(rightFrame, textvariable= coo, fg="black", bg="white", font="Verdana 28", relief="groove")
coordinatescanLabel.place(x=10, y=300, width=600, height=70)

lastKoordinate=Label(leftFrame, text="Letzter Artikel", fg="white", bg="dark blue", font="Verdana 15")
lastKoordinate.place(x=10, y=370, width=300, height=30)

lastcooLabel=Label(leftFrame, textvariable= lastcoo, fg="black", bg="white", font="Verdana 20", relief="groove")
lastcooLabel.place(x=10, y=410, width=300, height=70)

#------------------Images initalisieren------------------------

logo2=PhotoImage(file="festoolLang")
festoolLanglogo=Label(hauptFenster, image=logo2)
festoolLanglogo.place(x=200, y=550)

#-------------------------------Befehl fuer Endlosschleife----------------------------------------------
hauptFenster.mainloop()
Zubi
User
Beiträge: 10
Registriert: Donnerstag 29. November 2018, 13:35

Hab meinen Fehler gefunden:
Der Befehl "eingabeFenster.quit()" ist zu viel.

Nachdem ich diesen raus genommen habe lief es einwandfrei.

LG Zubi
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Zubi: Die Behandlung von CSV-Dateien ist ziemlich kaputt. Zuerst einmal solltest Du Dich zwischen dem `csv`-Modul aus der Standardbibliothek und `unicodecsv.csv` entscheiden. Momentan importierst Du effektiv `unicodecsv.csv` und benutzt das nicht nur falsch, sondern hast dann auch noch einen „monkey patch“ für das `csv`-Modul aus der Standardbibliothek im Programm der `DictWriter.writerow()` überschreibt. Das ist schon so ein bisschen Glück, dass das überhaupt funktioniert, weil der von Interna gebrauch macht, die so nicht da sein müssen, insbesondere nicht in einem anderen Modul als dem für den dieser Patch gedacht war. Ich würde `unicode.csv` verwenden und dass dann aber auch richtig.

Und dann wird das nur zum schreiben von CSV-Dateien verwendet. Gelesen werden die im Programm zwar auch an vielen Stellen, da dann aber ohne Modul sondern einfach als Textdateien und mit ``split(';')``-Aufrufen. Warum? Auch hier sollte man sich für *einen* Weg entscheiden.

Sternchen-Importe sind Böse™. Damit kann man sich sonstwas ins aktuelle Modul holen (Namenskollisionen) und der Code wird schwerer nachvollziehbar, weil man nicht mehr sieht was woher kommt.

Die Module `csv`, `math`, `time`, und `pigpio` werden importiert, aber nicht verwendet. `sys` wird importiert, aber auch nicht wirklich verwendet. Die Werte die damit bestimmt werden, werden ihrerseits nämlich nirgends verwendet. `codecs` wird nur gebraucht weil `unicodecsv.cvs` nicht konsequent und richtig verwendet wird.

Es werden kaum wirklich Funktionen verwendet. Diese Mischung aus globalen Variablen und lokalen Funktionen ist undurchsichtig und fehleranfällig und sollte durch objektorientierte Programmierung ersetzt werden.

`place()` mit absoluten Positions- und Grössenangaben ist der absolute Horror. Das sieht nur auf der Hardware mit den Einstellungen auf denen man das programmiert hat, genau so aus wie man will. Ändert sich etwas an diesen Rahmenbedingungen, kann die GUI nicht nur schlecht aussehen, sondern im Extremfall sogar unbenutzbar werden. Änderungen am Layout mutieren ganz schnell zu viel Handarbeit weil alles angepasst werden muss, was direkt oder indirekt von der Änderung betroffen ist.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Zubi
User
Beiträge: 10
Registriert: Donnerstag 29. November 2018, 13:35

@_blackjack_: erstmal vielen Dank für deine ausführliche Antwort ich finde es super das es Menschen wie dich gibt die sich die Zeit nehmen ihr Wissen zu teilen!

Mir ist sehr wohl bewusst dass mein Programm nicht gerade das ist was man hohe Programmierkunst nennt ;) aber da es mein erstes Pythonprogramm ist das ich geschrieben hab und es auch noch funktioniert bin ich erstmal recht zufrieden.

Da es jetzt alles macht was ich will werde ich mich an die Schönheits-OP machen und mir dabei deine Ratschläge zu herzen nehmen!

Nochmal Danke und Viel Grüße
Zubi
Antworten