Abfragefenster mit Befehlsausführung

Fragen zu Tkinter.
Antworten
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

mein aktuelles Projekt ist, Bestelldateien per FTP oder EMail mit Anhang an Lieferanten zu verschicken.

Nun wird es auch Zeit für eine Gui, die Informationen anzeigt und mit der man auch eine Auswahl treffen kann, wie mit der jeweiligen Situation zu verfahren ist.
Da ich bisher noch keine Ahnung von Guiś habe, habe ich zuerst einmal feste gegoggelt und habe mich für Tkinter der Standart-Gui Pythonś entschieden, da für den Anfang diese wohl am leichtesten zu Handeln ist.
Mein Gui-Konstrukt sieht so aus:

Code: Alles auswählen

from Tkinter import *

class App:
  def __init__(self, master, befehl):
    frame = Frame(master)
    frame.pack()
    self.button = Button(frame, 
                         text="Abbrechen", fg="red",
                         command=frame.quit)
    self.button.pack(side=LEFT)
    self.slogan = Button(frame,
                         text="Ausführen",
                         command=self.run)
    self.slogan.pack(side=LEFT)
    self.befehl = befehl
  def run(self):
    print(self.befehl)

def fenster(information, befehl):
    root = Tk()
    T = Text(root, height=2, width=50)
    T.pack()
    T.insert(END, information)
    app = App(root, befehl)
    root.mainloop()
Ich steuere dies dann so an:

Code: Alles auswählen

from window import *

dada = 'Hallo, hier bin ich!'
dirList = os.listdir(bestelleingang)

fenster(dada, dirList)
Kurze Erläuterung dazu.
Ich möchte bestimmte Informationen im Fenster direkt haben, und wenn alles ok ist mit dem Ausführen-Button, einen Befehl ausführen.

Nach ersten Test, funktioniert das so wie gewünscht.
Möchte aber trotzdem bei Euch, die Ihr mehr Erfahrung damit habt anfragen, ob das Konstrukt so ok ist, oder was man besser anderst machen sollte.

Grüße Nobuddy
BlackJack

@Nobuddy: Zuerst mal `slogan`‽ Und `T` ist unkonventionell.

Ich verstehe den Sinn der Aufteilung zwischen dem Textfeld und den Schaltflächen nicht. Warum ist eins in der `App`-Klasse und das andere nicht?

Eventuell solltest Du einen Blick auf `tkSimpleDialog.Dialog` werfen, damit Du nichts selbst implementierst, was dieses kleine Rahmenwerk schon anbietet.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo BlackJack,
Danke für Deine Info.

Beim Googeln, bin ich hier drauf http://epydoc.sourceforge.net/stdlib/tk ... class.html gestoßen.
Durch mein englisches Handicap, ist es äußerst schwierig, für den Anfang weiter zukommen.

Vielleicht Könntet Ihr mir für den Anfang, erste Hilfestellung geben?

Ich hätte gerne ein einziges Fenster, in dem gleichzeitig die Ausgaben erfolgen sollen.
Das Fenster öffnet sich, wenn ein Bestellauftrag vorliegt. Hier sollte dann die erste Ausgabe erfolgen, die Infos zu dem aktuellen Bestellauftrag liefert.
Weiter benötige ich zwei Buttons, Eines für den Abbruch (Bestellauftrag wird nicht ausgeführt) und das Andere zum Ausführen des Bestellauftrages. Hierzu sollte in dem Fenster, jeweils die aktuelle Ausgabe kommen, was gemacht wird.

Ist so etwas möglich?

Im Moment bewerkstellige ich dies so (ohne Fenster)

Code: Alles auswählen

                                ### FTP-Work
                                def ftp_work():
                                    try:
                                        # Modul FTP-Versand
                                        ftp_versand(auftrag, auftragdatei, zieladresse, benutzernamen, passwort, ftpverzeichnis)
                                        print('Der FTP-Versand war erfolgreich, Bestelldatei wurde versendet!')

                                        # Bestelldatei sichern
                                        zielordner(export, auftrag, export_path)
                                    except:
                                        print('Fehler beim FTP-Versand, der FTP-Versand wurde abgebrochen!')

                                        # Bestelldatei sichern
                                        zielordner(export, auftrag, fehler_path)

                                frage = ('Möchten Sie den Bestellauftrag absenden?')
                                infos = ('Bestellung für Lieferant: ' + lieferant + ', Auftragnummer: ' + auftragnummer + ' durchführen?')
                                run = functools.partial(ftp_work)
                                abfrage(frage, infos, run)
Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ich habe mal was zusammengebastelt:

