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.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

max_place_number ist eine Liste. Und auf die kann man halt nichts addieren, was du mit "liste + 1" versuchst.

Kann es sein, dass du statt ueber einen range gleich ueber die Liste der max_place_number iterieren willst? Ich habe nicht verfolgt, was du hier inhaltlich machen willst, also was die Abfrage in get_max_place_number ueberhaupt liefern soll.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Das hat mir freundlicherweise, jemand in dieser Art gepostet.

Ich habe in der Funktion get_max_place_numbers eine SQL Abfrage, welche Plätze aktuell belegt sind. Es kommt dann zurück [5, 4, 3] oder ähnliches.

Aus der get_max_place_number kommt die maximale Kapazität des Standes. z.b. [20]

Daraus möchte ich ableiten, welche Plätze noch frei sind. zwischen 1 und der max anzahl
Benutzeravatar
__blackjack__
User
Beiträge: 13174
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: Ich habe ein Dejavu. Da war doch schon mal die Frage warum Du eine einzelne Zahl als Liste lieferst. `get_max_place_number()` soll ja die *eine* maximale Platznummer für den *einen* gegebenen Stand liefern. Das ist sinnvollerweise einfach *eine* *Zahl*. Und keine Liste die *immer* *genau* *eine* Zahl enthält. Du versuchst dann ja durch die Addition von 1 damit weiter zu arbeiten als wäre es eine Zahl und keine Liste.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Ich war erst jetzt wieder an dem Thema dran.

Konnte aber was mit deiner Hilfe anstellen. Ich hatte ja den Output von get_max_place_number als Liste erstellt. Dann kann es nicht.

Habe es geändert. Nun geht es.

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,))
        for row in cursor:
            return row['PlaetzeMax'] 
        
        



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
Sirius3
User
Beiträge: 17785
Registriert: Sonntag 21. Oktober 2012, 17:20

Und wie schon mehrfach erwähnt deutet ein `return` direkt in einer for-Schleife auf einen Fehler hin, besser `fetchone` benutzen.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Sirius3 hat geschrieben: Donnerstag 28. März 2019, 12:27 Und wie schon mehrfach erwähnt deutet ein `return` direkt in einer for-Schleife auf einen Fehler hin, besser `fetchone` benutzen.
bei fetchone übergibt er mir das auch direkt an die Funktion?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Als nächstes wollte ich mir mit einer Schleife Buttons erstellen

Code: Alles auswählen

def buttons_places(db, self):
     frame = tk.Frame(self.master)
     free_places = range(sql_aufrufe.get_max_place_number(db, 2)) 
           
     for i in free_places:
                        
       button_places = tk.Button(frame, text = str(i))
       button_places.pack(padx=5, pady=20, side=tk.LEFT)
       
     frame.pack(side=tk.BOTTOM)
macht man das so? Die Buttons sollen dann einfach nur ihren Wert zurückgeben.

Also wenn Text 1 dann Wert 1 etc etc.


Eigentlich wollte ich mich heute NUR mit OOP beschäftigten....
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Hier ist mal mein aktueller Aufbau.

Mit dem self scheint angekommen zusein. Muss mich aber weiter in das OOP einarbeiten.

Sicher bin ich mir auch noch nicht, ob ich die Funktionen, für die Rückgabewerte dann in die Main Window Class packe muss oder ob ich diese da lasse. Aber dann sind sie ja gekapselt von Main Window an der jetzigen stelle.



Code: Alles auswählen

import tkinter as tk
import sql_aufrufe


#---------------------Aufbau Hauptfenster---------------------------------------------------

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 16 bold")
        self.label1.pack(padx=5, pady=30)
        self.frame1.pack(side=tk.TOP)
    
#------------------------------------------------------------------------------------------
        
#-----------------------LOGIK FÜR DEN ABLAUF-----------------------------------------------   
        
        input_user_id(self)
            
        show_users(db, self)
        
        buttons_places(db, self)
        
#------------------------------------------------------------------------------------------        
        

#----------------------FUNKTIONEN FÜR DIE AUFRUFE------------------------------------------        
       
def input_user_id(self):
    frame =tk.Frame(self.master, background='#ff99ff')
    label = tk.Label(frame, text = "Bitte wähle deine ID aus: ")
    label.pack(padx=5, pady=20)
        
    entry_userid = tk.Entry(frame)
    entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
    button_choice_userid = tk.Button(frame, text ="OK")
    button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
        
    frame.pack(side=tk.TOP)
        
        
       
   
