Eigene Klasse im mainloop laufend aktualisieren

Fragen zu Tkinter.
Antworten
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Hallo Zusammen :)

Nach langem Suchen bin ich auf dieses Froum gestoßen. Ich habe auch schon einiges an brauchbarem daraus gezogen. Vielen, vielen Dank an alle!!! :) Nun bin ich aber an einem Punkt wo ich nicht mehr weiter komme.
Ich habe in Python3 eine eigene Klasse erstellt die eine Analoguhr zeichnet. Bei der Erstellung des Objektes übergebe ich ihm die Werte für den Rahmen in der die Uhr erscheinen soll und die Größe der Uhr.
Desweiteren Werten noch zwei weitere Werte für die Anzeige übergeben. Genau diese Werte müssen jetzt aber immer wieder aktualisiert werden. Ich kann zwar die Werte zuweisen und sie werden auch erstellt aber ich weiß nun nicht wie ich sie laufend aktualisieren soll so dass das Hauptfenster auch stehen bleibt. Wenn ich eine Schleife einbaue läuft sie erst ab und erst dann wird das Hauptfenster erstellt.
Ich hoffe mir kann von euch jemand weiterhelfen. Schon mal vielen Dank im Voraus.

Grüße Jörg

Hier der Code:

Code: Alles auswählen

#!/usr/bin/python3
from tkinter import *
import tkinter
from math import *

from module.analoguhr import RhUhr
#from module.analoguhr import TempUhr

# root-Fenster
root = tkinter.Tk()
root.geometry("800x480")
root.title("Humimeter")
root.configure(background="black")
img = tkinter.PhotoImage(file='pics/humilogo.gif')
root.tk.call('wm', 'iconphoto', root._w, img)

# Rahmen erzeugen
toprahmen = Frame(root, bg="black", bd=8, relief=RIDGE)
toprahmen.grid()
rahmen_rh1 = Frame(toprahmen, bg="black", bd=2, relief=RIDGE)
rahmen_rh1.grid(row=0, column=0, pady=0, sticky=W + N)
rahmen_rh2 = Frame(toprahmen, bg="black", bd=2, relief=RIDGE)
rahmen_rh2.grid(row=0, column=1, pady=0, sticky=W + N)

# Testwerte fuer die Analog-RH-Uhr
folgeRh = 63.5
rhSoll = 65
zifferblattgroesse = 180

# Aufruf der RH-Analoguhr
testuhr1 = RhUhr(tkrahmen=rahmen_rh1, zifferblattgroesse=zifferblattgroesse)
testuhr1.setFolgeRh(folgeRh)
testuhr1.setSollRh(rhSoll)

root.mainloop()
und hier die Klasse:

Code: Alles auswählen

#!/usr/bin/env python3

from tkinter import *
from math import *
import tkinter as tk


