Seite 2 von 9

Re: Labeldruck und was draus folgt

Verfasst: Mittwoch 4. März 2020, 20:09
von theoS
Und noch was hab ich "geschafft". Ich konnte einen Ordner erzeugen und den mit den Dateien befüllen.
Dazu habe ich mir eine Funktion geschrieben.

Code: Alles auswählen

def checkfolder():    
    if not Path("../.DruckData/").exists():
        p = Path("../.DruckData/")
        p.mkdir(parents=True, exist_ok=True)
legt im Home-Ordner des Users (gibt eh nur den einen) einen versteckten Ordner an, die wird dann unten aufgerufen

Code: Alles auswählen

checkfolder() #funktion die oben steht und den Folder ggf. erzeugt
        pfad_ordner = Path("../.DruckData/") #das hätte ich mir irgendwie von oben runterziehen können, aber wie??
        
        ausgabe_name = pfad_ordner/"testT{}.zpl".format(column)
        
        with Path(ausgabe_name) as raus_text:
            raus_text.write_text(text_in_datei_aus_csv, encoding="utf-8")

Re: Labeldruck und was draus folgt

Verfasst: Mittwoch 4. März 2020, 20:59
von theoS
Hab ich dann noch mal ein wenig nachgegrübelt und die Einrückungen geradegebogen, jetzt gibt mir die Funktion auch den Pfad weiter.
Oben die Funktion:

Code: Alles auswählen

def checkfolder():    #checkt ab ob es den Ordner gibt, legt ihn an
    p = Path("../.DruckData/")    
    if not p.exists():
        p.mkdir(parents=True, exist_ok=True)
    return p    #der Rückgabewert der dann unten gebraucht wird
Unten der Aufruf und die Dateierzeugung:

Code: Alles auswählen

pfad_ordner  = checkfolder() #ruft die Funktion die dann den Ordern anlegt und den Pfad zurückgibt

        ausgabe_name = pfad_ordner/"testT{}.zpl".format(column)

        with Path(ausgabe_name) as raus_text:
            raus_text.write_text(text_in_datei_aus_csv, encoding="utf-8")
die Funktion wird halt jetzt jedesmal gerufen, vielleicht fällt mir da noch was ein. Oder vielleicht gehts ja ganz anders.

Re: Labeldruck und was draus folgt

Verfasst: Donnerstag 5. März 2020, 00:05
von __blackjack__
@theoS: Das `Path`-Objekte selbst auch Kontextmanager sind war micht nicht klar, weiss jetzt ohne nachzulesen auch gar nicht was das wohl bedeuten mag. Also mit anderen Worten ``with Path(…) as raus_text:`` bringt nichts. Es ging um *Datei*-Objekte und da bringt es das die geschlossen werden wenn der Programmfluss den ``with``-Block verlässt, und zwar egal aus welchem Grund das passiert.

Das hier wäre das was man nur braucht:

Code: Alles auswählen

Path(ausgabe_name).write_text(text_in_datei_aus_csv, "utf-8")
`raus_text` für eine Datei und `text_in_datei_aus_csv` für Text der nicht in einer Datei ist sind wirklich keine guten Namen. Und wo der Text mal her kam ist normalweise auch völlig egal.

Das ``Path("../.DruckData/")`` einen Ordner im Heimatverzeichnis des Benutzers anlegt ist ja eher Zufall, beziehungsweise funktioniert nur wenn das aktuelle Arbeitsverzeichnis eines im Heimatverzeichnis dieses Benutzer ist. Für das Heimatverzeichnis hat `Path` die Klassenmethode `home()`, die unabhängig vom aktuellen Arbeitsverzeichnis funktioniert.

Von einer Funktion die `checkfolder()` heisst würde man erwarten das die etwas prüft, nicht das die ein Verzeichnis anlegt. Der Test mit `exists()` ist unnötig, man kann das Verzeichnis doch einfach anlegen lassen mit ``exists_ok=True``.

"../.DruckData/" sollte man auch nicht mehr als einmal im Programm stehen haben. Wenn man das mal ändern möchte sollte man das nur an einer Stelle anpassen müssen und nicht an mehreren. Das macht Arbeit und ist fehleranfällig.

`a` ist ein schlechter Name. Wenn der `rows` heissen würde, nach dem was da tatsächlich enthalten ist, dann würde man auch sehen das `column` ein falscher Name ist, denn das ist ja weder eine Spalte noch eine Spaltennummer sondern eine Zeilen-/Datensatznummer.

