Uhrzeiger Analoguhr

Fragen zu Tkinter.
Antworten
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Hallo Forum,
gibt es schon eine fertige Funktion oder Bibliothek für eine Art Uhrzeiger?
Ich brauchte so etwas für eine Positionsanzeige an einem Kreis-Canvas, ähnlich dem Strich an einem Drehregler oder Poti.
Vielen Dank

P.S. kann den Thread leider nicht mehr entfernen, hab gerade eine schöne Lösung gefunden, danke soweit.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

Ich hab hier meine Lösung für den rotierenden Zeiger mal angehangen,
das Programm funktioniert so erst mal ganz gut.
gibt es vielleicht Funktionen mit denen ich den Code noch kürzen kann?

Außerdem bräuchte ich in dem Zusammenhang noch eine Funktion, die beim Arduino map() heißt.
damit können Wertebereiche in ein verändertes Verhältnis gesetzt werden. So eine Art erweiterter Dreisatz.
Gibt es so etwas schon in einer Bibliothek?

Code: Alles auswählen

from tkinter import Tk, Frame, Canvas
from math import sin, cos, radians

class mainWindow(Frame):
    def __init__(self, master=None):
        super(mainWindow, self).__init__(master)
        self.pack()
        self.cv = Canvas(self, width=200, height=200)
        self.cv.pack()
        self.uhr()
        self.zeigerBewegung()

    def uhr(self):
        self.x0 = 25
        self.y0 = 25
        self.x1 = 175
        self.y1 = 175
        self.schrittweite = 1
        self.zeigerPosition = 0 # Bereich 0 bis 360 Grad

        self.zeigerLaenge = (self.x1 - self.x0)/2
        self.center_x = ((self.x1 - self.x0)/2) + self.x0
        self.center_y = ((self.y1 - self.y0)/2) + self.y0

        self.cv.create_oval(self.x0, self.y0, self.x1, self.y1)
        self.zeiger = self.cv.create_line(self.center_x, self.center_y, self.center_x, self.center_y) # beim start nur als Punkt

    def zeigerBewegung(self):
        x = self.zeigerLaenge * sin(radians(self.zeigerPosition)) + self.center_x
        y = self.zeigerLaenge * cos(radians(180 + self.zeigerPosition)) + self.center_y

        self.cv.coords(self.zeiger, self.center_x, self.center_y, x, y)
        self.zeigerPosition += self.schrittweite
        if self.zeigerPosition > 360:
            self.zeigerPosition = self.zeigerPosition - 360
        self.after(50, self.zeigerBewegung)

if __name__ == "__main__":

    root = Tk()
    fenster = mainWindow(master=root)
    fenster.mainloop()
BlackJack

Eine solche `map()`-Funktion gibt's nicht. Aber in der Arduino-Dokumentation steht ja die Implementierung der Funktion. In Python solltest Du sie nur nicht `map()` nennen, denn eine `map()`-Funktion die etwas ganz anderes macht, gibt es in Python ja bereits bei den eingebauten Funktionen. :-)
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

ah ok, ich danke dir für info
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@XCDRiVER: Frames sollten sich nicht selbst positionieren, das pack gehört also aus __init__ heraus in main. In __init__ sollten schon alle Attribute angelegt werden. Die Attribute x0, y0, x1 und y1 werden sowieso nicht gebraucht. Die Zahlen würde ich über __init__ konfigurierbar machen und die Methode uhr weglassen.
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

danke für die Info, ich korrigiere das und lade es noch mal rauf
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

@Sirius3: ich denke so hattest du das gemeint?

Code: Alles auswählen

from tkinter import Tk, Frame, Canvas
from math import sin, cos, radians

