GUI – 38 Eingabefelder und 38 Beschriftungen

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
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo! :)

Bin jetzt einen Schritt weiter und die Widgets sind im Frame.

Aktuelles Problem: Ich habe die Datenbankabfrage in ein externes Skript und in eine dortige Funktion ausgelagert. Wie erreiche ich jetzt, dass das SQL-result im aufrufenden (Haupt-)Skript im Textfenster ausgegeben werden kann?

Bisher funktioniert das in beiden Richtungen nicht. Will heißen: Entweder kennt das Unter-Skript das Textfenster nicht, oder das Haupt-Skript kennt das SQL-result nicht. Gibt es einen Befehl, ein Objekt wie "result" global verfügbar zu machen? Oder wie anders realisiere ich das?

Grüße
Strawk
:D
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

In dem Buch, das du ja so gruendlich durchgearbeitet hast, gibt es bestimmt auch eine Einfuehrung in Funktionsparameter und Rueckgabewerte, und deren Nutzung. Da noch mal nachschauen.
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo __deets__!

Nein, zur skriptübergreifenden Übergabe steht im Einstiegsbuch nichts. Wäre es ein Ansatz, das SQL-Abfrageergebnis als Instanz einer Klasse zu gestalten? Wie sähe dann die Klassendefinition grob aus?

Grüße
Strawk
:?
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Natuerlich steht dazu etwas darin. Es behandelt Module, also die Aufteilung eines Programms in mehrere Teile. Und es behandelt Funktionen mit Parametern und Rueckgabewerten. Das findet sich im Inhaltsverzeichnis:

https://www.rheinwerk-verlag.de/einstie ... n_4374/toc

Deutlich vor der von dir angegebenen Seitennummer irgendwo bei 370.

Und die Ergebnisse einer Abfrage sind ja schon ein Objekt - naemlich ein Cursor. An sich kann man den auch einfach zurueckgeben. Allerdings kann man sich da Aerger einhandeln, weil dessen Gueltigkeit an der Verbindung und anderen Einfluessen haengt. Aber ein simples "return cursor.fetchall()" reicht, und du hast dein Objekt - eine Liste von Tupeln.
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo __deets__!

Das funktioniert schon anhand einfacher Beispiele nicht.

Code: Alles auswählen

def testFunktion():
    a = 42
    return a

Code: Alles auswählen

import sys

sys.path.append('C:/Users/Karl Kraft/Documents/Programmierung_ausser_PHP/Python/Anaconda_Navigator/Liverecord_Python')

import aufgerufenes_skript_01
aufgerufenes_skript_01.testFunktion()
print a
ergibt
NameError: name 'a' is not defined
Grüße
Strawk
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ja, weil a nur im Namensraum der Funktion bekannt ist. Das schwirrt nicht einfach so im Raum. Schon gar nicht modulübergreifend. Aus solchen Gründen solltest du dich mit den Grundlagen beschäftigen, bevor du weiter an GUI-Programmierung herumdoktorst. Das dauert nun mal ein paar Monate bis man es drauf hat. Das lernt man nicht an 3 Abenden. Mit anderen Worten: Du hast gerade Plus und Minus gelernt und willst direkt zur Analysis übergehen. Das funktioniert eben nicht.
Zuletzt geändert von snafu am Sonntag 10. Dezember 2017, 17:22, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Strawk: erstens ist das kein Skript das da aufgerufen wird, sondern Du importierst ein Modul, zweitens lergt man das Modul in ein Verzeichnis, das schon im Modulpfad ist (z.B. das aktuelle) drittens gibt man dem Modul einen sinnvollen Namen. Und jetzt lies nochmal nach, wie das mit den Funktionen funktioniert.
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!

Och, Leute, lasst euch doch nicht alles aus der Nase ziehen. Ja, ich gebe dir recht, dass das mindestens Monate, wenn nicht Jahre dauert. Aber ist denn eure Rolle im Forum, immer einfach nur zu sagen: Finde es selbst raus? Also, wie mache ich die Variable/das Objekt außerhalb nun bekannt?

