2. Montag im Monat. Und ?

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.
Antworten
mosimfs
User
Beiträge: 28
Registriert: Sonntag 30. Juni 2019, 13:07

Hallo Forumleser,
Lesen tun ja viele, schreiben nur wenige und die mit Vorbehalt.
Einen Wochentag im Monat im voraus bestimmen, eine Möglichkeit.

Code: Alles auswählen

#----------------------------------------------------------------------------
def Clubabend():
    Ca = False
    x=0
    while Ca == False:
        nT = datetime.date.today() + datetime.timedelta(x)
        if nT.day >= 8 and nT.day <= 14 and nT.weekday() == 0:  # 2. Montag
            Ca = nT.day,nT.month,nT.year
        x+=1
    print(" nächster Clubabend: %02i" % Ca[0]+ ".%02i" % Ca[1] +
                                 ".%02i" % Ca[2] + ' in ' + str(x) + ' Tage')    
#----------------------------------------------------------------------------
Vieleicht kann's wer brauchen. Und ?
Wer weiß warum diese Fehlermeldung, obwohl es trotzdem funktioniert angezeigt wird.
RuntimeError: cannot join thread before it is started
Ohne der .join() Zeile wird das Foto nur Schwarz angezeigt. Ohne Fehlermeldung.

Code: Alles auswählen

KFoto=Button(master=Startfenster, bg="#000", command=Monatauswahl, relief=RAISED)
    KFoto.grid(column=0, row=2, columnspan=10, pady=3, padx=3)
    img=Image.open(SO+datei)
    a,b = img.size
    if a/b >= 1920/1080:
        k = 1920/a/2.75
    else:
        k = 1080/b/1.5
    if k*a > 699:
        k = 698/(k*a)*k
    img = img.resize(size=(int(k*a), int(k*b)))
    imgTk = ImageTk.PhotoImage(img)
    Thread(target=KFoto.config(image=imgTk)).start()
    Thread(target=KFoto.config(image=imgTk)).join()
Bin schon ganz neugierig. lg
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Die ganzen Abkürzungen machen den Code nicht unbedingt verständlicher.

Um den Leuten hier das Lesen zu vereinfachen empfehle ich dir mal den PEP8 Style Guide anzuschauen.
Zuletzt geändert von Jankie am Dienstag 9. Juli 2019, 10:08, insgesamt 1-mal geändert.
xXSkyWalkerXx1
User
Beiträge: 379
Registriert: Mittwoch 27. Juni 2018, 17:39

Vllt musst du den Thread ersteinmal als Variable deklarieren?

Code: Alles auswählen

thread = Thread(target=KFoto.config(image=imgTk))
thread.start()
thread.join()
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hallo mosimfs,

Antworten im Forum erhalten ja viele, die darin enthaltenen Hinweise umsetzen hingegen nur die wenigsten.

Und bezueglich deines Thread-Problems: das ist auf gleich mehreren Ebenen falsch.

Fangen wir damit an, dass nur weil zwei Ausdrueck gleich aussehen sie nicht irgendwie magisch das gleiche Objekt darstellen. Oder wuerdest du erwarten wenn du zweimal "print('clubabend')" hinschreibst, dass das nur einmal passiert? Wenn nicht, warum sollte dann Thread(target=KFoto.config(image=imgTk)) jeweils nur EINEN Thread erzeugen, statt jedes mal einen?

Womit sich auch deine eigentliche Frage klaert: einen Thread starten, und dann einen zweiten erstellen, und auf DEN zu warten, ist halt nicht was du tun willst. Der ist dann eben noch nicht gestartet. Du muesstest dir den ersten also merken, und DARAUF dann join aufrufen.

Dann ist es zudem sinnlos einen Thread zu starten, um auf den dann gleich mit join zu warten. Dann kann man die Aufgabe auch gleich erledigen. Threads sind keine magisches Beschleunigungsexlixir.