class RhUhr(tk.Frame):
    def __init__(self, tkrahmen=None, zifferblattgroesse=100):
        tk.Frame.__init__(self, tkrahmen)
        self._zifferblattgroesse = zifferblattgroesse
        self.grid()
        self.erzeugeRhUhr()

    def setFolgeRh(self, folgeRh):
        self._humidity = folgeRh
        self._korrekturwert = (self._humidity) * 3  # Fuer Teilung des Kreises
        self._korrekturwert = (-self._korrekturwert)  # Vorzeichenwechsel
        self._cos_x = (sin(radians(self._korrekturwert)) *
                       self._zifferblatt_radius)
        self._cos_x = (self._cos_x + self._zifferblatt_radius)
        self._sin_y = (cos(radians(self._korrekturwert)) *
                       self._zifferblatt_radius)
        self._sin_y = self._sin_y + self._zifferblatt_radius
        self._w3.coords(self._sid_zeiger_rhneu,
                        self._zifferblatt_radius,
                        self._zifferblatt_radius,
                        self._cos_x, self._sin_y)  # Zeiger
        self._rh_anzeigen = self._humidity
        self._w3.itemconfigure(self._id_font_humidity, text=self._rh_anzeigen)

    def setSollRh(self, rhSoll):
        self._rhSoll = rhSoll

        self._zifferblatt_radius = self._zifferblattgroesse / 2
        self._strich_radius_in = (self._zifferblatt_radius * 0.9)

        self._alpha_soll = (-rhSoll * 3)
        self._start_x = (sin(radians(self._alpha_soll)) *
                         self._zifferblatt_radius)
        self._start_x = self._start_x + (self._zifferblatt_radius)
        self._start_y = (cos(radians(self._alpha_soll)) *
                         self._zifferblatt_radius)
        self._start_y = self._start_y + (self._zifferblatt_radius)
        self._end_x = (sin(radians(self._alpha_soll)) * self._strich_radius_in)
        self._end_x = self._end_x + (self._zifferblatt_radius)
        self._end_y = (cos(radians(self._alpha_soll)) * self._strich_radius_in)
        self._end_y = self._end_y + (self._zifferblatt_radius)
        self._w3.coords(self._id_soll_rh, self._start_x, self._start_y,
                        self._end_x, self._end_y)

    def erzeugeRhUhr(self):
        self._rh = 0
        self._rhSoll = 0

        #print ((self._zifferblattgroesse))

        # ZifferblattDurchmesser
        self._zifferblattgroesse = (self._zifferblattgroesse)
        # ZifferblattRadius
        self._zifferblatt_radius = (self._zifferblattgroesse / 2)
        # Liniestartpunkt innen Striche

        self._line_radius_in = (self._zifferblatt_radius * 0.6)
        # Liniestartpunkt aussen Striche
        self._line_radius_aus = (self._zifferblatt_radius * 0.7)
        # Linienendpunkt Sollstrich
        self._strich_radius_in = (self._zifferblatt_radius * 0.9)
        # Schriftgrösse der Ziffern
        self._zifferngroesse = int(self._zifferblatt_radius / 6)
        # ZiffernPostitionsverhältnis
        self._text_radius = (self._zifferblatt_radius * 0.8)

        # Schriftgrösse RH und Temp
        self._font_size_zifferblatt = int(self._zifferblatt_radius / 4)

        self._alpha = 90  # Startpunkt für die Linienteilung in Grad
        self._teilung = 30  # Teilung der Linien

        # Wert x für das Canvas-Grafikfenster
        self._canvas3_width = (self._zifferblattgroesse)
        # Wert y für das Canvas-Grafikfenster
        self._canvas3_height = (self._zifferblattgroesse)

        # Hier wird das Canvas-Zeichenfenster erstellt'
        self._w3 = tk.Canvas(self)
        self._w3["width"] = self._canvas3_width
        self._w3["height"] = self._canvas3_height
        self._w3["highlightthickness"] = 0
        self._w3["bd"] = 0

        self._w3.grid(row=0, column=0, padx=0)  # 'grid' für Rahmen platziert

        self._w3.create_rectangle(0, 0, self._zifferblattgroesse,
                                  self._zifferblattgroesse,
                                  fill="black")  # Zifferblatthintergrund
        self._w3.create_oval(0, 0, self._zifferblattgroesse,
                             self._zifferblattgroesse,
                             fill="AntiqueWhite", width=0)  # Zifferblatt

        self._w3.create_rectangle(0, 0, self._zifferblattgroesse,
                                  self._zifferblattgroesse,
                                  fill="black")  # Zifferblatthintergrund
        self._w3.create_oval(0, 0, self._zifferblattgroesse,
                             self._zifferblattgroesse,
                             fill="AntiqueWhite", width=0)  # Zifferblatt

        # grüner Gutbereich auf das Ziffferblatt Zeichnen ---------------------
        self._start_tk1 = (0, 0, self._zifferblattgroesse,
                           self._zifferblattgroesse)
        self._sartline = self._zifferblattgroesse * 0.2
        self._endline = self._zifferblattgroesse * 0.8
        self._start_tk2 = (self._sartline, self._sartline,
                           self._endline, self._endline)

        self._w3.create_arc(self._start_tk1, start=50, extent=30,
                      fill="green1", outline="")

        self._w3.create_arc(self._start_tk2, start=0, extent=180,
                      fill="AntiqueWhite", outline="")

        # Formel für die Winkelteilung der Teilstriche
        self._i = 1
        self._alpha_ziffer = (self._alpha)
        while self._i <= 7:
            self._start_x = ((sin(radians(self._alpha)) *
                             self._line_radius_in) +
                             (self._zifferblatt_radius))
            self._start_y = ((cos(radians(self._alpha)) *
                             self._line_radius_in) +
                             (self._zifferblatt_radius))
            self._end_x = ((sin(radians(self._alpha)) *
                           self._line_radius_aus) +
                           (self._zifferblatt_radius))
            self._end_y = ((cos(radians(self._alpha)) *
                            self._line_radius_aus) +
                            (self._zifferblatt_radius))
            self._text_x = ((sin(radians(self._alpha)) *
                            self._text_radius) +
                            (self._zifferblatt_radius))
            self._text_y = ((cos(radians(self._alpha)) *
                            self._text_radius) +
                            (self._zifferblatt_radius))

            # Teilstrich und Ziffern zeichnen
            self._w3.create_line(self._start_x, self._start_y,
                                 self._end_x, self._end_y, fill="black",
                                 width=2)
            self._w3.create_text(self._text_x, self._text_y,
                                 text=(self._alpha_ziffer),
                                 font=("Helvetica",
                                 (self._zifferngroesse), "bold"))

            self._i = (self._i + 1)  # Zähler erhöhen
            # Winkel Versetzen für die nächsten Linie
            self._alpha = (self._alpha + (self._teilung))
            self._alpha_ziffer = (self._alpha_ziffer - 10)

        # Sollwertstrich erstellen
        self._alpha_soll = (-self._rhSoll * 3)
        self._start_x = ((sin(radians(self._alpha_soll)) *
                         self._zifferblatt_radius) +
                         (self._zifferblatt_radius))
        self._start_y = ((cos(radians(self._alpha_soll)) *
                         self._zifferblatt_radius) +
                         (self._zifferblatt_radius))
        self._end_x = ((sin(radians(self._alpha_soll)) *
                       self._strich_radius_in) +
                       (self._zifferblatt_radius))
        self._end_y = ((cos(radians(self._alpha_soll)) *
                       self._strich_radius_in) +
                       (self._zifferblatt_radius))
        self._id_soll_rh = self._w3.create_line(self._start_x, self._start_y,
                                                self._end_x, self._end_y,
                                                fill="orange", width=4)

        # Zeiger erstellen
        self._cos2_x = self._zifferblatt_radius
        self._sin2_y = self._zifferblattgroesse
        self._sid_zeiger_rhneu = self._w3.create_line(self._zifferblatt_radius,
                                                      self._zifferblatt_radius,
                                                      self._cos2_x,
                                                      self._sin2_y,
                                                      fill="red", width=1)

        # Beschriftug für Digialwert erstellen
        self._font_rh = ("Helvetica", self._font_size_zifferblatt, "bold")
        self._text_pos_y = (self._zifferblatt_radius * 0.5 +
                           self._zifferblatt_radius)

        self._id_font_humidity = self._w3.create_text(self._zifferblatt_radius,
                                                      self._text_pos_y,
                                                      text="Hygro",
                                                      font=self._font_rh)  # RH

        self._font_rh = ("Helvetica", self._font_size_zifferblatt)
        self._text_pos_y = self._zifferblatt_radius * 0.7
        self._w3.create_text(self._zifferblatt_radius, self._text_pos_y,
                             text="%", font=self._font_rh, fill="#404040")

        # Mittenpunkte des Zeigers Vorbereitung RH
        self._radius_zeigermitte = (self._zifferblattgroesse / 20)
        self._radius_mittelstifft = (self._radius_zeigermitte / 3)
        self._zeiger_mitte_radius_1 = (self._zifferblatt_radius +
                                       self._radius_zeigermitte)
        self._zeiger_mitte_radius_2 = (self._zifferblatt_radius -
                                       self._radius_zeigermitte)
        self._zeiger_mitte_stift_1 = (self._zifferblatt_radius +
                                      self._radius_mittelstifft)
        self._zeiger_mitte_stift_2 = (self._zifferblatt_radius -
                                      self._radius_mittelstifft)

        # Zeigermittepunkte Zeichnen
        self._w3.create_oval(self._zeiger_mitte_radius_2,
                             self._zeiger_mitte_radius_2,
                             self._zeiger_mitte_radius_1,
                             self._zeiger_mitte_radius_1,
                             fill="red", width=0)  # Zeigermittelkreis
        self._w3.create_oval(self._zeiger_mitte_stift_2,
                             self._zeiger_mitte_stift_2,
                             self._zeiger_mitte_stift_1,
                             self._zeiger_mitte_stift_1,
                             fill="black", width=0)  # Mittelstifftkreis
