Hilfe bei erstellen und Weiterverarbeitung eines Textfeldes

Fragen zu Tkinter.
Antworten
Benutzeravatar
Dirki
User
Beiträge: 40
Registriert: Donnerstag 23. Juni 2016, 16:11

Sonntag 10. Juli 2016, 12:09

Hallo zusammen!

Da mein letzes Skript so läuft wie ich es mir gewünscht habe, versuche ich mich an mein nächstes Projekt.
Obwohl das Buch eigentlich super ist, fehlt mir super viel zum Verständnis von tkinter im Zusammenhang mit der Weiterverarbeitung von Variablen in neue Funktionen.

Hier ist mal der Ansatz von meinem Skript. Ich stehe noch am Anfang. Die Kommentare sind für mich, damit ich den Überblick behalte. Die verschwinden noch. Wie gesagt, das Skript ist noch am Anfang, da ich versuche erst die leichten Funktionen zu begreifen und mich im Schwierigkeitsgrad nach oben zu bewegen. ;)

Code: Alles auswählen

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

import tkinter, tkinter.messagebox

def ende():
    main.destroy()

def testfenster():
    tkinter.messagebox.showinfo("Test","Das ist eine Testmeldung!!!")

def schliessen():
    schliessen = tkinter.messagebox.askyesno("Schließen?", "Soll das Programm geschlossen werden? Ggf. nicht gespeicherte Daten können verloren gehen!")
    if schliessen == 1:
        ende()
    else:
        pass

def about():
    tkinter.messagebox.showinfo("Über", "CD-Box Version 0.001 \n"
                                        "(c) blabla")


def ask_new_database():
    eingabe = e.get()
    e = tkinter.Entry(e)
    e.pack
    dbname = tkinter.Label(e)
    bdbname = tkinter.Button(e, text="OK", command = new_database)

def new_database():
    pass
    # hier soll die Funktion zum erstellen einer Datenbank entstehen


main = tkinter.Tk()
main.title("CD-Box")

# Zielobjekt der Menubefehle
fr = tkinter.Frame(main, height=300, width=600,
                   bg="#FFFFFF", bd=10)
fr.pack()

# erzeugt gesamte Menuleiste
mBar = tkinter.Menu(main)

# erzeugt erstes Menuobjekt der Menuleiste
mFile = tkinter.Menu(mBar)

# erzeugt Elemente in erstem Menu
mFile.add_command(label="Neu", command=ask_new_database)
mFile.add_command(label="Laden")
mFile.add_command(label="Speichern")
mFile.add_separator()
mFile.add_command(label="Beenden", command=schliessen)


# erzeugt zweites Menuobjekt der Menuleiste
mView = tkinter.Menu(mBar)
mView["tearoff"] = 0     # Menu nicht abtrennbar

mInfo = tkinter.Menu(mBar)

mInfo.add_command(label="About", command=about)



# erstes und zweites Menu zur Menuleiste hinzu
mBar.add_cascade(label="Datei", menu=mFile)

mBar.add_cascade(label="?", menu=mInfo)

# gesamte Menuleiste zu Fenster hinzu
main["menu"] = mBar

main.mainloop()
Mein Problem:
Wenn ich auf Datei --> Neu klicke möchte ich die Funktion "ask_new_database()" aufrufen, in der Ich nach dem Dateinamen frage... ja und dann möchte ich entweder in dieser funktion eine sqlite datenbank erstellen, oder eine neue Funktion aufrufen, die das erledigt.

Aber wie gesagt, ich verstehe nicht, wie ich die Information aus der Eingabemaske weiterberarbeite. Kann mir einer von euch Python-Göttern da mal weiterhelfen und mir das eventuell auch direkt mal genauer erklären? So das ich nicht nur im Skript weiterkomme, sondern auch verstehe was da passiert?

Ich danke euch schon mal vielmals!
Zuletzt geändert von Anonymous am Sonntag 10. Juli 2016, 12:52, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

Sonntag 10. Juli 2016, 13:02

@Dirki: Wenn Du erst die leichten Funktionen begreifen möchtest, und Dich dann im Schwierigkeitsgrad nach oben zu bewegen, dann solltest Du besser nicht mit GUI-Programmierung anfangen. Du verwendest Funktionen noch nicht so wie sie gedacht sind, willst aber schon mit GUIs etwas machen was nicht nur Funktionen, sondern objektorientierte Programmierung (OOP) erfordert.

Funktionen sollten alle Werte mit denen sie arbeiten (ausser Konstanten) als Argumente übergeben bekommen und falls es Ergebnisse gibt, diese als Rückgabewerte an den Aufrufer zurückgeben. Dann braucht man auf Modulebene keine Variablen mehr, und kann das Hauptprogramm ebenfalls in eine Funktion stecken. So hat man mehr Überblick wo welcher Wert verändert oder zugewiesen wird und kann Funktionen einzeln nachvollziehen, ohne den ganzen Rest des Programms kennen zu müssen.

