Kann nicht in entry klicken

Fragen zu Tkinter.
Antworten
Nergal53
User
Beiträge: 10
Registriert: Sonntag 15. September 2013, 08:26

Hallo,
ich habe mir eine kleine GUI programmiert und habe folgendes Problem.
Wenn ich mein Programm starte, kann ich mir wie gewollt einen Ordner auswählen.
Nachdem sich dieses Fenster zur Auswahl geschlossen hat, ist mein Hauptfenster aktiv.
In diesem Hauptfenster kann ich auch auf die Buttons drücken, aber nicht in die Entrys.
In die kann ich erst klicken, wenn ich zu einem anderem Fenster und wieder zurück gewechselt bin.
Wenn ich aber den Ordner nicht auswählen lasse am Anfang, dann funktioniert es.

Code: Alles auswählen

import tkinter as tk
import tkinter.messagebox as tkmessagebox
import tkinter.filedialog as tkfiledialog



def ask_direction(path_list, mainwindow):

    path = tkfiledialog.askdirectory(parent = mainwindow)
    path_list.append(path)
    return path_list


#method to close the mainwindow
def destroy_mainwindow(mainwindow):
    mainwindow.destroy()

#method to delete the given conten of an entry
def delete_text(event):

    try:
        int(event.widget.get())

    except ValueError:
        event.widget.delete(0,tk.END)
        event.widget.configure(foreground = "black")
        event.widget.configure(background = "white")

def cancle(input_list, path_list, mainwindow):

    del input_list[:]
    del path_list[:]
    destroy_mainwindow(mainwindow)


#method which checks that all entrys filled with integers
#in that case it store them in the inputlist
#otherwise show the user that there was a wrong or incomplete input
def check_content(entry_list, input_list,  path_list, mainwindow):

    error = False
    i = 0
    del input_list[:]

    for entry in entry_list:

        content = entry.get()
        try:
            int(content)
            entry.configure(background = "white")
            input_list.insert(i, content)

        except ValueError:
            if (error == False):
                tkmessagebox.showerror("Falsche Eingabe","Es wurde kein Zahlenwert eingebenn")

            entry.configure(background = "red")
            error = True

        i += 1

        if (len(path_list) == 0 and error == False):
            tkmessagebox.showerror("Kein Quellordner", "Es wurde kein Quellordner ausgewählt")
            error = True


        elif (len(input_list) == len(entry_list) and error == False):
            tkmessagebox.showinfo("Vorgang Abgeschlossen", "Eingaben erfolgreich gespeichert")
            destroy_mainwindow(mainwindow)

    return input_list

#method to create the nessecary entrys with their functions
def create_entrys(on_frame_place, name_list, label_list, input_list, path_list, mainwindow):

   entry_list = []

   for name in name_list:
      fra = tk.Frame(on_frame_place)
      lab = tk.Label(fra,  text = label_list[name_list.index(name)])
      ent = tk.Entry(fra, width = 20, foreground = "grey", state = "normal")
      ent.insert(tk.END, "Hier Wert eingeben")
      ent.bind("<FocusIn>", delete_text)
      ent.bind("<Return>", lambda event: check_content(entry_list, input_list, path_list, mainwindow))
      fra.pack()
      lab.pack(side = "top", padx = 3, pady = 3)
      ent.pack(side = "bottom", padx = 3, pady = 3)
      entry_list.append(ent)

   return entry_list

def create_inputwindow(name_list, label_list, input_list, path_list):
    #create and place mainwindow
    root = tk.Tk()
    root.title("Parameterabfrage")
    root.geometry('450x225+600+300')
    ask_direction(path_list, root) #Wenn die Zeile auskommentiert ist funktioniert es!!!!!!!!!
    #frames to place all correctly
    fbuttons = tk.Frame(root)
    fentrys = tk.Frame(root)

    #create entrys and labels
    entry_for_parameter_list = create_entrys(fentrys, name_list, label_list, input_list, path_list, root)

    #button to select startfolder
    buttonchangdir = tk.Button(fbuttons, text = "Quellordner ändern", width = 20, command = lambda: ask_direction(path_list, root))
    buttonchangdir.bind("<Return>", lambda event: ask_direction(path_list, root))
    buttonchangdir.pack(side = "top", padx = 10, pady = 10)

    #assume-button
    buttonassume = tk.Button(fbuttons, text = "Übernehmen", width = 20, command = lambda:(check_content(entry_for_parameter_list, input_list, path_list, root)))
    buttonassume.bind("<Return>", lambda event: check_content(entry_for_parameter_list, input_list, path_list, root))
    buttonassume.pack(side = "top", padx = 10, pady = 10)

    #cancle-button with function
    buttoncancle = tk.Button(fbuttons, text ="Abbrechen", width= 20,command = lambda: cancle(input_list, path_list, root))
    buttoncancle.bind("<Return>", lambda event: cancle(input_list, path_list, root))
    buttoncancle.pack(side = "bottom", padx = 10, pady = 10)

    #show buttonframe and entryframe 
    fentrys.pack(side = "left")
    fbuttons.pack(side = "right")

    #infinite loop
    root.mainloop()

    return input_list, path_list 