`printDat()` ist als Name auch nicht gut. Da wird nichts mit `print()` ausgegeben sondern es werden Dateien gespeichert. Das wird aus dem Namen nicht klar.

Die ganzen ``+=``-Operation sind unübersichtlich und ineffizient. In den mehrzeiligen Zeichenkettenliteralen sind führende Leerzeichen die in den Dateien bestimmt nicht schön aussehen. Wenn man in einer Schleife, oder wie hier manuell eine Zeichenkette mit ``+=`` aufbaut, dann ist der idiomatische Weg in Python eine Liste mit den Teilen zu erstellen und die mit der `join()`-Methode auf Zeichenketten zusammen zu setzen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import csv
from pathlib import Path


ABFRAGE_FILENAME = Path(__file__).with_name("TB_Ausgabe_Abfrage8StueckII.txt")


def save_rows_as_files(rows):
    for file_number, row in enumerate(rows):
        text = "\n".join(
            [
                "^XA",
                "^FO15,90^GB780,0,8,^FS",
                "^FO15,250^GB780,0,8,^FS",
                "^FO15,700^GB780,0,8,^FS",
                "^FO0,0^GB600,200,2",
                "^FO15,20^GB780,785,4^FS",
                "^FO0,40^A0,50,50^FB800,1,0,C^FD",
                #
                # muss ich noch rauskriegen wie das in die csv kommt
                #
                "ABC Dingsbums",
                "^FS",
                "^FO0,110^A0,60,60^FB800,1,0,C^FD",
                row[1],
                "^FS",
                "^FO0,190^A0,70,70^FB800,1,0,C^FD",
                row[2],
                "^FS",
                "^FO0,80^BY3",
                "^BCN,170,Y,N,N",
                "^FO130,270^BY4^FD",
                #
                # das muss noch dynamisch werden
                #
                "12345667890",
                "^FS",
                "^FO0,500^A0,60,50^FB800,,0,C^FD",
                row[3],
                "^FS",
                "^FO0,580^A0,60,50^FB800,,0,C^FD",
                row[4],
                "^FS",
                "^FO0,730^A0,60,60^FB800,1,0,C^FD",
                row[5],
                "^FS",
                "^XZ",
                "",
            ]
        )
        path = Path.home() / ".DruckData"
        path.mkdir(exist_ok=True)
        path.with_name(f"testT{file_number}.zpl").write_text(text, "utf-8")


def main():
    #
    # TODO Falls ASCII nicht ausreicht, hier die tatsächliche Kodierung
    # einsetzen.
    #
    with ABFRAGE_FILENAME.open(encoding="ascii") as lines:
        rows = csv.reader(lines, delimiter=";")
        next(rows)  # Skip first row.
        save_rows_as_files(rows)


if __name__ == "__main__":
    main()

Re: Labeldruck und was draus folgt

Verfasst: Donnerstag 5. März 2020, 08:51
von theoS
Hallo blackjack, danke für den Input. Das muss ich dann heute Abend mal testen und nachvollziehen.
(ich hab viel dazu gelesen und dachte, das mit dem with muss sein wegen evtl. Fehlerbehandlung.)
Nur eine Frage gleich noch.
Ich habe ja vor, diese Datei jedesmal anzupassen wenn ein Knopf gerückt wird. Die Zeile mit der Bar-Code-Nummer soll dann bei jedem Knopfdruck um 1 erhöht werden, geht das auch mit der "Listenmethode"?
(Nicht dass ich da schon einen Plan hätte, wie ich das überhaupt anstelle :))

Re: Labeldruck und was draus folgt

Verfasst: Donnerstag 5. März 2020, 12:18
von __blackjack__
@theoS: ``with`` ist nicht zur Fehlerbehandlung aber im Falle von Ausnahmen innerhalb des ``with``-Blocks wird noch das ausgeführt was das Objekt was da mit ``with`` verwendet wird in dem Falle vorgesehen hat. Und bei Dateien ist das ein `close()`. Ohne ``with`` musste man ``try``/``finally`` dafür verwenden:

Code: Alles auswählen

with open(...) as file:
    ...

# <=>

file = open(...)
try:
    ...
finally:
    file.close()