def buttons_places(db, self):
     frame = tk.Frame(self.master)
     free_places = sql_aufrufe.get_free_place_list(db, 2)
     label = tk.Label(frame, text = "Bitte tippe auf den Platz auf dem du schießt: ")
     label.pack(padx=5, pady=5)
     
           
     for i in free_places:
                        
       button_places = tk.Button(frame, text = i)
       button_places.pack(padx=5, pady=5, side=tk.LEFT)
       
     frame.pack(side=tk.BOTTOM)
   
   
   
    
def show_users(db, self):
    frame =tk.Frame(self.master, background='#ff99ff')
    users = sql_aufrufe.get_users(db)
    for row in users:
        user_label = tk.Label(frame, text= (row["ID"], row["UName"], row["UVorname"]),
                fg = "red",
                font = "Arial")
        user_label.pack(fill=tk.X, pady=10)
    frame.pack(side=tk.TOP)
   


    
#--------------------------------------------------------------------------------------    


#----------------------------------MAIN AUFRUF------------------------------------------

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

if __name__ == '__main__':
    main()

EDIT: Aber trotz das ich euch den letzten nerv raube! Finde ich das Forum hier super toll! Ihr helft gerne und gebt nicht gleich fertigen Code aus, sondern animiert die User zu denken. Richtig gut !!
Ich bin aber auch bissl stolz auf mich aus dem blauen raus, schon mal sowas wie jetzt zuhaben. Wahrscheinlich könnt ihr das innerhalb von einem Tag neben bei aufbauen.
Sirius3
User
Beiträge: 17785
Registriert: Sonntag 21. Oktober 2012, 17:20

Du siehst allein schon daran, dass Du self an `buttons_places`, `show_users` und `input_user_id` übergibst, dass die besser in der Klasse aufgehoben sind, vor allem dann, wenn die Buttons auch irgendwann mal etwas machen.

Laß das bitte mit diesen komischen Kommentaren sein, gut benannte Funktionen und Klassen sind schon auffällig und aussagekräftig genug. Vor allem, wenn man an den Funktionen was ändert hast Du irgendwann das Problem, das der Kommentar nicht mehr zum Code passt.
Benutzeravatar
__blackjack__
User
Beiträge: 13174
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@matze1708: `self` ist das erste Argument von Methoden. Das ist kein Name den man für Argumente in Funktionen verwenden darf, egal ob das syntaktisch zulässig ist, und das ist kein Argument das an irgendeiner anderen Stelle als der ersten bei den Argumenten einer Methodendefinition steht. Der Name steht für das Objekt *selbst*, auf dem die Methode aufgerufen wurde; das gibt es bei Funktionen doch aber überhaupt gar nicht.

Ich bin auch nicht so wirklich überzeugt von Deinem GUI-Aufbau. Üblicherweise erstellt man erst die *komplette* GUI und erweitert die nicht bei jedem Schritt um weitere Elemente. Man muss sich dann um den gesamten Zustand Gedanken machen und eventuell Teile mit Platzhaltern versehen, also zum Beispiel Platz für Schaltflächen für den Stand mit den meisten Plätzen bereit stellen, und die Schaltflächen erst dann einblenden wenn bekannt ist welcher Stand ausgewählt wurde. Und dann am besten auch eine Schaltfläche pro Platz, auch für die belegten. Die Schaltflächen für die belegten Plätze kann man deaktivieren, dann werden die ausgegraut dargestellt und sind nicht klickbar. Aber man hat dann keine GUI die dauernd, für den Benutzer nicht wirklich vorhersehbar ihre Grösse ändert.

Radiobuttons könnten hier auch Sinn machen, denn man kann ja immer nur einen Platz von den ganzen Möglichkeiten auf einmal auswählen, und so lässt sich das einfach sicherstellen das der Benutzer nur einen Auswählen kann, die Auswahl aber bis zum endgültigen Akzeptieren aber leicht ändern kann.

Oder man löst die Schritte durch einzelne, modale Dialoge. Oder einen ”Wizard”. Wobei man sich den bei Tk selber basteln muss. Andere GUI-Rahmenwerke haben dafür oft schon Widgets/die Infrastruktur.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