input_parameter_list = []
startpath_list = []
#startpath = tkfiledialog.askdirectory()
#startpath_list.append(startpath)
#list of paramters whitch the user have to define
#names begin with an "e" becuase that are the names of the entrys
entry_name_list = ["efeeder", "espindelrpm", "etool", "edrillingdepth"]
#list of questions to interact with the user
question_list = ["Welchen Vorschub soll die Spindel haben?",
             "Welche Drehzahl soll die Spidel haben?",
             "Welche Werkzeugnummer soll verwendet werden?",
             "Wie tief soll das Bohrloch werden? (Plattenstärke)"]

input_parameter_list, startpath_list = create_inputwindow(entry_name_list, question_list, input_parameter_list, startpath_list)
Benutzeravatar
pillmuncher
User
Beiträge: 1531
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Ich hab es unter Windows mit Python 3.3 und unter cygwin/vcxsrv mit Python 3.2 laufen lassen und nirgends trat der von dir beschriebene Fehler auf.

Allerdings tritt ein anderer Fehler auf: Wenn ich in ein Feld eine Zahl eingebe und anschließend den Mauszeiger über ein anderes Fenster bewege, dann wird, wenn ich ihn wieder zurück auf das Mainwindow schiebe, die Zahl gelöscht. Allerdings nur unter cygwin.

Anmerkungen zum Code:

Statt auf len(bla) == 0 solltest du auf not bla testen. Das ist das in Python übliche Idiom. Und auf keinen Fall solltest du auf blubb == False testen, sondern auf not blubb. Viele Werte sind nämlich nicht gleich False, können aber trotzdem - mittels bool() - zu False ausgewertet werden:

Code: Alles auswählen

>>> bool(0)
False
>>> bool("")
False
>>> bool([])
False
Beim if-Satement wird hinter den Kulissen automatisch bool() aufgerufen, sofern der abgefragte Wert selbst kein Boolean ist.

Statt selber eine Zählvariable zu initialisieren und inkrementieren kannst du auch einfach enumerate() verwenden. Also statt:

Code: Alles auswählen

    i = 0
    ... 
    for entry in entry_list:
        ...
            input_list.insert(i, content)
        ...
        i += 1
lieber

Code: Alles auswählen

    for i, entry in enumerate(entry_list):
        ...
            input_list.insert(i, content)
Oder verwende gleich input_list.append(content), denn du fügst sowieso immer nur am Ende an. Dann brauchst du auch keine Zählvariable.

Funktionen, die übergebene Datenstrukturen ändern, und diese dann zusätzlich als Ergebnis zurückliefern, sind sonderbar. Würde ich versuchen anders zu lösen.

Insgesamt ist der Code recht byzantinisch. Ich kann zB. nicht den Vorteil von

Code: Alles auswählen

def destroy_mainwindow(mainwindow):
    mainwindow.destroy()
...
        elif ...:
            tkmessagebox.showinfo(...)
            destroy_mainwindow(mainwindow)
gegenüber

Code: Alles auswählen

        elif ...:
            tkmessagebox.showinfo(...)
            mainwindow.destroy()
erkennen.

Und assume heißt zwar annehmen, aber nicht im Sinne von Ich nehme die Wahl zur Kanzlerin der Bundesrepublik Deutschland an, sondern im Sinne von Ich nehme an, dass es nach Angela Merkel noch andere Bundeskanzler geben wird. Annehmen im Sinne von akzeptieren heißt natürlich accept.
In specifications, Murphy's Law supersedes Ohm's.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

pillmuncher hat geschrieben:Und assume heißt zwar annehmen, aber nicht im Sinne von Ich nehme die Wahl zur Kanzlerin der Bundesrepublik Deutschland an, sondern im Sinne von Ich nehme an, dass es nach Angela Merkel noch andere Bundeskanzler geben wird. Annehmen im Sinne von akzeptieren heißt natürlich accept.
Im Umfeld von GUIs ist hier die Bezeichnung "apply" üblich.
Das Leben ist wie ein Tennisball.
Nergal53
User
Beiträge: 10
Registriert: Sonntag 15. September 2013, 08:26

Hallo,
erstmal Danke für euere Hilfe.
Die Anmerkungen:
pillmuncher hat geschrieben:Statt auf len(bla) == 0 solltest du auf not bla testen. Das ist das in Python übliche Idiom. Und auf keinen Fall solltest du auf blubb == False testen, sondern auf not blubb. Viele Werte sind nämlich nicht gleich False, können aber trotzdem - mittels bool() - zu False ausgewertet werden:
pillmuncher hat geschrieben:Oder verwende gleich input_list.append(content), denn du fügst sowieso immer nur am Ende an. Dann brauchst du auch keine Zählvariable.
EyDu hat geschrieben:Im Umfeld von GUIs ist hier die Bezeichnung "apply" üblich.
habe ich geändert.

die Methode destroy_mainwindow habe ich entfernt.

Aber leider tritt mein ursprüngliches Problem immer noch auf.
Ich verwende Python 3.3, als Editor Spyder und als Betriebssystem Windows 7.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Nergal53

Kannst du dein Skript mit folgender Änderung ausprobieren?:

Code: Alles auswählen

def ask_direction(path_list, mainwindow):
 
    path = tkfiledialog.askdirectory(parent = mainwindow)
    mainwindow.focus_force()
    path_list.append(path)
    return path_list
Gruss wuf :wink:
Take it easy Mates!
Nergal53
User
Beiträge: 10
Registriert: Sonntag 15. September 2013, 08:26

Danke damit funktioniert es :D :D :D :D
Antworten