Die Liste enthält Zeilen (ohne "\n") als Elemente. Da kannst Du beliebige Ausdrücke verwenden die eine Zeichenkette liefern. Ich würde der Funktion auch mehr als Argument übergeben als da jetzt übergeben wird. Also beispielsweise das Zielverzeichnis und das Dateinamentemplate. Und ich würde das auch auf mehr Funktionen verteilen, alleine um da besser Unit Tests für schreiben zu können zum Beispiel das Erstellen vom Inhalt *einer* Datei in einer eigenen Funktion.

Re: Labeldruck und was draus folgt

Verfasst: Donnerstag 5. März 2020, 23:50
von theoS
Danke für die Info, das hatte ich dann anders interpretiert. (Ausnahmen sind für mich noch "Fehler")
DAnke auch für deinen Code..
Hab deinen Code getestet, sieht deutlich ordentlicher aus als meiner :)
Aber leider krieg ich ihn nicht zum Laufen.
Die Codierung ist wohl utf-8 dann mault es nicht schon rum bevor es was tut.
Es kam zuerst immer diese Meldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/earl/projekt/prnDateiErzeugerIvb.py", line 69, in <module>
    main()
  File "/home/earl/projekt/prnDateiErzeugerIvb.py", line 65, in main
    save_rows_as_files(rows)
  File "/home/earl/projekt/prnDateiErzeugerIvb.py", line 26, in save_rows_as_files
    row[1],
IndexError: list index out of range
>>> 
Jetzt hab ich noch mal nachgeschaut, das geht trotz dem ganzen Rot: Der Ordner wird angelegt, die Dateien geschrieben, allerdings direkt im home-Verzeichnis, nicht im angelegten Ordner.
Und, was merkwürdig ist, das Ding funktioniert komplett ohne Fehlermeldung mit der "Original-CSV", hab ich also in meiner Test -CSV was verkehrtes drin, dass das Rote kommt.

Jetzt muss ich noch grübeln, wie dein Befehl die Dateien zu speichern aufgebaut ist, denn wenn ich ihn anschaue, weiß ich es nicht.

Re: Labeldruck und was draus folgt

Verfasst: Donnerstag 5. März 2020, 23:58
von __blackjack__
Upsi, die Zeile müsste dann wohl besser so lauten:

Code: Alles auswählen

        (path / f"testT{file_number}.zpl").write_text(text, "utf-8")
Wenn ``row[1]`` einen `IndexError` zur Folge hat, dann gibt es wohl mindestens einen Datensatz der leer ist oder nur ein Element enthält, aber eben kein zweites.

Re: Labeldruck und was draus folgt

Verfasst: Freitag 6. März 2020, 07:45
von theoS
Danke.
Das ist aber schon schwer, das zu entscheiden, wo jetzt ein Slash hinkommt oder was anderes.
Wenn ich die Konstruktion google, komm ich auch nicht dahin. Wo finde ich denn so was?
Will da ja auch mal selbst drauf kommen.

Re: Labeldruck und was draus folgt

Verfasst: Freitag 6. März 2020, 08:18
von __blackjack__
@theoS: Das findet man in der Dokumentation zum `pathlib`-Modul. Man muss halt immer schauen was der Typ des Ergebnisses eines (Teil)Ausdrucks ist und dann in die Dokumentation von diesem Typ schauen. Hier geht es ja hauptsächlich um `pathlib.Path`. `path` ist ein `Path`. Beim ``/``-Operator kommt auch wieder ein `Path` bei heraus. Der einzigen anderen an dem Ausdruck beteiligten Datentyp sind `int` (`file_number`) und `str` (f"testT{file_number}.zpl", `text`, und "utf-8"). Und der Ausdruck besteht letztlich ja nur aus zwei bis drei ”Teilen” — eine Operation, die f-Zeichenkette mit der eingesetzten Variablen, und einem Methodenaufruf.

Re: Labeldruck und was draus folgt