Code: Alles auswählen

from Tkinter import *

import tkSimpleDialog, tkMessageBox

class DialogFenster(tkSimpleDialog.Dialog):
    ## so leitet man in Python aus einer Klasse ab!
    ## Aufruf: NamenDialog = DialogFenster(root)
    def body(self, master):  ## wird überschrieben
        self.titel = titel
        self.title(self.titel)

        self.info = info

        self.namen = Label(master, text=self.info)
        self.namen.pack(side=LEFT)


    def apply(self):  ## wird überschrieben
        self.result = 1 ## alles ok!

def benutzer(titel, info):
    root = Tk()
    NamenDialog = DialogFenster(root)
    if NamenDialog.result <> None:
        tkMessageBox.showinfo('Info','Bestellauftrag wurde versendet!')

titel = 'Bestellauftrag'
info = 'Achtung, neuer Auftrag!\nAuftragnummer: 4711, Lieferant: Mops'

benutzer(titel, info)
So, in der Art wäre der Ablauf.
Es sind zwar mehrere Fenster im Einsatz, aber das wäre nicht so schlimm.
Was mich etwas irritiert, ist daß wenn das erste Fenster geöffnet ist, ein zweites leeres Fenster noch dazu geöffnet ist.
Muß das so sein, oder kann man das ändern?

Hoffe, ihr habt mir noch ein paar gute Ratschläge!
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ich habe das mal so in meinem Pythonprogramm umgesetzt:

Code: Alles auswählen

                                ### GUI ###
                                class DialogFenster(tkSimpleDialog.Dialog):
                                    ## so leitet man in Python aus einer Klasse ab!
                                    ## Aufruf: NamenDialog = DialogFenster(root)
                                    def body(self, master):  ## wird überschrieben
                                        self.titel = titel
                                        self.title(self.titel)

                                        self.auftraginfo = auftraginfo

                                        self.namen = Label(master, text=self.auftraginfo)
                                        self.namen.pack(side=LEFT)


                                    def apply(self):  ## wird überschrieben
                                        self.result = 1 ## alles ok!

                                ### FTP-Work
                                def ftp_work(titel, auftraginfo):
                                    root = Tk()
                                    NamenDialog = DialogFenster(root)
                                    if NamenDialog.result <> None:
                                        try:
                                            # Modul FTP-Versand
                                            ftp_versand(auftrag, auftragdatei, zieladresse, benutzernamen, passwort, ftpverzeichnis)
                                            info = ('Der FTP-Versand war erfolgreich, Bestelldatei wurde versendet!')

                                            # Bestelldatei sichern
                                            zielordner(export, auftrag, export_path)
                                        except:
                                            info = ('Fehler beim FTP-Versand, der FTP-Versand wurde abgebrochen!')

                                            # Bestelldatei sichern
                                            zielordner(export, auftrag, fehler_path)
                                        tkMessageBox.showinfo('Info', info)

                                auftraginfo = ('Bestellung für Lieferant: ' + lieferant + ', Auftragnummer: ' + auftragnummer + ' durchführen?')
                                titel = 'Bestellauftrag'
                                
                                ftp_work(titel, auftraginfo)
Das erste Fenster öffnet sich und informiert über einen Bestellauftrag.
Nach dem ich auf den OK-Button geklickt habe, wird die Bestelldatei per FTP versendet und ich erhalte anschließend die Info, ob der FTP-Versand erfolgreich war oder nicht. Wenn ich aber dann bei diesem Fenster auf Ok klicke, passiert nichts.
Auch beim ersten Fenster, wenn ich auf das CANCEL-Button klicke passiert auch nichts.

Da könnte ich Eure Hilfe brauchen.

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

So, bin selbst drauf gekommen! :D
Mit root.destroy(), konnte ich das problem lösen.

Code: Alles auswählen

                                        tkMessageBox.showinfo('Info', info)
                                        if not None:
                                            root.destroy() 
BlackJack