Grüße
Strawk
:idea:
Ich programmiere erfolglos, also bin ich nicht.
__deets__
User
Beiträge: 14528
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du musst einen rückgabewert schon an einen Namen binden. Der erscheint nicht magisch in dem Namensraum um die aufrufstelle herum.

Code: Alles auswählen

wert = funktion_die_was_tut()
Das steht auch so ganz bestimmt NICHT in deinem Buch. Du wirst nicht darum herum kommen, das nochmal anzuschauen.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Gibt es einen Befehl, ein Objekt wie "result" global verfügbar zu machen?
Unter Python nutzt man _keine_ globalen Namensraum, über den Werte von Variablen abgerufen werden können. Entweder nutzt du Instanzen von Objekten, deren Attribute Werte enthalten (können) oder du bindest einen Wert an die Rückgabe einer Funktion wie gezeigt.

Bei der GUI-Programmierung mit Python ist es _essentiell_ wichtig, dass man die Objektorientierung von Python verstanden hat - sonst wird das nix. Alle GUI-Frameworks, nicht nur Tkinter, nutzen das sehr umfassend. Mit Python anfangen und dann direkt eine (größere) GUI programmieren wollen geht nun mal in der Regel schief...
Aber ist denn eure Rolle im Forum, immer einfach nur zu sagen: Finde es selbst raus?

In der Tat sehen die meisten das hier als "Hilfe zur Selbsthilfe", zumindest bei den gängigen / nicht-schwierigen Problemen wie diesem hier.

Gruß, noisefloor
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo! :wink:

Also, was die Funktions-Syntax betraf, da habe ich mich dumm angestellt; das gebe ich zu / räume ich ein.

Positiv: Ich komme jedesmal ein Stück weiter und habe schon einige Probleme (nicht zuletzt mit eurer Hilfe) lösen können. Außerdem meine ich, wenn die Ausgabe einmal gelungen ist, ist das auch der Durchbruch. Man darf dabei nicht vergessen, dass das ganze Projekt ja schon steht und fehlerfrei läuft, halt nur in PHP.

Und so komme ich zu meiner aktuellen Frage. Momentan sieht die Ausgabe so aus:

Code: Alles auswählen

# Daten ausgeben
    for data in abfrageergebnis:
        print(unicode(data[0]) + ", " + unicode(data[1]) + ", " + 
          unicode(data[2]) + ", " + unicode(data[3]) + ", " +
          unicode(data[4]) + ", " + unicode(data[5]) + ", " +
          unicode(data[6]) + ", " + unicode(data[7]) + ", " +
          unicode(data[8]) + ", " + unicode(data[9]) + ", " +
          unicode(data[10]) + ", " + unicode(data[11]) + ", " +
          unicode(data[12]) + ", " + unicode(data[13]) + ", " +
          unicode(data[14]) + ", " + unicode(data[15]) + ", " +
          unicode(data[16]) + ", " + unicode(data[17]) + ", " +
          unicode(data[18]) + ", " + unicode(data[19]) + ", " +
          unicode(data[20]) + ", " + unicode(data[21]) + ", " +
          unicode(data[22]) + ", " + unicode(data[23]) + ", " +
          unicode(data[24]) + ", " + unicode(data[25]) + ", " +
          unicode(data[26]) + ", " + unicode(data[27]) + ", " +
          unicode(data[28]) + ", " + unicode(data[29]) + ", " +
          unicode(data[30]) + ", " + unicode(data[31]) + ", " +
          unicode(data[32]) + ", " + unicode(data[33]) + ", " +
          unicode(data[34]) + ", " + unicode(data[35]) + ", " +
          unicode(data[36]) + ", " + unicode(data[37]))
Sie soll aber in ein großes Entry-Feld hinein, mit Scrollbalken. Und auch tabellarisch. Wie kann ich das realisieren? Wie lautet der entsprechende Befehl und: kann ich im Entry-Feld mit String-Literalen arbeiten?

Viele Grüße
Strawk
:D
Ich programmiere erfolglos, also bin ich nicht.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Strawk: das, was unter PHP als akzeptabler Programmierstil durchgeht, kann man halt mit Python dreimal eleganter lösen. Dir fehlen noch viele Grundlagen.