BlackJack

@joerg123: Schau Dir mal die `after()`-Methode auf Widgets an. Damit kann man eine Funktion/Methode nach einer angegebenen Zeit ausführen lassen. Das musst Du dann nur noch regelmässig machen.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@joerg123: Sternchenimporte sind schlecht, weil man nicht kontrollieren kann, welche Namen da in den eigenen Namensraum geladen werden. Frames sollten nicht selbst platzieren, das ist Aufgabe dessen, der das Frame erzeugt. Alle Attribute sollten in __init__ erzeugt werden, damit man schnell sehen kann, welche Attribute ein Objekt insgesamt hat. Und es muß nicht alles als Attribut gespeichert werden. 90% Deiner Attribute sind keine. Du hast unübersichtlich viele Klammern. Was hilft es, einen kompletten Ausdruck oder eine einzelne Variable zu klammern? Viele Ausdrücke, die Du in mehrere Zuweisungen aufgespaltet hast, lassen sich auch in einem schreiben. Das Berechnen von x- und y-Koordinaten kommt so oft vor, dass das in eine eigene Methode gehört.

GUI-Programme sind ereignisgesteuert. Du mußt Ereignisse definieren, die dann die Zeiger umstellen.
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Herzlichen Dank für die schnellen Antworten!!!