__blackjack__ hat geschrieben: Donnerstag 28. März 2019, 15:05 @matze1708: `self` ist das erste Argument von Methoden. Das ist kein Name den man für Argumente in Funktionen verwenden darf, egal ob das syntaktisch zulässig ist, und das ist kein Argument das an irgendeiner anderen Stelle als der ersten bei den Argumenten einer Methodendefinition steht. Der Name steht für das Objekt *selbst*, auf dem die Methode aufgerufen wurde; das gibt es bei Funktionen doch aber überhaupt gar nicht.
Habe ich das noch unwissentlich im Code?
__blackjack__ hat geschrieben: Donnerstag 28. März 2019, 15:05
Ich bin auch nicht so wirklich überzeugt von Deinem GUI-Aufbau. Üblicherweise erstellt man erst die *komplette* GUI und erweitert die nicht bei jedem Schritt um weitere Elemente. Man muss sich dann um den gesamten Zustand Gedanken machen und eventuell Teile mit Platzhaltern versehen, also zum Beispiel Platz für Schaltflächen für den Stand mit den meisten Plätzen bereit stellen, und die Schaltflächen erst dann einblenden wenn bekannt ist welcher Stand ausgewählt wurde. Und dann am besten auch eine Schaltfläche pro Platz, auch für die belegten. Die Schaltflächen für die belegten Plätze kann man deaktivieren, dann werden die ausgegraut dargestellt und sind nicht klickbar. Aber man hat dann keine GUI die dauernd, für den Benutzer nicht wirklich vorhersehbar ihre Grösse ändert.

Radiobuttons könnten hier auch Sinn machen, denn man kann ja immer nur einen Platz von den ganzen Möglichkeiten auf einmal auswählen, und so lässt sich das einfach sicherstellen das der Benutzer nur einen Auswählen kann, die Auswahl aber bis zum endgültigen Akzeptieren aber leicht ändern kann.

Oder man löst die Schritte durch einzelne, modale Dialoge. Oder einen ”Wizard”. Wobei man sich den bei Tk selber basteln muss. Andere GUI-Rahmenwerke haben dafür oft schon Widgets/die Infrastruktur.
Ich bin gerne offen für ein anderes GUI.

Radiobuttons wäre auch ok.

Ich hätte sonst die Aktion gestartet wenn auf den Button geklickt wird.


Habe die Funktionen nochmal in die MainWindow verschoben.

Hatte das vorhin probiert und db, self geschrieben. self muss aber offentsichtlich vorne stehen

Kommentare habe ich entfernt.

Ich hätte es gern so, das nach der Userauswahl, das Fenster seinen Inhalt wechselt auf die Platz eingabe.
Die User Erkennung soll über RFID passieren und der Stand selbst über eine Variable beim aufruf. Da ein Raspberry mit Display pro Stand vorhanden sein wird. Damit entfällt die User Interaktion Stand Auswahl. Geben tut es die im Hintergrund schon, bzw ich kann dann ja direkt zu Platz Auswahl springen.

Falls keine Standaufsicht aktuell da ist, muss da halt noch eine Prüfung rein, oder der User wird selbst zur Standaufsicht.

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 16 bold")
        self.label1.pack(padx=5, pady=30)
        self.frame1.pack(side=tk.TOP)
    
  
        
        self.input_user_id()
            
        self.show_users(db)
        
        self.buttons_places(db)
        
       
    def input_user_id(self):
        frame =tk.Frame(self.master)
        label = tk.Label(frame, text = "Bitte wähle deine ID aus: ")
        label.pack(padx=5, pady=20)
            
        entry_userid = tk.Entry(frame)
        entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
        button_choice_userid = tk.Button(frame, text ="OK")
        button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
            
        frame.pack(side=tk.TOP)
        
        
       
   
    def buttons_places(self, db):
         frame = tk.Frame(self.master)
         free_places = sql_aufrufe.get_free_place_list(db, 2)
         label = tk.Label(frame, text = "Bitte tippe auf den Platz auf dem du schießt: ")
         label.pack(padx=5, pady=5)
         
               
         for i in free_places:
                            
           button_places = tk.Button(frame, text = i)
           button_places.pack(padx=5, pady=5, side=tk.LEFT)
           
         frame.pack(side=tk.BOTTOM)
   
   
   
    
    def show_users(self, db):
        frame =tk.Frame(self.master)
        users = sql_aufrufe.get_users(db)
        for row in users:
            user_label = tk.Label(frame, text= (row["ID"], row["UName"], row["UVorname"]),
                    fg = "red",
                    font = "Arial")
            user_label.pack(fill=tk.X, pady=10)
        frame.pack(side=tk.TOP)
   



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

Hallo,

ich versuche gerade, über das Button Ereignis mir den Text im Textfeld per Print anzeigen zulassen.

Klappt aber nicht. Warum?

Code: Alles auswählen

import tkinter as tk
import sql_aufrufe