Verfasst: Freitag 6. März 2020, 22:16
von theoS
@__blackjack__ tja, aber die Dokumentation ist leider nicht immer so, dass man das so wirklich versteht.
Immerhin habe ich jetzt nach gut 2 Stunden verstanden, wie man auf das Konstrukt, das enumerate() erzeugt auf einzelne Daten zugreifen kann. Vermute das was ich mir zusammengeschustert hab ist grottig, aber ich glaube ich hab das Prinzip verstanden.
Mal sehen.
Noch eine konkrete Frage:
Ich will ja die Nummerierung für den Barcode des Labels hochzählen, dass man weiß wieviele man da gedruckt hat.
Dass das auch präsent ist wenn man zwischendrin mal die Kiste ausschaltet, muss ich das ja in eine Datei speichern, oder gibt es da einen anderen Weg?
Dass das für die 8 verschiedenen Label nicht zu 8 verschiedenen Dateien führt (macht eigentlich auch nix) denke ich jetzt an eine csv. Das Modul vergewaltige ich ja eh schon :-)
Was würde(s)t du/ihr mir da raten?

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 13:19
von Sirius3
Ja, das kann man machen, 8 Zahlen per csv in einer Datei zu speichern. Oder json benutzen.

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 13:33
von __deets__
Oder sqlite.

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 13:45
von Sirius3
@__deets__: für 8 Zahlen?

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 14:14
von __deets__
Ob nun 10 oder 20 Kanonen auf Spatzen gerichtet werden - what's the harm? Und sqlite hat einen entscheidenden Vorteil: die wissen, wie man Bytes auf die Platte bekommt. Es klingt fuer mich so, als ob das dem TE durchaus wichtig ist. sqlite bringt Dinge wie flushing und journaling (oder aehnliches) mit. Wuerde man fuer JSON (oder CSV) nie schreiben, aber mindestens zB ein Vorgehen, bei dem man erst eine Datei unter neuem Namen anlegt & dann atomar tauscht ist angezeigt - wie eigentlich immer, wenn man Daten verlaesslich speichern will. Der Mehraufwand dafuer ist dann gespart.

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 15:22
von theoS
Uff, eine Diskussion.
Danke fürs Interesse. Mal sehen, da für mich beides neu ist und ich mich in beides einarbeiten muss ist das fast egal.
Es geht ja drum, dass die Zahlen zum einen bei jedem Knopfdruck/Labeldruck je Sorte hochzählen und zum anderen von außen auch ausgelesen werden können ohne dass man sich was verkrampft.
Ich schau mir das beides mal an. Was ich zuerst kapier und tut was ich brauche, wird gewinnen.
Danke erst mal.

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 15:37
von __deets__
Wer ist denn "aussen"? Und wie schaut der - mit einem Vergroesserungsglas, oder per SSH, oder ...?

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 19:59
von theoS
Noch eine Baustelle.
Das soll passieren wenn man einen USB Stick einsteckt. Der liefert dann die neuen Daten in einer csv-Datei und bekommt die Zahlen der gedruckten Labels. Vermutlich wird das dann suf Excel rauslaufen. Die Daten für die Label kommt via csv aus Access.

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 20:15
von sparrow
Welches Betriebssystem?

Re: Labeldruck und was draus folgt

Verfasst: Samstag 7. März 2020, 21:32
von theoS
sparrow hat geschrieben:Welches Betriebssystem?
Alles was in Python läuft, läuft auf einem Raspi mit "2019-09-26-raspbian-buster-full" Komplett Offline, drum der USB-Stick. Die Daten werden dann von einem Win10-Rechner kommen, bzw. dann ausgewertet. (sind ja nur die Zahlen)

Re: Labeldruck und was draus folgt

Verfasst: Montag 9. März 2020, 22:57
von theoS
Also, ich hab das jetzt mal so zusammengebaut und die Zähler lass ich hochzählen in einem csv. Das erschien mir jetzt zunächst mal als einfacher. Kommen sicher noch irgendwelche Probleme an die ich nicht gedacht hab. (z.B. dass die csv nicht da ist oder falsch aussieht.)
die zugehörige numbers.csv sieht so aus:

Code: Alles auswählen

Einsatzstelle;Anzahl
Dings 006;27
Dings 004;18
Dings 005;34
Dings 007;6
Dings 008;10
Dings 413;18
217;104
Dings 009;54
Das ist jetzt der code für Oberfläche die jetzt pro Knopfdruck eine Datei erzeugt die dann noch zum Drucker geschickt werden soll.

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
import csv
from pathlib import Path
from functools import partial


##ABFRAGE_FILENAME = Path(__file__).with_name("TB_Ausgabe_Abfrage8Stueck.txt")
PFAD = (Path.home() / ".DruckData")

ABFRAGE_FILENAME = (PFAD / "TB_Ausgabe_Abfrage8StueckII.txt")
ZAEHLER_FILENAME=(PFAD / 'numbers.csv')
#print(ZAEHLER_FILENAME)
#---------------- Knopf-Teil -------------------