Code: Alles auswählen

for data in abfrageergebnis:
    print(", ".join(["{}"]*38).format(*data))
Tabellen macht man per `.grid`. Aber ehrlich, 38 Spalten liest doch niemand.
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo Sirius3!

Doch. In der Ergebnisanzeige müssen keine 38 Spalten nebeneinander stehen. Man kann sie auch teilweise untereinander anordnen und dann mit Blöcken pro Datensatz/Tupel arbeiten.

Wichtiger jetzt aber: Wie gelangt das Ergebnis ins Textfeld. (Nicht Entry! Hab mich vertan.)

Die .insert-Methode verlangt drei Argumente, das zweite davon ist der auszugebende Text. Wenn man es googelt, findet man:

Code: Alles auswählen

.insert(index, text, tags=None)
bzw.

Code: Alles auswählen

.insert(END, text)
Funktioniert aber (noch) nicht.

Grüße
Strawk
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

@Strawk: Zwischenfrage - warum willst du das eigentlich von web-basiert und PHP auf (Desktop-) GUI-basiert und Python umstellen?

Gruß, noisefloor
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo noisefloor!

Das ist eine längere Geschichte. Hier die Kurzversion.

Arbeite seit 2011 mit PHP. Mein bisher größtes Projekt: "Liverecord". Eine Datenbank, die Menschen und ihre Lebensdaten speichern kann. Empfehlung meines Ingenieur-Cousins im Februar 2017: Python erlernen, weil man damit am meisten machen kann. Erste Übung: Das Projekt in Python übersetzen.

So sieht das im Moment übrigens aus:
Bild

Erbitte Hilfe zum Gliedern innerhalb eines Text-Widgets.
Grüße, Strawk
Ich programmiere erfolglos, also bin ich nicht.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

aha. Gut ist zum Lernen immer, wann man ein Ziel hat :-)

Aber:
Erste Übung: Das Projekt in Python übersetzen.
IMHO ist das keine gute Übung, weil 3-5 Nummern zu groß. Das die Grundlagen fehlen, wurde ja hier schon öfters erwähnt.
Außerdem bedeutet GUI-Programmierung relativ viel Code, der "nur" für die Erstellung der GUI notwendig ist. Die reine Programmlogik kann vergleichsweise gering sein - das ist aber das, was du lernen möchtest / solltest.

GUI-Programmierung erfordet grundlegende Kenntnis der Objektorientierung, sonst kommt kein brauchbarer Code raus. Bei 38 Feldern ist eine gewisse Aufteilung, GUIs auf mehrere Module aufteilen ist aber für Einsteiger mehr als sportlich.
GUI + Datenbank-Anbindung ist IMHO auch kein Thema für Einsteiger.

Was du machen könntest:
* lass' dein Projekt ruhen und lerne vernünftig die Grundlagen von Python
* reduziert dein Übungsprojekt auf 5 Felder oder so, dass macht die Sache einfacher und übersichtlicher
* vergiß' Tkinter und setze es mit Web-basierte Applikation mit Python um. Ist auch einfacher als Tkinter & Co.
* vergiß' Tkinter und wechsel auf Qt, weil das eine Anbindung an SQL-Datenbanken ootb mitbringt
Erbitte Hilfe zum Gliedern innerhalb eines Text-Widgets.
Du musst den Text formatiert, also z.B. mit Zeilenumbrüchen, übergeben.

Gruß, noisefloor
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Sirius3 hat geschrieben:@Strawk: das, was unter PHP als akzeptabler Programmierstil durchgeht, kann man halt mit Python dreimal eleganter lösen. Dir fehlen noch viele Grundlagen.

Code: Alles auswählen

for data in abfrageergebnis:
    print(", ".join(["{}"]*38).format(*data))
Das geht noch einfacher:

Code: Alles auswählen

print(*data, sep=', ')
Oder ohne print()-Funktion unter Python 2.7:

Code: Alles auswählen

print u', '.join(map(unicode, data))
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Strawk

Hier ein Ausgabeversuch mittels Tk-Textwidget:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
    import tkFont as fnt
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk
    import tkinter.font as fnt