BlackJack,
ich weiß zwar das man mint after eine Schleife generieren kann, aber ich komm einfach nicht dahinter wie ich das jetzt in meinen Code integrieren kann.

Code: Alles auswählen

class RhUhr(tk.Frame):
    def __init__(self, tkrahmen=None, zifferblattgroesse=100):
        tk.Frame.__init__(self, tkrahmen)
        self._zifferblattgroesse = zifferblattgroesse
        self.grid()
        self.erzeugeRhUhr()

    def setFolgeRh(self, folgeRh):
        self._humidity = folgeRh
        self._korrekturwert = (self._humidity) * 3  # Fuer Teilung des Kreises
        self._korrekturwert = (-self._korrekturwert)  # Vorzeichenwechsel
        self._cos_x = (sin(radians(self._korrekturwert)) *
                       self._zifferblatt_radius)
        self._cos_x = (self._cos_x + self._zifferblatt_radius)
        self._sin_y = (cos(radians(self._korrekturwert)) *
                       self._zifferblatt_radius)
        self._sin_y = self._sin_y + self._zifferblatt_radius
        self._w3.coords(self._sid_zeiger_rhneu,
                        self._zifferblatt_radius,
                        self._zifferblatt_radius,
                        self._cos_x, self._sin_y)  # Zeiger
        self._rh_anzeigen = self._humidity
        self._w3.itemconfigure(self._id_font_humidity, text=self._rh_anzeigen)
        self.tkrahmen.after(1000, self.setFolgeRh)  # geht so nicht!!!
hast du mir dazu vielleicht ein Beispiel wie das aussehen soll?