Zusaetzlich machst du natuerlich den klassischen Fehler, den eigentlich jeder macht, der Threads das erste mal benutzt. Du denkst "KFoto.config(image=imgTk)" wuerde nebenlaeufig ausgefuehrt. Wird es nicht. target muss ein CALLABLE bekommen. Also eine Funktion. Was hier passiert ist, dass KFoto.config(image=imgTk) einfach durchgerechnet wird, und etwas zurueck gibt. Wahrscheinlich None. Und DAS wird dann ausgefuehrt. Was natuerlich keinen Sinn ergibt, None kann man ja gar nicht ausfuehren. Die Loesung laege in dem dir schon bekannten functools.partial.

Und wenn wir jetzt mal annehmen, das du das alles umsetzt (siehe meine Eingangsbemerkung): dann hast du einen kapitalen Bock geschossen, denn GUI Elemente darf man NUR im main-Thread manipulieren. Der Versuch das anders zu machen fuehrt frueher oder spaeter zu einem harten Absturz, weil GUI-Toolkits ihre internen Datenstrukturen nicht gegen so etwas schuetzen.

Als Bonus noch der Hinweis: dein Programm wird kein Bild darstellen, weil du es versaeumst dir eine Referenz auf PhotoImage zu merken. Leider ein klassischer Fallstrick von tkinter, dessen Loesung hier im Forum schon oft diskutiert wurde, ein bisschen suchen hilft dir da hoffentlich weiter.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@mosimfs: allgemein zum Code: Die Einrückung strukturiert den Code optisch. Da ist es eher störend, wenn noch Zeilen mit vielen Minuszeichen dazwischen stehen. Funktionen sollten nach Tätigkeiten benannt werden, aber `Clubabend` ist keine. Funktionsnamen und Variablennamen werden nach Konvention klein_mit_unterstrich geschrieben. Keine Abkürzungen. Was soll `Ca` den heißen?
Variablen sollten nur einen Typ haben, und ihn nicht von Boolean nach Tuple ändern. Wenn Du eine while-Schleife hast, die erst einen Dummy-Wert zum Starten braucht, dann willst Du eigentlich eine while-True-Schleife, die Du per `break` verläßt.
`x´ ist ein schlechter Name für eine Anzahl Tage. Auch würde ich die Tage nicht einzeln zählen. Erster Schritt wäre, mit weekday die Anzahl Tage bis Montag zu ermitteln und dort hinzugehen, und dann Wochenweise auf den 8 bis 14 zu springen.

Wenn Du String-Formatierung nutzt, warum stückelst Du dann immer noch die Teile per + zusammen?

Code: Alles auswählen

def print_next_club_night():
    today = datetime.date.today()
    next_date = today
    weekday = next_date.weekday()
    if weekday != 0:
        # jump to the next monday
        next_date += datetime.timedelta(7-weekday)
    while not (8 <= next_date.day <= 14):
        # jump to the next week
        next_date += datetime.timedelta(7)
    print("nächster Clubabend: {:%d.%m.%Y} in {} Tagen".format(next_date, (next_date-today).days))
mosimfs
User
Beiträge: 28
Registriert: Sonntag 30. Juni 2019, 13:07

Hi, danke für die Rückmeldungen.
zu den Thread's: Eigentlich sollte doch das Foto angezeigt werden mit,

KFoto=Button(master=Startfenster, bg="#000", command=Monatauswahl, image=imgTk, relief=RAISED)
KFoto.grid(column=0, row=2, columnspan=10, pady=3, padx=3)

Nein es wird nur ein schwarzes Rechteck, der Fotogröße entsprechend angezeigt.
Das gleiche passiert bei KFoto.config(image=imgTk)

Bei dem alten _thread funktioniert es, _thread.start_new_thread(image=imgTk, ())
Beim neuen, erst wenn auch .join() ausgeführt wird. Allerdings bei beide, mit der oben angeführten Fehlermeldung.

Hallo __deets__,
deine Beschreibung wird schon stimmen, allerdings die Fotos werden ja angezeigt nach .join,
ohne .join nur die schwarzen Rechtecke. Vielleicht erklärst kurz wie es richtig funktioniert.

Anmerkung:
Ich weiß, wir die sich an's Forum wenden sind keine routinierten Python-Kenner.
Wir wollen unsere Projekte zum laufen bringen und man lernt ständig dazu.
Was nützen die großartigen Erklärungen wenn man noch nicht soweit ist sie zu verstehen.
lg
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Es hat nichts mit Verstaendnis zu tun gegebene Hinweise zu Namenskonventionen zu ignorieren. Da geht es um Lesbarkeit, nicht um Semantik.

Und das das Bild sonst nicht angezeigt wird deutet auf das Problem hin, das ich in meinem letzten Absatz beschrieben habe. Hast du wie vorgeschlagen PhotoImage mal hier im Forum gesucht? Oder mal die offizielle Dokumentation dazu durchgelesen? Auch da wird auf das Problem hingewiesen.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mosimfs: Zu den Threads: Es ist egal ob Du `threading` oder `_threads` verwendest, es ist beides falsch wenn da aus einem anderen Thread heraus als dem in dem die `mainloop()` läuft, die GUI veränderst. Nur ist `_threads` ein bisschen mehr falsch, weil man das nicht verwenden sollte, da es nicht (mehr) Teil der öffentlichen API ist.

Das Problem dabei ist, dass das mit den Threads *scheinbar* funktionieren kann, aber es ist eben nicht garantiert, bzw. schlimmer, irgendwann geht das garantiert schief. Und dann nicht einfach so das etwas nicht angezeigt wird, sondern so, dass das gesamte Programm hart abstürzt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Um das auch nochmal ganz klar zu sagen: ich weiss nicht, was dich dazu bewogen hat, einfach mal mit den Threads rumzuspielen. Tatsache ist aber, dass der vermeintliche Erfolg auf toenernen Fuessen steht. Es ist nicht korrekt, das so zu machen. Und wenn du das nicht glauben magst, dann sei dir ein kleines Gedankenexperiment ans Herz gelegt: wenn ich dir sage, dass es eine sehr dumme Idee ist, mit verbundenen Augen und Ohren einfach ueber eine Strasse zu laufen, dann bleibt das auch dann eine schlechte Idee, wenn du das einmal ausprobiert hast, und dabei zufaellig nicht verletzt wurdest. Wir erzaehlen das nicht, weil wir dich hier gaengeln wollen.
mosimfs
User
Beiträge: 28
Registriert: Sonntag 30. Juni 2019, 13:07

Hi ihr Zwei,
Stimmt ich rufe den Thread aus bereits einem laufenden Thread auf. Erkenne ich jetzt erst. Jetzt muss ich mal überlegen wie ich das umgehen kann. Vielen Dank.
mosimfs
User
Beiträge: 28
Registriert: Sonntag 30. Juni 2019, 13:07

Erfolgsmeldung:

__blackjack__, hatte .mainloop() erwend und siehe da so funktioniert es, mit und auch ohne Thread.

KFoto=Button(master=Startfenster, bg="#000", command=Monatauswahl, image=imgTk, relief=RAISED)
KFoto.grid(column=0, row=2, columnspan=10, pady=3, padx=3)
Startfenster.mainloop()

Startfenster.mainloop() steht zwar auch am Ende des Hauptprogramm.
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@mosimfs: Dann startest Du eine zweite `mainloop()` was unsinnig bis falsch ist. Das heisst Hauptschleife, die sollte nur einmal aufgerufen werden. Das Problem ist, wie __deets__ bereits geschrieben hat, dass Du eine Referenz auf Python-Seite auf das `PhotoImage`-Objekt behalten musst. Sonst räumt die Speicherverwaltung von Python die Bilddaten weg und Tk hat nichts mehr zum Anzeigen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
mosimfs
User
Beiträge: 28
Registriert: Sonntag 30. Juni 2019, 13:07

Ok und wie behalte ich die Referenz?
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

__deets__ hat geschrieben: Dienstag 9. Juli 2019, 16:23Hast du wie vorgeschlagen PhotoImage mal hier im Forum gesucht? Oder mal die offizielle Dokumentation dazu durchgelesen? Auch da wird auf das Problem hingewiesen.
Antworten