class mainWindow(Frame):
    def __init__(self, koordinate_1, koordinate_2, master=None):
        super(mainWindow, self).__init__(master)
        # self.pack()
        self.x0 = koordinate_1
        self.y0 = koordinate_1
        self.x1 = koordinate_2
        self.y1 = koordinate_2
        self.zeigerPosition = 0 # Bereich 0 bis 360 Grad
        self.zeigerLaenge = (self.x1 - self.x0)/2
        self.center_x = ((self.x1 - self.x0)/2) + self.x0
        self.center_y = ((self.y1 - self.y0)/2) + self.y0
        self.cv = Canvas(self, width=200, height=200)
        self.cv.create_oval(self.x0, self.y0, self.x1, self.y1)
        # self.cv.pack()
        self.zeiger = self.cv.create_line(self.center_x, self.center_y, self.center_x, self.center_y) # beim start nur als Punkt
        self.zeigerBewegung()

    def zeigerBewegung(self):
        x = self.zeigerLaenge * sin(radians(self.zeigerPosition)) + self.center_x
        y = self.zeigerLaenge * cos(radians(180 + self.zeigerPosition)) + self.center_y

        self.cv.coords(self.zeiger, self.center_x, self.center_y, x, y)
        self.zeigerPosition += 1
        if self.zeigerPosition > 360:
            self.zeigerPosition = self.zeigerPosition - 360
        self.after(2, self.zeigerBewegung)

if __name__ == "__main__":

    root = Tk()
    fenster = mainWindow(10, 190, master=root)
    fenster.pack()
    fenster.cv.pack()
    fenster.mainloop()
BlackJack

Das ``fenster.cv.pack()`` gehört da nicht hin. Du solltest den abgeleiteten Frame selbst sich selbst nicht anordnen lassen, weil das nicht seine Aufgabe ist. Der ist aber sehr wohl für seinen Inhalt zuständig.

Ich würde auch das Attribut nicht abkürzen. `cv` ist eine übliche Abkürzung für einen Lebenslauf („Curriculum Vitae“).
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

@BlackJack: danke, ich ändere das
den StyleGuide muss ich mir sicher mal anschauen
Benutzeravatar
XCDRiVER
User
Beiträge: 31
Registriert: Sonntag 12. Februar 2017, 19:59

die Wertebegrenzung (Winkel) habe ich wieder raus genommen, die war in diesem Zusammenhang unnötig.
ich würde es für dieses Testfile dabei belassen,
vielen Dank euch beiden.

Code: Alles auswählen

from tkinter import Tk, Frame, Canvas
from math import sin, cos, radians

class mainWindow(Frame):
    def __init__(self, koordinate_1, koordinate_2, master=None):
        super(mainWindow, self).__init__(master)
        self.x0 = koordinate_1
        self.y0 = koordinate_1
        self.x1 = koordinate_2
        self.y1 = koordinate_2
        self.zeigerPosition = 0
        self.zeigerLaenge = (self.x1 - self.x0)/2
        self.center_x = ((self.x1 - self.x0)/2) + self.x0
        self.center_y = ((self.y1 - self.y0)/2) + self.y0
        self.leinwand = Canvas(self, width=200, height=200)
        self.leinwand.pack()
        self.leinwand.create_oval(self.x0, self.y0, self.x1, self.y1)
        self.zeiger = self.leinwand.create_line(self.center_x, self.center_y, self.center_x, self.center_y) # beim start nur als Punkt
        self.zeigerBewegung()

    def zeigerBewegung(self):
        x = self.zeigerLaenge * sin(radians(self.zeigerPosition)) + self.center_x
        y = self.zeigerLaenge * cos(radians(180 + self.zeigerPosition)) + self.center_y

        self.leinwand.coords(self.zeiger, self.center_x, self.center_y, x, y)
        self.zeigerPosition += 1
        self.after(5, self.zeigerBewegung)

if __name__ == "__main__":

    root = Tk()
    fenster = mainWindow(10, 190, master=root)
    fenster.pack()
    fenster.mainloop()
die Idee hinter dem Zeiger entspringt übrigens einem Youtubevideo von Ishan Mitra:
Using Python to make a Rotating Line (and implement it in Stopwatch)
Antworten