Sirius3,
ich weiß, das mit den Sternchen ist nicht gut. Muss ich auf jeden Fall noch ändern.
Wegen dem übergebenem Frame bin ich auch nicht so glücklich damit. Aber um die Uhr im Hauptfenster platzieren zu können viel mir nicht besseres ein.
Das mit den Attributen verstehe ich nicht wirklich. Gibt es dafür ein Beispiel wie man es richtig macht? Auch bei den anderen Dingen die du geschrieben hast, da hast du sicherlich Recht. Ich bin bemüht darum es besser zu machen. Aber da ich noch nicht lange programmiere fehlt es mir schwer auf Anhieb alles gleich zu verstehen. Ich habe gemerkt dass ich mit konkreten Beispielen am besten vorwärts komme. Ich würde mich sehr freuen wenn du mir das eine oder andere Beispiel geben könntest.

Und nochmals vielen, vielen Dank für eure Mühe
Grüße Jörg
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@joerg123: man darf nur etwas an ein Attribut binden, was man später, wenn die Methode fertig ist, nochmal braucht. Ein bißchen aufgeräumt, könnte es so aussehen:

Code: Alles auswählen

from math import sin, cos, radians
import tkinter as tk
 
class RhUhr(tk.Frame):
    def __init__(self, tkrahmen=None, zifferblattgroesse=100):
        tk.Frame.__init__(self, tkrahmen)
        self._zifferblattgroesse = zifferblattgroesse
        self._zifferblatt_radius = zifferblatt_radius = zifferblattgroesse / 2
        font_ziffer = ("Helvetica", int(zifferblatt_radius / 6), "bold")
        font_bold = ("Helvetica", int(zifferblatt_radius / 4), "bold")
        font_normal = ("Helvetica", int(zifferblatt_radius / 4))
 
        # Hier wird das Canvas-Zeichenfenster erstellt'
        canvas = tk.Canvas(self)
        canvas["width"] = zifferblattgroesse
        canvas["height"] = zifferblattgroesse
        canvas["highlightthickness"] = 0
        canvas["bd"] = 0
 
        canvas.grid(row=0, column=0, padx=0)  # 'grid' fuer Rahmen platziert
 
        canvas.create_rectangle(0, 0, zifferblattgroesse, zifferblattgroesse, fill="black")  # Zifferblatthintergrund
        canvas.create_oval(0, 0, zifferblattgroesse, zifferblattgroesse, fill="AntiqueWhite", width=0)  # Zifferblatt
 
        # gruener Gutbereich auf das Ziffferblatt Zeichnen ---------------------
        start_tk1 = (0, 0, zifferblattgroesse, zifferblattgroesse)
        startline = zifferblattgroesse * 0.2
        endline = zifferblattgroesse * 0.8
        start_tk2 = (startline, startline, endline, endline)
        canvas.create_arc(start_tk1, start=50, extent=30, fill="green1", outline="")
        canvas.create_arc(start_tk2, start=0, extent=180, fill="AntiqueWhite", outline="")
 
        # Formel fuer die Winkelteilung der Teilstriche
        for i in range(7):
            alpha = 90 + i * 30
            alpha_ziffer = 90 - i * 10
            start_x, start_y = self._angle_to_pos(alpha, 0.6)
            end_x, end_y = self._angle_to_pos(alpha, 0.7)
            text_x, text_y = self._angle_to_pos(alpha, 0.85)
 
            # Teilstrich und Ziffern zeichnen
            canvas.create_line(start_x, start_y, end_x, end_y, fill="black", width=2)
            canvas.create_text(text_x, text_y, text=alpha_ziffer, font=font_ziffer)

        # Sollwertstrich erstellen
        self._id_soll_rh = canvas.create_line(0,0,0,0,fill="orange", width=4)
 
        # Zeiger erstellen
        self._sid_zeiger_rhneu = canvas.create_line(0,0,0,0,fill="red", width=1)
 
        # Beschriftug fuer Digialwert erstellen
        x, y = self._angle_to_pos(0, 0.5)
        self._id_font_humidity = canvas.create_text(x, y, text="Hygro", font=font_bold)
        x, y = self._angle_to_pos(0, 0.7)
        canvas.create_text(x, y, text="%", font=font_normal, fill="#404040")
 
        # Mittenpunkte des Zeigers Vorbereitung RH
        zeigermitte = zifferblattgroesse / 20
        mittelstift = zeigermitte / 3
        r1 = zifferblatt_radius + zeigermitte
        r2 = zifferblatt_radius - zeigermitte
        s1 = zifferblatt_radius + mittelstift
        s2 = zifferblatt_radius - mittelstift
 
        # Zeigermittepunkte Zeichnen
        canvas.create_oval(r2, r2, r1, r1, fill="red", width=0)  # Zeigermittelkreis
        canvas.create_oval(s2, s2, s1, s1, fill="black", width=0)  # Mittelstiftkreis
        self._canvas = canvas

    def _angle_to_pos(self, angle, scale=1.0):
        angle = radians(angle)
        return ((scale * sin(angle) + 1) * self._zifferblatt_radius,
                (scale * cos(angle) + 1) * self._zifferblatt_radius)
 
    def setFolgeRh(self, folgeRh):
        korrekturwert = - 3 * folgeRh  # Fuer Teilung des Kreises
        x, y = self._angle_to_pos(korrekturwert)
        self._canvas.coords(self._sid_zeiger_rhneu,
                        self._zifferblatt_radius,
                        self._zifferblatt_radius,
                        x, y)  # Zeiger
        self._canvas.itemconfigure(self._id_font_humidity, text=folgeRh)
 
    def setSollRh(self, rhSoll):
        alpha_soll = -rhSoll * 3
        start_x, start_y = self._angle_to_pos(alpha_soll)
        end_x, end_y = self._angle_to_pos(alpha_soll, 0.9)
        self._canvas.coords(self._id_soll_rh, start_x, start_y, end_x, end_y)
 
