Laufschrift mit tkinter

Fragen zu Tkinter.
Antworten
pythonstefan
User
Beiträge: 13
Registriert: Freitag 22. Januar 2016, 09:34

Donnerstag 24. März 2016, 17:43

Hallo,
kann mir jemand einen Link zu einer EINFACHEN Lösung für eine Laufschrift mit Tkinter empfehlen? Google gibt natürlich viel mit 'scrollable' oder so, aber ich suche nach einer EMPFEHLUNG für eine EINFACHE Implementierung.
Stefan
__deets__
User
Beiträge: 2850
Registriert: Mittwoch 14. Oktober 2015, 14:29

Freitag 25. März 2016, 23:35

Was ist denn nicht einfach genug an den Dingen, die du findest? Und so generell wuerde ich sagen - Tkinter & animation ist jetzt eher mau. Soll das eine Statusleiste werden, oder ein grafischer Effekt? Dann wuerde ich eher pygame empfehlen.
pythonstefan
User
Beiträge: 13
Registriert: Freitag 22. Januar 2016, 09:34

Samstag 26. März 2016, 18:25

Ich möchte einen langen Text in einem Fenster von rechts nach links laufen lassen. Den Hintergrund (evtl. ein Foto) und weitere Elemente des Fensters möchte ich unabhängig davon gestalten können. Praktisch wie ein Label, dem ih Text zuweise, der dann aber läuft. Eine Art Info-Tafel.
Ich hätte gedacht, dass das Standard ist und viele von Euch das schon (in Ihrer Anfangszeit ..) gemacht haben.
Viele Lesezugriffe auf meinen Beitrag und einer, der es anscheinend auch noch nicht gelöst hat, legen nahe, dass es wohl NICHT so einfach ist. Wenn jemand das schon einmal gemacht hat oder eine gute Lösung zeigen kann, dann würde ich mich freuen.
__deets__
User
Beiträge: 2850
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 27. März 2016, 00:23

Ich wiederhole mich: pygame. Das, was du da beschreibst, klingt nach einem klassischen grafischen Scroller, und fuer so etwas solltest du Abstand von tkinter nehmen.

Das hier koennte ein Start sein: https://github.com/gunny26/pygame/blob/ ... ollText.py
Benutzeravatar
wuf
User
Beiträge: 1462
Registriert: Sonntag 8. Juni 2003, 09:50

Sonntag 27. März 2016, 08:05

Hi __deets__
__deets__ hat geschrieben:Das, was du da beschreibst, klingt nach einem klassischen grafischen Scroller, und fuer so etwas solltest du Abstand von tkinter nehmen.
Einspruch!

Hier der Beweis, dass es mit Tkinter lösbar ist!

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "TkTemplate_Idiom_01"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200
SCROLL_TEXT = "My scrollable text!"

class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
        
        self.canvas = tk.Canvas(self, bg='mistyrose2', highlightthickness=0)
        self.canvas.pack(expand=True)

        self.canvas.create_rectangle(50, 50, 150, 150, fill='mistyrose4')
        
        xpos = APP_WIDTH
        ypos = 100
        self.canvas.create_text(xpos, ypos, anchor='w', text=SCROLL_TEXT,
            font=('Helvetica 30 bold'), tags='text')
            
        text_begin = self.canvas.bbox('text')[0]
        text_end = self.canvas.bbox('text')[2]
        self.text_length = text_end - text_begin
        
        self.scroll_text()
        
    def scroll_text(self):
        self.canvas.move('text', -2, 0)
        text_end = self.canvas.bbox('text')[2]
        if text_end < 0:
            self.canvas.move('text', APP_WIDTH + self.text_length, 0)
        
        self.canvas.after(50, self.scroll_text)
        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True, padx=0, pady=0)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
__deets__
User
Beiträge: 2850
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 27. März 2016, 14:31