APP_TITLE = "Datenausgabe (19 Datenpaare)"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 350
APP_HEIGHT = 200


class Application(tk.Frame):

    def __init__(self, parent, abfrageergebnis):
        self.parent = parent
        
        self.parent.protocol("WM_DELETE_WINDOW", self.close)
        tk.Frame.__init__(self, parent)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        xscrollbar = tk.Scrollbar(self, orient='horizontal')
        xscrollbar.grid(row=1, column=0, sticky='ew')

        yscrollbar = tk.Scrollbar(self)
        yscrollbar.grid(row=0, column=1, sticky='ns')

        text = tk.Text(self, wrap='none', bd=0, xscrollcommand=xscrollbar.set,
            yscrollcommand=yscrollbar.set, fg='steelblue3')
        text.grid(row=0, column=0, sticky='nsew')

        xscrollbar.config(command=text.xview)
        yscrollbar.config(command=text.yview)

        for data in abfrageergebnis:
            # Data Tuple Zeile im Textwidget ausgeben
            # Platzhalter 20 Zeichen 
            text.insert(1.0, "   {:20} {:20}\n".format(*data))
            
    def close(self):
        print("Application-Shutdown")
        self.parent.destroy()
    
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))

    # Simulationsdaten erstellen (19 Datenpaare)    
    abfrageergebnis = list()
    index = 1                  
    for pair_index in range(19):
        abfrageergebnis.append(
            ("Data-{}".format(index), "Data-{}".format(index+1)))
        index += 2
        
    # Simulationsdatenliste kehren damit das erste Datentuple als letzte
    # Zeile dem Textwidget übergeben wird und somit zuoberst steht.
    abfrageergebnis.reverse()
    
    app = Application(app_win, abfrageergebnis)
    app.pack(fill='both', expand=True, padx=6, pady=6)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()      
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
Strawk
User
Beiträge: 229
Registriert: Mittwoch 15. Februar 2017, 11:42
Wohnort: Aachen
Kontaktdaten:

Hallo!

noisefloor, das sind sicherlich kluge Gedanken und Ideen, die du da kundtust. Eine Weile möchte ich mein Glück aber noch am Projekt versuchen.

Aktuell geht es darum, die Entry-Einträge, die ein User in der Maske gemacht hat, per Schleife auszulesen.
Die Namen der Entry-Widgets lauten immer "e_*".
* = feldname. Folgenden Code habe ich dazu erstellt:

Code: Alles auswählen

def buttonNachKriterienAnzeigenClick():
    felder = ["nummer", "codierung",
              "name_oder_firmenname", "geburtsname", "vorname_bezeichnung",
              "strasse_hausnummer", "plz", "ort",
              "ortsteil", "bundesland_provinz_kanton", "land_nation",
              "fahrzeugfabrikat", "fahrzeugtyp", "kfz_kennzeichen_historie",
              "landesvorwahl", "festnetzvorwahl", "festnetznummer",
              "aktiv", "mobile_vorwahl", "mobiler_anschluss",
              "e_mail_1", "e_mail_2", "url",
              "geschlecht", "anzahl_kinder", "verstorben_am_um",
              "geburtstag", "anzahl_ereignisse", "memos",
              "fax", "titel", "beruf",
              "ausbildung", "taetigkeit", "taetig_in_firma",
              "hobbys", "herkunftsland", "bekanntschaft_seit"]
    
    kriterien = []
    for feld in felder:
        kriterien.append("e_" + feld + ".get()")
        
    print(kriterien)
Problem: Was jetzt als String vorliegt, soll als Wert einer weiteren Liste hinzugefügt werden, sodass eine Liste der in die Entrys gemachten Eingaben entsteht. Erbitte Hilfe.

Grüße
Strawk
:)
Ich programmiere erfolglos, also bin ich nicht.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Strawk: falscher Weg. Ich habe in meinem Beispiel vom 3. Dezember alle Entries in eine Liste gepackt, die parallel zur LABELS-Liste gelesen werden muß. Alternativ kann man auch ein Wörterbuch verwenden. Für einen Datensatz bietet sich auch ein Namedtuple an.
Antworten