def main():
    # root-Fenster
    root = tk.Tk()
    root.geometry("800x480")
    root.title("Humimeter")
    root.configure(background="black")
     
    # Rahmen erzeugen
    toprahmen = tk.Frame(root, bg="black", bd=8, relief=tk.RIDGE)
    toprahmen.grid()
    rahmen_rh1 = tk.Frame(toprahmen, bg="black", bd=2, relief=tk.RIDGE)
    rahmen_rh1.grid(row=0, column=0, pady=0, sticky=tk.W + tk.N)
    rahmen_rh2 = tk.Frame(toprahmen, bg="black", bd=2, relief=tk.RIDGE)
    rahmen_rh2.grid(row=0, column=1, pady=0, sticky=tk.W + tk.N)
     
    # Testwerte fuer die Analog-RH-Uhr
    folgeRh = 63.5
    rhSoll = 65
    zifferblattgroesse = 180
     
    # Aufruf der RH-Analoguhr
    testuhr1 = RhUhr(tkrahmen=rahmen_rh1, zifferblattgroesse=zifferblattgroesse)
    testuhr1.grid()
    testuhr1.setFolgeRh(folgeRh)
    testuhr1.setSollRh(rhSoll)
     
    root.mainloop()
    
if __name__ == '__main__':
    main()
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Hallo Sirius3,
zu allererst einmal einen recht Herzlichen Dank für das tolle Beispiel!!! Es ist wirklich fantastische wie hier im Forum versucht wird einem Neuling in Sachen Programmierung weiter zu helfen.
Die Sternchen habe ich in der Klasse RhUhr derweilen auch geschafft zu entfernen. Mit Freude sah ich dass es in deinem Beispiel exakt gleich war.
Nun habe ich wieder einigen Stoff um deinen umgebauten Code im Einzelnen zu verstehen und nachzuvollziehen. Wie ich sah, ist das Prozentzeichen in der Uhr nach unten gerutscht. Das werde ich als erstes angehen.
Die Zeile:
if __name__ == '__main__':
kannte ich so noch nicht. Kannst du mir bitte noch erklären was dabei genau geschieht?
Ich kann nur noch mal sagen SUPER!!! Und vielen Dank für alles!!! :D :D :D