Ich hoffe mal da steht nicht wirklich ``if not None:`` im Quelltext. ;-)
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Beim Versuch, diesen Bereich aus meinem Programm herauszunehmen und in ein eigene Pythondatei zu nehmen und dann von dort aus das Modul bzw. die GUI aufzurufen, habe ich Schwierigkeiten.

Code: Alles auswählen

### GUI ###
class DialogFenster(tkSimpleDialog.Dialog):
    ## so leitet man in Python aus einer Klasse ab!
    ## Aufruf: NamenDialog = DialogFenster(root)
    def body(self, master):  ## wird überschrieben
        self.titel = titel
        self.title(self.titel)

        self.auftraginfo = auftraginfo

        self.namen = Label(master, text=self.auftraginfo)
        self.namen.pack(side=LEFT)

    def apply(self):  ## wird überschrieben
        self.result = 1 ## alles ok!

### FTP-Work
def ftp_work(titel, auftraginfo):
    root = Tk()
    NamenDialog = DialogFenster(root)
    if NamenDialog.result <> None:
        try:
            # Modul FTP-Versand
            ftp_versand(auftrag, auftragdatei, zieladresse, benutzernamen, passwort, ftpverzeichnis)
            info = ('Der FTP-Versand war erfolgreich, Bestelldatei wurde versendet!')

            # Bestelldatei sichern
            zielordner(export, auftrag, export_path)
        except:
            info = ('Fehler beim FTP-Versand, der FTP-Versand wurde abgebrochen!')

            # Bestelldatei sichern
            zielordner(export, auftrag, fehler_path)
            tkMessageBox.showinfo('Info', info)
                if not None:
                    root.destroy() 
    else:
        # Bestelldatei umbenennen und nach Ordner .. verschieben
        quelle = auftrag
        ersatzname = (lieferantnummer + 'officeplanet.' + endung + '-' + auftragdatei)
        ziel = os.path.join(os.path.dirname(__file__),  offen_path, ersatzname)
        os.rename(quelle, ziel)
        info = ('Der FTP-Versand wurde abgebrochen!')
    tkMessageBox.showinfo('Info', info)
    if not None:
        root.destroy() 
Wie kann ich das machen, daß der Aufruf der GUI aus einem anderen Pythonprogramm funktioniert?

Grüße Nobuddy
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

BlackJack hat geschrieben:Ich hoffe mal da steht nicht wirklich ``if not None:`` im Quelltext. ;-)
Doch das tut es, wäre die 'if <> None' besser?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Nobuddy hat geschrieben: Doch das tut es, wäre die 'if <> None' besser?
Um Gottes Willen, nee! Nichts davon ist irgend wie *gut* :-D

Code: Alles auswählen

In [23]: if not None:
   ....:     print("Ich bin immer wahr!")
   ....:     
Ich bin immer wahr!
Du kannst Dir das anhand der `bool`-Funktion klar machen:

Code: Alles auswählen

In [26]: bool(None)
Out[26]: False
`bool` gibt zu einem beliebigen Objekt seinen Wahrheitswert zurück. (Doku s. Built-in Functions)

Damit ist klar, was passiert:

Code: Alles auswählen

In [27]: not False
Out[27]: True
Du packst hinter `if` einen Ausdruck, der *immer* wahr ist. Ergo wird der Code *immer* aufgerufen. Und bei so etwas, kann man sich `if` schlicht sparen und den auszuführenden Code auch direkt hinschreiben...
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Also einfach 'root.destroy()' ohne die if-Abfrage davor.

Danke und Grüße
Nobuddy
BlackJack

@Nobuddy: Ich glaube ich hatte ``<>`` schon mal irgendwo in Deinem Quelltext gesehen: Gewöhn Dir das am besten auch schnell wieder ab, beziehungsweise gar nicht erst an. Der Operator war schon „deprecated” als ich mit Python angefangen habe, also schon ziemlich lange. Ungleich testet man mit ``!=``.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Eigentlich, benutze ich '!=' ... außer wenn ich fremden Code kopiere, da kann sich so etwas einschleichen ..., aber ich schreibe es mir hinter die Ohren! :wink:

Hast Du mir evtl. auch einen Tipp zu meinem Post (etwas weiter oben, GUI-Modul)?
Antworten