Niemand hat behauptet das es nicht geht. Aber mit pygame geht's IMHO besser, denn dort habe ich zB double-buffering. Zumindest fuer meinen Scroller laeuft's smoother als mit dem von dir (ich hab' deinen Code so angepasst, dass er auch auf 60 Frames/Sekunde kommen sollte)

EDIT

Ich lass das Video mal da - aber es wird dem visuellen Eindruck leider nicht gerecht. Kannst ja einfach mal selbst ausprobieren.

https://www.dropbox.com/s/ecta5peydpcet ... n.mov?dl=0

Von der Moeglichkeit, mit Transparenz und anderen Effekten zu spielen ganz zu schweigen.

Code: Alles auswählen

import sys
import pygame

SCROLL_TEXT = "My scrollable text! " * 20

BLACK = (0, 0, 0)
YELLOW = (255, 255, 0)

class Scroller(object):

    def __init__(self, screen, text, size=40, speed=200, y=300):
        self._pos = float(screen.get_size()[0])
        self._speed = speed
        self._y = y
        font = pygame.font.SysFont(pygame.font.get_default_font(), size)
        self._scrollsurface = font.render(text, True, YELLOW)
        self._screen = screen
        print self._scrollsurface


    def __call__(self, elapsed):
        self._pos -= 1 # (elapsed / 1000.0) * self._speed
        if self._pos < -(self._scrollsurface.get_size()[0]):
            self._pos = float(self._screen.get_size()[0])

        self._screen.blit(self._scrollsurface, (int(self._pos), self._y))


def main():
    pygame.init()
    pygame.font.init()
    screen = pygame.display.set_mode((800, 600))

    clock = pygame.time.Clock()

    scroller = Scroller(screen, SCROLL_TEXT, speed=60)

    while True:
        elapsed = clock.tick(60)
        screen.fill(BLACK)
        scroller(elapsed)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit(); sys.exit();


        pygame.display.update()


if __name__ == "__main__":
    main()
Benutzeravatar
wuf
User
Beiträge: 1462
Registriert: Sonntag 8. Juni 2003, 09:50

Sonntag 27. März 2016, 17:30

Hi __deets__

Danke für deine Stellungsnahme.

Was die Bewegung der Schrift anbelangt sehe ich bei mir keinen Unterschied zwischen Tkinter und pygame. Gut bei meinem Skript bewege ich die Schrift mit einem Inkrement von -2 Pixeln und so wie ich dein Skript interpretiere bewegst du deine Schrift mit -1 Pixel. Dies könnte auf das glatte bewegen der Schrift einen Einfluss haben. Betreffs Transparenz und für zusätzliche grafischen Effekte müsste natürlich PIL einbezogen werden.

Hier noch mein modifiziertes Skript mit einem Inkrement von -1 Pixel und 20 mal den vorgegebenen Text in Reihe:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except ImportError:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "Moving text"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 600
APP_HEIGHT = 200
SCROLL_TEXT = "My scrollable text! " * 20

class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)
        
        self.canvas = tk.Canvas(self, bg='mistyrose2', highlightthickness=0,
            width=APP_WIDTH, height=APP_HEIGHT)
        self.canvas.pack(expand=True)

        self.canvas.create_rectangle(50, 50, 150, 150, fill='mistyrose4')
        
        xpos = APP_WIDTH
        ypos = 100
        self.canvas.create_text(xpos, ypos, anchor='w', text=SCROLL_TEXT,
            font=('Helvetica 30 bold'), tags='text')
            
        text_begin = self.canvas.bbox('text')[0]
        text_end = self.canvas.bbox('text')[2]
        self.text_length = text_end - text_begin
        
        self.scroll_text()
        
    def scroll_text(self):
        self.canvas.move('text', -1, 0)
        text_end = self.canvas.bbox('text')[2]
        if text_end < 0:
            self.canvas.move('text', APP_WIDTH + self.text_length, 0)
        
        self.canvas.after(10, self.scroll_text)
        
def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    #app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    
    app = Application(app_win).pack(fill='both', expand=True, padx=0, pady=0)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
pythonstefan
User
Beiträge: 13
Registriert: Freitag 22. Januar 2016, 09:34

Sonntag 27. März 2016, 17:49

Hallo wuf,
genial! DANKE!!! Ich habe das eben bei mir ausprobiert und es läuft. Sieht toll aus. Jetzt muss ich das nur noch verstehen, um ggf. individuelle Anpassungen vorzunehmen. Ich bin immer wieder beeindruckt, was für tolle Sachen mit relativ wenig Aufwand machbar sind - wenn man es kann ...
Viele Grüße
Stefan
__deets__
User
Beiträge: 2850
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 27. März 2016, 18:04

@wuf: nein, das ruckelt gelegentlich bei mir. Als ob so etwas wie garbage collection zuschlaegt. Ist jetzt kein Oberdrama, bekommt aber meiner alten Demoscene-Seele weh ;)