#def click(e_st_z2):
#    print(e_st_z2)

def main():
    with ABFRAGE_FILENAME.open() as lines:
        data = list(csv.reader(lines, delimiter=";"))
        data.pop()
    root = tk.Tk()
    root.wm_title("Auswahl der Label")
    root.config(background = "#f2c618")
    right_frame = tk.Frame(root, width=1200, height = 400)
    right_frame.grid(row=0, column=1, padx=0, pady=0)
    button_frame = tk.Frame(right_frame)
    button_frame.grid(row=1, column=0, padx=10, pady=3)
    
    
    for index, entry in enumerate(data):
        row, column = divmod(index, 4) #hier werden die row und column zu Variablen und gefüllt mit dem Index
        button = tk.Button(button_frame, text="{}\n{}".format(entry[1],entry[2]), bg="#f2c618", width=15, height=10, command=partial(click, index)) 
        button.grid(row=row, column=column, padx=0, pady=0)                                                         #übergibt die Nummer in der Reihenfolge

    root.mainloop()

#-------------Datei--Teil -------------


def save_rows_as_files(row, first_line, file_number):
  
  
        text = "\n".join(
            [
                "^XA",
                "^FO15,90^GB780,0,8,^FS",
                "^FO15,250^GB780,0,8,^FS",
                "^FO15,700^GB780,0,8,^FS",
                "^FO0,0^GB600,200,2",
                "^FO15,20^GB780,785,4^FS",
                "^FO0,40^A0,50,50^FB800,1,0,C^FD",
                #
                # muss ich noch rauskriegen wie das in die csv kommt (vorerst statisch)
                #
                first_line,
                "^FS^FO0,110^A0,60,60^FB800,1,0,C^FD",
                row[1],
                "^FS^FO0,190^A0,70,70^FB800,1,0,C^FD",
                row[2],
                "^FS^FO0,80^BY3",
                "^BCN,170,Y,N,N",
                "^FO165,270^BY4^FD",
                #
                # das muss noch dynamisch werden
                #
                "12345667890",  ###hier soll die hochgezählte Nummer rein
                "^FS^FO0,500^A0,60,50^FB800,,0,C^FD",
                row[3],
                "^FS^FO0,580^A0,60,50^FB800,,0,C^FD",
                row[4],
                "^FS^FO0,730^A0,60,60^FB800,1,0,C^FD",
                row[5],
                "^FS",
                "^XZ",
                "",
            ]
        )

        
        PFAD.mkdir(exist_ok=True)
        (PFAD / f"testT{file_number}_{row[1]}.zpl").write_text(text, "utf-8")
#---------------Beim Klick: ----------------------

def click(file_number):        
    
    #
    with ABFRAGE_FILENAME.open(encoding="utf-8") as lines:
        rows = csv.reader(lines, delimiter=";")        
        first_line = "PZ DingsBums" #momentan noch fix, kann mit Abfrage kommen
        numb_fil = list(enumerate(rows))
        #file_number  #kommt vom Knopfdrücker
        row = numb_fil[file_number][1]        
        einsatzstelle=row[3]        
        save_rows_as_files(row, first_line, file_number)
        countprints(file_number,einsatzstelle)
##-----------------Hochzählen und in csv schreiben ----------

def countprints(file_number, einsatzstelle):    
    PFAD.mkdir(parents=True, exist_ok=True)
    (ZAEHLER_FILENAME / "numbers.csv")
    print(ZAEHLER_FILENAME)
    with ZAEHLER_FILENAME.open(encoding="utf-8") as zeilen:
            werte = list(csv.reader(zeilen, delimiter=";"))
            numhochgez=int(werte[file_number+1][1])+1
            werte[file_number+1][1]=numhochgez ##das muss jetzt noch irgendwie hoch in den zpl-code
            werte[file_number+1][0]=einsatzstelle
    with open(ZAEHLER_FILENAME, 'w') as f:
            writer = csv.writer(f, delimiter=';')
            writer.writerows(werte)

if __name__ == "__main__":
    main()
Baustelle jetzt erst mal "countprints" sollte einen Wert zurückgeben der dann in den Druck-Code mit eingebaut wird für den Barcode. Gibt irgendwas mit return, aber soweit bin ich noch nicht. :-)

Bin für jeden Hinweis dankbar. heut gehts ins Bett.