Um das mit GUIs und Funktionsaufrufen zu kombinieren die einen Zustand über Aufrufe hinweg behalten müssen, braucht man OOP. Man kann versuchen sich mit Datenstrukturen und Closures, z.B. mittels `functools.partial()`, zu behelfen, aber zum einen skaliert das nicht wirklich gut, und zum anderen ist OOP in einer objektorientierten Sprache wie Python die offensichtlichere Lösung für das Problem.
BlackJack

Montag 11. Juli 2016, 10:50

Bei der Namensgebung sollte man nicht abkürzen (`fr` statt `frame`) oder kryptische Präfixe verwenden (`mFile` statt `file_menu`).

`messagebox.askyesno()` gibt einen Wahrheitswert zurück, den sollte man nicht noch mal explizit vergleichen, den kann man gleich verwenden.

`destroy()` ist dazu da Fenster zu ”zerstören”. Wenn man die Tk-Hauptschleife beenden möchte, sollte man besser die `quit()`-Methode verwenden.

``if``- oder ``else``-Zweige in denen nur ``pass`` steht, sind sinnfrei.

`ask_new_database()` kann so nicht funktionieren. Du hast da in der ersten Zeile ``e.get()`` stehen, zu dem Zeitpunkt ist `e` aber noch gar nicht definiert. Dann versuchst Du ein Entry zu erstellen mit dem nicht existierenden `e` als Elternwidget. Danach steht ein `pack` ohne die Klammern dass das auch wirklich *aufgerufen* wird. Danach erstellst Du ein `Label` wieder mit `e` als Elternwidget und ohne Text. Das funktioniert so alles nicht.

Wenn es das täte, hättest Du das nächste Problem, dass Du nun ein Eingabefeld und eine Schaltfläche hättest, und alles weiterhin aktiv ist. Du könntest den Menüpunkt Datei → Neu also durchaus noch mal wählen und es würde wieder `ask_new_database()` aufgerufen was dann noch ein Eingabefeld und noch eine Schaltfläche erstellen wird.

An der Stelle würde man eher einen Dialog öffnen der den Benutzer nach den Datenbanknamen fragt. `tkinter.simpledialog` hat da schon ein paar vorbereitete Sachen.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from functools import partial
import tkinter as tk
from tkinter import messagebox, simpledialog


def schliessen(root):
    antwort = messagebox.askyesno(
        'Schließen?',
        'Soll das Programm geschlossen werden?'
        ' Ggf. nicht gespeicherte Daten können verloren gehen!'
    )
    if antwort:
        root.quit()
 

def about():
    messagebox.showinfo('Über', 'CD-Box Version 0.001 \n(c) blabla')
 
 
def ask_new_database():
    database_name = simpledialog.askstring(
        'Datenbankname', 'Name für die neue Datenbank?'
    )
    if database_name:
        new_database(database_name)
 

def new_database(database_name):
    # hier soll die Funktion zum erstellen einer Datenbank entstehen
    pass
 

def main(): 
    root = tk.Tk()
    root.title('CD-Box')
     
    # Zielobjekt der Menubefehle
    frame = tk.Frame(root, height=300, width=600, bg='white', bd=10)
    frame.pack()
     
    # erzeugt gesamte Menuleiste
    menu = tk.Menu(root)
     
    # erzeugt erstes Menuobjekt der Menuleiste
    file_menu = tk.Menu(menu)
     
    # erzeugt Elemente in erstem Menu
    file_menu.add_command(label='Neu', command=ask_new_database)
    file_menu.add_command(label='Laden')
    file_menu.add_command(label='Speichern')
    file_menu.add_separator()
    file_menu.add_command(label='Beenden', command=partial(schliessen, root))

    info_menu = tk.Menu(menu)
    info_menu.add_command(label='About', command=about)
     
    # erstes und zweites Menu zur Menuleiste hinzu
    menu.add_cascade(label='Datei', menu=file_menu)
    menu.add_cascade(label='?', menu=info_menu)
     
    # gesamte Menuleiste zu Fenster hinzu
    root['menu'] = menu
     
    root.mainloop()


if __name__ == '__main__':
    main()
Benutzeravatar
Dirki
User
Beiträge: 40
Registriert: Donnerstag 23. Juni 2016, 16:11

Montag 11. Juli 2016, 15:06

Danke BlackJack!

bei dir sieht Code immer so elegant aus. Da merkt man halt den Unterschied zwischen richtigen Programmierern und Leute wie ich, die versuchen, das alleine zu lernen. Ich nehme deine Veränderungen als Muster und schreibe dann daran weiter, damit ich das mal begreife. :)

Das gucke ich mir jetzt genau an und versuche das so weiterzuführen. Ich habe auch noch mal im Buch zurück geblättert. Die objektorientierte Programmierung will einfach noch nicht so richtig in meinem Kopf, aber ich arbeite daran. Mein Problem ist, das ich immer rennen will, bevor ich laufen kann.
Antworten