Grüße
Jörg
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@joerg123: das if-name-main braucht man, damit man das Modul sowohl importieren kann, als auch als Skript benutzen.
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Hallo Sirius3,
ich sehe schon es gibt noch viel zu lernen und zu verstehen.
Das Prozentzeichen konnte ich an die richtige Stelle rücken. Das habe ich so gelöst:

Code: Alles auswählen

        # Beschriftug fuer Digialwert erstellen
        x, y = self._angle_to_pos(0, 0.5)
        self._id_font_humidity = canvas.create_text(x, y, text="Hygro",
                                                    font=font_bold)
        x, y = self._angle_to_pos(0, 0.7)
        y = y - self._zifferblatt_radius  # hier die Änderung
        canvas.create_text(x, y, text="%", font=font_normal, fill="#404040")
Hallo BlackJack,
ich habe mir die after() – Methode genauer angesehen und ich habe das so gelöst:

Code: Alles auswählen

#!/usr/bin/python3

import tkinter as tk
from module.analoguhr import RhUhr
#from module.analoguhr import TempUhr
folgeRh = 0


def counter_uhr(testuhr1):

    def count():
        global folgeRh
        testuhr1.setFolgeRh(folgeRh)
        testuhr1.after(1000, count)
        folgeRh = folgeRh + 1
    count()


def main():
    # root-Fenster
    root = tk.Tk()
    root.geometry("800x480")
    root.title("Humimeter")
    root.configure(background="black")
    img = tk.PhotoImage(file='pics/humilogo.gif')
    root.tk.call('wm', 'iconphoto', root._w, img)

    # Rahmen erzeugen
    toprahmen = tk.Frame(root, bg="black", bd=8, relief=tk.RIDGE)
    toprahmen.grid()
    rahmen_rh1 = tk.Frame(toprahmen, bg="black", bd=2, relief=tk.RIDGE)
    rahmen_rh1.grid(row=0, column=0, pady=0, sticky=tk.W + tk.N)
    rahmen_rh2 = tk.Frame(toprahmen, bg="black", bd=2, relief=tk.RIDGE)
    rahmen_rh2.grid(row=0, column=1, pady=0, sticky=tk.W + tk.N)

    # Testwerte fuer die Analog-RH-Uhr
    #folgeRh = 63.5
    rhSoll = 65
    zifferblattgroesse = 180

    # Aufruf der RH-Analoguhr
    testuhr1 = RhUhr(tkrahmen=rahmen_rh1, zifferblattgroesse=zifferblattgroesse)
    testuhr1.grid()
    #testuhr1.setFolgeRh(folgeRh)
    testuhr1.setSollRh(rhSoll)

    counter_uhr(testuhr1)

    root.mainloop()

if __name__ == '__main__':
    main()
Funktionieren tut es so ganz gut. Wäre das so OK? Oder habe ich etwas übersehen das sich vielleicht erst zu einem späteren Zeitpunkt bemerkbar macht?
BlackJack

@joerg123: Vergiss am besten gleich wieder dass es ``global`` gibt. Und die Zeit mit `after()` tatsächlich zu ”messen” ist keine gute Idee. Dafür solltest Du die Uhr des Rechners verwenden und deren Wert regelmässig auslesen und anzeigen.
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

@BlackJack: Das 'global' nicht gut ist habe ich schon an vielen Stellen hier und im Netz gelesen. Es fehlt mir aber noch schwer alternativen dazu zu finden. Wenn man im Internet sucht bekommt man meist ein 'global' als Lösung vorgestellt. Hättest du in meinem Fall ein Beispiel dazu wie man es stattdessen richtig macht? Ich muss ja einer Variablen einen Startwert zuweisen der dann später hochgezählt wird. Aber diese Variable muss ja außerhalb der Schleife stehen damit sie nicht immer wieder durch den Startwert nach dem hochzählen überschrieben wird. :K

Bei der Uhr handelt es sich nicht wirklich um eine Uhr die die Zeit misst :wink: , sondern sie gibt die Werte eines Feuchtsensors wieder die in regelmäßigen Abständen eingelesen werden. Bei der Schleife ging es mir hauptsächlich darum zu testen ob die Werte mittels 'after()' nun an die Uhr übertragen werden.

