Projekterstellung mit GUI

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
__blackjack__
User
Beiträge: 14133
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Für jede nicht-triviale GUI braucht man objektorientierte Programmierung (OOP), weil man sich ja über Aufrufe hinweg Zustand merken muss. Du müsstest Dich also mal mit Klassen auseinander setzen.
“It is easier to change the specification to fit the program than vice versa.” — Alan J. Perlis
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ach du liebes Lieschen :-)

Das geht als weiter in die Tiefe :-)

Das heißt ich muss mir Klassen bauen, die meine Werte behalten oder Klassen bauen die diese Abfragen steuern?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Code: Alles auswählen

import tkinter as tk

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("500x500")
        self.master.title("Schiessbuch")
        self.frame1 = tk.Frame(self.master)
        
        self.Label1 = tk.Label(self.frame1, text = "Schiessbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack()
                
        self.frame1.pack()
        
        self.frame2 = tk.Frame(self.master)
        
        self.e1 = tk.Entry(self.frame2)
        self.e1.pack(padx=5, pady=20)
        
        self.Buttonchoice= tk.Button(self.frame2, text ="OK")
        self.Buttonchoice.pack(padx=5, pady=20)
        
        
        self.frame2.pack()
  
def main(): 
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Hallo,

ich habe mal etwas probiert und einen kleinen Teil in MainWindow verschoben.
Frage
ist das schon zuviel in MainWIndows?
Wie kann ich das pack() anordnen? side=LEFT etc bringt er als Fehler raus, er würde es nicht kennen
wie rufe ich jetzt hier die nächsten Dinge auf?
Benutzeravatar
__blackjack__
User
Beiträge: 14133
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: `LEFT` ist ja in der Tat auch nirgends definiert. Das ist aus dem `tkinter`-Modul, wie `Tk`, `Button`, …

Du musst halt bei der Schaltfläche ein `command`-Argument angeben, dass dann aufgerufen wird wenn die Schaltfläche geklickt wird. Die darf dann kurz etwas machen, und dann zur GUI-Hauptschleife zurück kehren.
“It is easier to change the specification to fit the program than vice versa.” — Alan J. Perlis
Sirius3
User
Beiträge: 18298
Registriert: Sonntag 21. Oktober 2012, 17:20

Es ist nicht nötig, alles an Attribute zu binden. Die Label werden ja sonst nicht mehr gebraucht, da ist sogar gar keine Variable nötig.
`e1` ist ein ganz schlechter Variablenname, wie auch alle anderen mit Nummern.
`Buttonchoice` hält sich nicht an die Konvention und wird wahrscheinlich auch nicht mehr gebrauct.
LEFT kommt auch aus Tkinter -> tk.LEFT
Um das = bei Keyword-Argumente setzt man keine Leerzeichen.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

So ganz geschnalt habe ich es noch nicht.

Jetzt meint er das Syntax nicht stimmt bei side=tk.BOTTOM :-O

Code: Alles auswählen

import tkinter as tk

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("500x500")
        self.master.title("Schiessbuch")
        self.frame1 = tk.Frame(self.master)
        
        self.Label1 = tk.Label(self.frame1, text = "Schiessbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack()
                
        self.frame1.pack()
        
        
        
        
        
        
        self.frame2 = tk.Frame(self.master)
        
        self.enty_userid = tk.Entry(self.frame2)
        self.enty_userid.pack(padx=5, pady=20 side=tk.BOTTOM)
        
        self.button_choice_userid = tk.Button(self.frame2, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20 side=tk.BOTTOM)
        
        
        self.frame2.pack()
   
    
   



def main(): 
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hast du mal genau hingeschaut, was du da geschrieben hast? Wie du mehrere Argumente an eine Funktion uebergeben musst, und was du stattdessen tust?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Habe mein fehlendes Komma gefunden! :-O

Habe es auch erstmal einigermaßen erfolgreich hinbekommen.

Nun will ich aber die Überschrift und die button_BOTTOM Gedöns, in eine Funktion schreiben, innerhalb der Klasse.

Wie rufe ich das auf? Oder spreche ich die Klasse anders an?

Code: Alles auswählen

import tkinter as tk
import funktion

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("1000x1000")
        self.master.title("Schießbuch")
        
        self.frame1 = tk.Frame(self.master)
        self.Label1 = tk.Label(self.frame1, text = "Schießbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.frame1.pack(side=tk.TOP)
        
        ueberschrift(self)
        buttons_bottom(self)
       
    def ueberschrift(self):
        self.frame2 =tk.Frame(self.master)
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack(padx=5, pady=20)
        self.frame2.pack(side=tk.BOTTOM)
        
        
    def buttons_bottom(self):
        self.frame3 = tk.Frame(self.master)
        self.enty_userid = tk.Entry(self.frame3)
        self.enty_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.button_choice_userid = tk.Button(self.frame3, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.frame3.pack(side=tk.BOTTOM)
   
    
   



def main(): 
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

war zu schnell!

Habe es. Muss es auch mit self aufrufen und den master noch übergeben!

Code: Alles auswählen

import tkinter as tk
import funktion

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("1000x1000")
        self.master.title("Schießbuch")
        
        self.frame1 = tk.Frame(self.master)
        self.Label1 = tk.Label(self.frame1, text = "Schießbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.frame1.pack(side=tk.TOP)
        
        self.ueberschrift(self.master)
        self.buttons_bottom(self.master)
       
    def ueberschrift(self, master):
        self.frame2 =tk.Frame(self.master)
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack(padx=5, pady=20)
        self.frame2.pack(side=tk.BOTTOM)
        
        
    def buttons_bottom(self, master):
        self.frame3 = tk.Frame(self.master)
        self.enty_userid = tk.Entry(self.frame3)
        self.enty_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.button_choice_userid = tk.Button(self.frame3, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.frame3.pack(side=tk.BOTTOM)
   
    
   



def main(): 
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Sirius3
User
Beiträge: 18298
Registriert: Sonntag 21. Oktober 2012, 17:20

Das `master`-Argument ist unnötig, weil unbenutzt. Ein Modul das `funktion` heißt, ist zu generisch. Wenn Du keinen passenden Namen findest heißt das wohl, dass Du was in ein Modul gepackt hast, was nicht zusammengehört.
Tippfehler sind auch Fehlerquellen: enty_userid.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Das Master Element, kann ich nicht rausnehmen. Da sagt er mir, das 1 Argument verfügbar ist aber 2 kommen.

Wie und vorallem wo, rufe ich denn am besten die Show_users auf?

Code: Alles auswählen

import tkinter as tk
import sql_aufrufe

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.master.geometry("1000x1000")
        self.master.title("Schießbuch")
        
        self.frame1 = tk.Frame(self.master)
        self.Label1 = tk.Label(self.frame1, text = "Schießbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.frame1.pack(side=tk.TOP)
        
        self.ueberschrift(self.master)
        self.buttons_bottom(self.master)
        
       
    def ueberschrift(self, master):
        self.frame2 =tk.Frame(self.master)
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack(padx=5, pady=20)
        self.frame2.pack(side=tk.BOTTOM)
        
        
    def buttons_bottom(self, master):
        self.frame3 = tk.Frame(self.master)
        self.enty_userid = tk.Entry(self.frame3)
        self.enty_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.button_choice_userid = tk.Button(self.frame3, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.frame3.pack(side=tk.BOTTOM)
   
    
def show_users(db):
    frame4 =tk.Frame()
    w = sql_aufrufe.get_users(db)
    for row in w:
        tk.Label(frame4, text= (row["ID"], row["UName"], row["UVorname"]),
                fg = "red",
                font = "Arial")
        frame4.pack(fill=X,pady=10)
   



def main():
    db = sql_aufrufe.connect() 
    #show_users(db)
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

Sirius3
User
Beiträge: 18298
Registriert: Sonntag 21. Oktober 2012, 17:20

Das `master`, das in buttons_bottom zu viel ist, fehlt in `show_users`. Oder eben besser auch als Methode von `MainWindow` definieren, wo auch `db` hingehört.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ich weiss immer noch nicht, welches Master du meinst. Sorry für die Begriffsstutzigkeit. Weil wenn ich das Master aus

Code: Alles auswählen

def buttons_bottom(self, master):
nehme geht es nicht

und wenn ich das master aus

Code: Alles auswählen

self.frame3 = tk.Frame(self.master)
geht es auch nicht.

Verstehe den Zusammenhang noch nicht wirklich.

Sowie ich es jetzt gepostet habe, bekomme ich zumindest mal das was ich gerne haben mag. Ob es praktikabel ist weiß nicht ....

Schon gar nicht wo ich die Antworten aus den eingaben hernehme und wie ich die weiter verwende.

Code: Alles auswählen

import tkinter as tk
import sql_aufrufe

class MainWindow:
    def __init__(self, master):
        
        db = sql_aufrufe.connect()
        
        self.master = master
        self.master.geometry("1000x1000")
        self.master.title("Schießbuch")
        
        self.frame1 = tk.Frame(self.master)
        self.Label1 = tk.Label(self.frame1, text = "Schießbuch", font = "Arial 14 bold")
        self.Label1.pack()
        self.frame1.pack(side=tk.TOP)
        
        self.ueberschrift(self.master)
        self.buttons_bottom(self.master)
        
        show_users(db, self.master)
        
       
    def ueberschrift(self, master):
        self.frame2 =tk.Frame(self.master)
        self.Label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.Label2.pack(padx=5, pady=20)
        self.frame2.pack(side=tk.BOTTOM)
        
        
    def buttons_bottom(self, master):
        self.frame3 = tk.Frame(self.master)
        self.entry_userid = tk.Entry(self.frame3)
        self.entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.button_choice_userid = tk.Button(self.frame3, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.frame3.pack(side=tk.BOTTOM)
   
    
def show_users(db, self):
    self.frame4 =tk.Frame(self.master)
    w = sql_aufrufe.get_users(db)
    for row in w:
        self.Label_Users = tk.Label(self.frame4, text= (row["ID"], row["UName"], row["UVorname"]),
                fg = "red",
                font = "Arial")
        self.Label_Users.pack(fill=tk.X, pady=10)
    self.frame4.pack()
   



def main():
     
    #show_users(db)
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()

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

@matze1708: Das `master`-Argument aus `ueberschrift()` und `buttons_bottom()` zu nehmen geht sehr wohl. Es wird in den beiden Methoden ja gar nicht benutzt, warum sollte man das dann übergeben müssen?

Die beiden Methodennamen beschreiben übrigens keine Tätigkeiten.

`self` sollte man nur das erste Argument von Methoden nennen. Wirklich kein anderes Argument sollte so heissen, das ist extrem verwirrend. Das dieser Name eine superbesondere Bedeutung hat, macht auch die farbige Syntaxhervorhebung hier (und in den meisten Editoren/IDEs) klar. Hier im Forum wird das sogar wie ein Schlüsselwort eingefärbt.

Namen durchnummerieren ist immer noch keine gute Idee. Und ich glaube es wurde auch schon mal angesprochen das man nicht alles an das Objekt binden muss, sondern nur Werte die auch tatsächlich für den Zustand benötigt werden. Dann erledigt sich das mit der Nummerierung bei einigen Namen mehr oder weniger automatisch.

`w` ist kein guter Name. Ich wüsste nicht mal Ansatzweise wofür das hier eine Abkürzung sein sollte.

Bei `self.Label_Users` sieht man eigentlich schon wegen der Schleife, dass das keinen Sinn macht an ein Objekt gebunden zu werden, denn da wird ja am Ende nur der Wert vom letzten Schleifendurchlauf übrig bleiben.

Der Name entspricht nicht den Namenskonventionen. Es ist ganz schön ermüdend die jedes mal wieder erwähnen zu müssen. Sooo schwer kann das doch nicht sein nahezu alles klein_mit_unterstrichen zu schreiben. Inhaltlich ist der Name auch komisch weil es sich nicht um *mehrere* Labelbenutzer handelt, sondern um *ein* Benutzerlabel, also `user_label`.

Ein `grid()` wäre wahrscheinlich schöner, und man wird Probleme bekommen wenn es dort mehr Benutzer als Platz auf dem Bildschirm gibt. Dann müsste man sich etwas Scrollbares für die Anzeige nehmen. Oder auf was anderes als Tk setzen. :-)
“It is easier to change the specification to fit the program than vice versa.” — Alan J. Perlis
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ich hoffe nun alles ausgemerzt zuhaben.

das ist aber nun der Fehler, wenn ich master aus den Funktionen lasse
Traceback (most recent call last):
File "test2.py", line 61, in <module>
main()
File "test2.py", line 57, in main
app = MainWindow(root)
File "test2.py", line 18, in __init__
self.ueberschrift(self.master)
TypeError: ueberschrift() takes 1 positional argument but 2 were given
Wo lasse ich nun am besten das self weg? Das kam für mich jetzt nicht so rüber.

muss ich sowas wie das Show_users() überhaupt mit self aufrufen?

Code: Alles auswählen

import tkinter as tk
import sql_aufrufe

class MainWindow:
    def __init__(self, master):
        
        db = sql_aufrufe.connect()
        
        self.master = master
        self.master.geometry("1000x1000")
        self.master.title("Schießbuch")
        
        self.frame1 = tk.Frame(self.master)
        self.label1 = tk.Label(self.frame1, text = "Schießbuch", font = "Arial 14 bold")
        self.label1.pack()
        self.frame1.pack(side=tk.TOP)
        
        self.ueberschrift(self.master)
        self.buttons_bottom(self.master)
        
        show_users(db, self.master)
        
       
    def ueberschrift(self):
        self.frame2 =tk.Frame(self.master)
        self.label2 = tk.Label(self.frame1, text = "Bitte wähle deine ID aus: ")
        self.label2.pack(padx=5, pady=20)
        self.frame2.pack(side=tk.BOTTOM)
        
        
    def buttons_bottom(self):
        self.frame3 = tk.Frame(self.master)
        self.entry_userid = tk.Entry(self.frame3)
        self.entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.button_choice_userid = tk.Button(self.frame3, text ="OK")
        self.button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        self.frame3.pack(side=tk.BOTTOM)
   
    
def show_users(db, self):
    self.frame4 =tk.Frame(self.master)
    users = sql_aufrufe.get_users(db)
    for row in users:
        self.user_label = tk.Label(self.frame4, text= (row["ID"], row["UName"], row["UVorname"]),
                fg = "red",
                font = "Arial")
        self.user.label.pack(fill=tk.X, pady=10)
    self.frame4.pack()
   



def main():
     
    #show_users(db)
    root = tk.Tk()
    app = MainWindow(root)
    root.mainloop()

if __name__ == '__main__':
    main()


EDIT:
Ich baue auch gern auf was anderes. Wenn das sinnvoller ist.

Aber es soll später keine User Liste geben, da soll dann der RFID aufruf sein.. Danach kommen nur die kleinen anzeigen, Kaliber, Platz Standaufsicht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Welche von den beiden self.irgendwas in "self.ueberschrift(self.master)" hat denn was mit master zu tun, und koennte darum der erste Kandidat fuer das weglassen sein? Und dann sind das ja auch theoretisch nur 2 Moeglichkeiten (an dieser Stelle.) Das dauert ja nun nicht einen Nachmittag auszuprobieren, welches weg muss.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Bei diesen hier geht es so.
Wenn ich bei den anderen was wegnehme, geht es nicht.

Innerhalb der Funktion, verweist das self.master auf das tk.

aber es war doch noch mehr wo ich self zu viel habe.

Code: Alles auswählen

	self.ueberschrift(self)
        self.buttons_bottom(self)
        
        show_users(db, self)
EDIT:

Alles was innerhalb der Klasse ist, kann ich nur mit self aufrufen, sonst streikt er.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst das nicht erraten. Du musst das schon versuchen zu verstehen, warum eine Methode die so deklariert wird

Code: Alles auswählen

def meine_methode(self, ein_argument):
       ...
SO aufgerufen wird:

Code: Alles auswählen

ein_objekt_mit_meine_methode.meine_methode("DAS ARGUMENT") # KEIN SELF! NIRGENDWO!
Und das ein_objekt_mit_meine_methode in deinem Fall self ist, ist voellig unerheblich.

Das ist wirklich ganz grundlegend Python OO. Dafuer gibt es eine Menge an Tutorials da draussen, die einem das erklaeren.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

matze1708 hat geschrieben: Mittwoch 27. März 2019, 14:52 Alles was innerhalb der Klasse ist, kann ich nur mit self aufrufen, sonst streikt er.
Ja. Das ist die entscheidende Eigenschaft einer Methode, dass sie nur in Zusammenhang mit einem dazugehoerigen Objekt aufgerufen werden kann. Du rufst doch auch

Code: Alles auswählen

root = tk.Tk()
...
root.mainloop()
auf. Und erwartest nicht, dass einfach mainloop hinzuschreiben genuegen wuerde. Genauso mit deinen ganzen Frames etc, die du zwar an self.irgendwas gebunden hast (weil du sie spaeter brauchst. Oder auch nicht). Aber self.frame.pack(...) ist pack auch bezogen auf den Frame. Ohne den macht es ja auch keinen Sinn, oder? Woher soll Tk sonst wissen *WAS* du packen willst.

Also nochmal: alles ganz Grundlegende OO, die du dir raufschaffen musst.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Hallo,

ich muss nochmal eine zwischen Frage stellen,

ich möchte von der Gesamtmenge der Plätze aus get_max_place_number und der Teilmenge get_occupied_place_numbers die freien Plätze bekommen.

Versuche ich das aber wie unten, in eine Liste zuschieben,

Sagt er folgendes:
Traceback (most recent call last):
File "schuetzeanlegen.py", line 273, in <module>
main()
File "schuetzeanlegen.py", line 253, in main
print(get_free_place_list(db, range_id))
File "schuetzeanlegen.py", line 181, in get_free_place_list
for place_number in range(1, max_place_number + 1)
TypeError: can only concatenate list (not "int") to list
Jetzt hatte ich versucht diverse Funktionen als list zu formatieren. Das hat es auch nicht gebracht.

Was muss ich tun?

Code: Alles auswählen

def get_occupied_place_numbers(db, range_id):
    with closing(db.cursor()) as cursor:
        cursor.execute(
            'SELECT Platz FROM tbl_Schiesstand'
            ' WHERE Ende IS NULL AND StandID = %s',
            (range_id,)
        )
        return [row['Platz'] for row in cursor]


def get_max_place_number(db, range_id):
    with closing(db.cursor()) as cursor:
        cursor.execute("""SELECT PlaetzeMax FROM tbl_Stand WHERE ID =%s """, (range_id,))
        return [row['PlaetzeMax'] for row in cursor]




def get_free_place_list(db, range_id):
    
        occupied_place_numbers = set(get_occupied_place_numbers(db, range_id))
        max_place_number = get_max_place_number(db, range_id)
        free_place_numbers = [
            place_number
            for place_number in range(1, max_place_number + 1)
            if place_number not in occupied_place_numbers]
        
        return free_place_numbers

Danke und Liebe Grüße
Antworten