class MainWindow:
    def __init__(self, master):
        
        db = sql_aufrufe.connect()
        
        user_id_get_from_entry = tk.StringVar()
        
        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 16 bold")
        self.label1.pack(padx=5, pady=30)
        self.frame1.pack(side=tk.TOP)
    
  
        
        self.input_user_id()
            
        self.show_users(db)
        
        self.buttons_places(db)
        
       
    def input_user_id(self):
        frame =tk.Frame(self.master)
        label = tk.Label(frame, text = "Bitte wähle deine ID aus: ")
        label.pack(padx=5, pady=20)
            
        entry_userid = tk.Entry(frame)
        entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
        
        self.user_id_get_from_entry = entry_userid.get()
        
        button_choice_userid = tk.Button(frame, text ="OK", command = self.get_user_id_from_button())
        button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
            
        frame.pack(side=tk.TOP)
        
        
        
    def get_user_id_from_button(self):
         print(self.user_id_get_from_entry)  
       
   
    def buttons_places(self, db):
         frame = tk.Frame(self.master)
         free_places = sql_aufrufe.get_free_place_list(db, 2)
         label = tk.Label(frame, text = "Bitte tippe auf den Platz auf dem du schießt: ")
         label.pack(padx=5, pady=5)
         
               
         for i in free_places:
                            
           button_places = tk.Button(frame, text = i)
           button_places.pack(padx=5, pady=5, side=tk.LEFT)
           
         frame.pack(side=tk.BOTTOM)
   
   
   
    
    def show_users(self, db):
        frame =tk.Frame(self.master)
        users = sql_aufrufe.get_users(db)
        for row in users:
            user_label = tk.Label(frame, text= (row["ID"], row["UName"], row["UVorname"]),
                    fg = "red",
                    font = "Arial")
            user_label.pack(fill=tk.X, pady=10)
        frame.pack(side=tk.TOP)
   



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

Weil du den standard-Fehler machst: du rufst das gewünschte Kommando an Ort und Stelle auf. Statt es unaufgerufen zu übergeben. Du musst die () loswerden.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Na toll.... wie einfach....

Bekomme aber jetzt das hier

<bound method Entry.get of <tkinter.Entry object .1981406512.1981406608>>

ist das schon das Ergebnis oder was ist das?
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

Muss ich dieses StringVar nutzten? Das habe ich aus einem der vielen Tutorials
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du bekommst, wonach du fragst. Du gibst ein Objekt aus, und so sieht es aus. Schau in die Dokumentation zu dem tkinter entry Objekt, wie du an dessen INHALT kommst.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

DAs versuche ich....

Bekomme das über .get.

Aber irgendwie muss ich noch die user_id_get_from_entry Variable noch befüllen. Das sollte mit .set gehen.
Das wiederrum rufe ich aber in der Funktion get_user_id_from_button auf. DIe dann das entry_userid nicht kennt.

Aktuelle bekomme ich einen PYVAR0 ausgeben. Denke das ist der Null Wert der Variable
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst die ID ja auch ermitteln NACHDEM dr Button gedrückt wurde. Python kann nicht in die Zukunft sehen.
matze1708
User
Beiträge: 112
Registriert: Dienstag 12. März 2019, 11:49

__deets__ hat geschrieben: Freitag 29. März 2019, 10:12 Du musst die ID ja auch ermitteln NACHDEM dr Button gedrückt wurde. Python kann nicht in die Zukunft sehen.
Das wollte ich auch veruschen.

Code: Alles auswählen


def input_user_id(self):
        frame =tk.Frame(self.master)
        label = tk.Label(frame, text = "Bitte wähle deine ID aus: ")
        label.pack(padx=5, pady=20)
            
        entry_userid = tk.Entry(frame, textvariable = self.user_id_get_from_entry)
        entry_userid.pack(padx=5, pady=20, side=tk.LEFT)
        
        
            
        button_choice_userid = tk.Button(frame, text ="OK", command = self.get_user_id_from_button)
        button_choice_userid.pack(padx=5, pady=20, side=tk.LEFT)
            
        frame.pack(side=tk.TOP)
        
        
        
    def get_user_id_from_button(self):
        
         self.user_id_get_from_entry.set(entry_userid)
         print(self.user_id_get_from_entry)
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist wieder alles komplett geraten und gewurschtelt. Du hast immer noch nicht verstanden, wozu das binden an self dient. Und den Wert eines entries bekommt man mit get(). Was du nicht aufrufst. Den dann wiederum mit set woanders zu setzen ist erstmal so völlig unnötig.

Ich sag’s jetzt zum 3ten oder so mal: ohne ein Verständnis dafür, was Klassen, Objekte, Attribute und Methoden sind, wird es nichts werden.
Antworten