Aber wenn's dem TE genuegt, soll's mir recht sein.
pythonstefan
User
Beiträge: 13
Registriert: Freitag 22. Januar 2016, 09:34

Montag 28. März 2016, 23:59

Hallo wuf,
ich habe damit etwas herumgespielt und auch etliche Dinge in der Hilfe nachgelesen. Funktioniert klasse. Noch einmal vielen Dank.
Jedes Detail habe ich noch nicht verstanden.
Könntest Du bitte erläutern, was hier gemacht wird:

Code: Alles auswählen

app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    #app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
   
    app = Application(app_win).pack(fill='both', expand=True, padx=0, pady=0)
  
Insbesondere diese Sache: +{}+{} kenne ich noch nicht.
(Mit place, grid und pack habe ich mich natürlich schon beschäftigt.)
Viele Grüße
Stefan
Benutzeravatar
wuf
User
Beiträge: 1462
Registriert: Sonntag 8. Juni 2003, 09:50

Dienstag 29. März 2016, 08:06

Hi Stefan

Die Standartanweisung für die Platzierung und Dimesionen für das Hauptfensters ist folgende:
app_win.geometry("400x300+200+100")
Die Werte hierfür sind von mir frei gewählt.

Um die Werte für Position & Dimension als Integerwerte in die Stringbehaftete Anweisung zu kopieren benutze ich:
app_win.geometry("{}x{}+{}+{}".format(400, 300, 200, 100))

Das folgenden Skript zeigt noch detailierter die verschiedenen Varianten:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except:
    # Tkinter for Python 3.xx
    import tkinter as tk

APP_TITLE = "Geometrie & Platzierung"
APP_XPOS = 100
APP_YPOS = 100
APP_WIDTH = 300
APP_HEIGHT = 200


class Application(tk.Frame):

    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, master)


def main():
    app_win = tk.Tk()
    app_win.title(APP_TITLE)
    
    #~~ Platziert die obere linke Ecke des Hauptfensters
    #   BEMERKUNG: Steht diese Zeile alleine wird auf der angegebenen Position
    #              nur ein kleines fast unsichtbares Hauptfenster ohne grössere
    #              Dimensioneen platziert! Die Dimensionen des Hauptfensters
    #              ändern sich erst, wenn ein weiteres Tk-Widget im Fenster
    #              erstell wird!
    app_win.geometry("+{}+{}".format(APP_XPOS, APP_YPOS))
    #~~ Kann alternativ auch so geschrieben werden
    #app_win.geometry("+100+100")
    
    #~~ Bestimmt die horizontale und vertikale Dimension des Hauptfensters
    #   BEMERKUNG: Steht diese Zeile alleine wird das Hauptfenster mit den
    #   angegebenen Dimensionen durch den Fenstermanager des entsprechenden
    #   OS-System an einer von ihm bestimmten Position platziert!
    app_win.geometry("{}x{}".format(APP_WIDTH, APP_HEIGHT))
    #~~ Kann alternativ auch so geschrieben werden
    #app_win.geometry("300x200")
    
    #~~ Platzierung und Dimension können auch in einer Zeile vereint werden.
    #app_win.geometry("{}x{}+{}+{}".format(APP_WIDTH, APP_HEIGHT, APP_XPOS,
        #APP_YPOS))
    #~~ Alternativ kann die obige Anweisung auch so geschrieben werden
    #app_win.geometry("300x200+100+100")  
        
    app = Application(app_win).pack(fill='both', expand=True, padx=6, pady=6)
    
    app_win.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
pythonstefan
User
Beiträge: 13
Registriert: Freitag 22. Januar 2016, 09:34

Dienstag 29. März 2016, 22:27

Hallo wuf,
vielen Dank. Jetzt ist es klarer. Ich hatte noch nichts mit .geometry und .format gemacht.
Python und Tkinter sind so leistungsfähig, aber man muss sich alles irgendwie zusammensuchen und lernt Schritt für Schritt dazu - so wie ich jetzt. Vielen Dank.
Stefan

P.S.:
Wenn es jemand geht wie mir: Hier etwas bezüglich .format: https://pyformat.info
Und hier etwas Interessantes zu .geometry: http://stackoverflow.com/questions/1491 ... ndow-opens
Antworten