Nochmals herzlichen Dank für deine Hilfe :D
Grüße
Jörg
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Um eine Variable im Augen behalten zu können, bietet tkinter einen Satz von Klassen an:

http://effbot.org/tkinterbook/variable.htm

Die callback-Funktionalität kannst Du nutzen, um z. B. Dein Canvas neu zu zeichnen.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@joerg123: Klassischerweise nimmt man dafür Klassen, die können Zustände auch nach beenden einer Methode noch speichern. Man kann dafür aber auch einen Generator verwenden:

Code: Alles auswählen

def update_rh(uhr):
    rh = 63.5
    while True:
        rh += random.random() - 0.5
        uhr.setFolgeRh(rh)
        yield 100

def after_loop(element, generator):
    def loop():
        element.after(next(generator), loop)
    loop()

[...]
    after_loop(testuhr1, update_rh(testuhr1))
[...]
@bwbg: es geht hier, glaube ich, nicht um ein Textfeld, o.ä., sondern um einen externen Sensor, der regelmäßig ausgelesen werden soll.
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

@bwbg: Vielen Dank erst mal für die Info :D . Aber wie Sirius3 schon richtig erkannt hatt, geht es nicht um ein Textfeld sonder um einen externen Sensor. Entschuldigt bitte falls ich hier zu wenige oder missverständliche Angaben gemacht habe.

@Sirius3: Danke, :D nun habe ich wieder viele Informationen die für mich noch ziemlich neu sind und die ich erst mal alle wieder durcharbeiten muss. Ich werde es zuerst einmal mit einer Klasse ausprobieren.

Euch allen noch ein schönes und erholsames Restwochenende :D :D :D
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Hallo Sirius3,
ich habe es jetzt mit einem Generator programmiert. So wie du mir es in deinem Beispiel beschrieben hast. Das yield 100 gibt glaube ich die Millisekunden an die bis zum nächsten Durchlauf gewartet wird.
Darf ich eigentlich beim after_loop Aufruf noch weitere Parameter mitgegeben?
Ich habe das mal so gemacht.

Code: Alles auswählen

after_loop(testuhr1, update_uhr(rhuhr, tempuhr, rh_diagramm, temp_diagramm, datum_diagramm, rw_rhsoll, soll_Rh, rahmen_soll, vanico_aus, vanico_an, luefter))
Im Funktionskopf sieht das so aus:

Code: Alles auswählen

def update_uhr(rhuhr, tempuhr, rh_diagramm, temp_diagramm, datum_diagramm, rw_rhsoll, soll_Rh, rahmen_soll, vanico_aus, vanico_an, luefter)
Wenn ich yield auf 1000 Setze funktioniert alles, wenn ich auf 2000 oder 3000 gehe werden manche Werte in der Funktion nicht mehr richtig angezeigt. Das heißt wenn ich zum Beispiel in der Funktion innerhalb der while-Schleife einem Label eine Bild zuweise, wird es zeitversetzt oder gar nicht angezeigt. Wie gesagt, bei yield 1000 funktioniert das ganze einwandfrei. :K

Kannst du mir da vielleicht noch mal ein bisschen weiterhelfen? Das wäre wirklich sehr nett :D

Grüße
Jörg
joerg123
User
Beiträge: 13
Registriert: Samstag 27. Juni 2015, 10:47

Hallo Sirius3,

Kommando zurück!!! ich habe den Fehler gefunden. Ich habe übersehen dass eine weitere Funktion immer wieder das Bild wechselt. Beide Funktionen wurden miteinander nur noch nicht abgestimmt. Es fiel am Anfang nur nie auf, da sich der Wechsel mit dem Schleifendurchlauf von 1Sekunde scheinbar synchron verhielt. Erst als die Wartezeit sich verlängerte wurde der Fehler sichtbar.
Sorry!!!
:oops: :oops: :oops:
Antworten