-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscrolling_text_widget.py
More file actions
139 lines (112 loc) · 4.05 KB
/
scrolling_text_widget.py
File metadata and controls
139 lines (112 loc) · 4.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
"""
Improved ScrollingText Widget
A clean, maintainable implementation of scrolling text for WeatherPeg.
Replaces the problematic ScrollingSummary class with a much better solution.
"""
import tkinter as tk
from typing import Optional
class ScrollingTextWidget:
"""
A clean, efficient scrolling text widget that handles long text gracefully.
Features:
- Automatic scrolling for text longer than display width
- Smooth, configurable scrolling speed
- Memory efficient (no callback chains)
- Easy to use and maintain
- Thread-safe GUI updates
"""
def __init__(self, parent, text: str = "", width: int = 80, speed: int = 150):
"""
Initialize the scrolling text widget.
Args:
parent: Parent tkinter widget
text: Initial text to display
width: Maximum width in characters
speed: Scroll speed in milliseconds per character
"""
self.parent = parent
self.width = width
self.speed = speed
self.original_text = text
# Create the label widget
self.label = tk.Label(
parent,
text="",
fg="lime",
bg="black",
font=("VCR OSD Mono", 12),
justify="left",
padx=10,
pady=10
)
self.label.pack()
# Scrolling state
self.position = 0
self.is_scrolling = False
self.after_id: Optional[str] = None
self.scroll_id = 0
# Update with initial text
self.update_text(text)
def update_text(self, new_text: str) -> None:
"""
Update the text content and start scrolling if needed.
Args:
new_text: New text to display
"""
# Stop any existing scrolling
self.scroll_id += 1
self.is_scrolling = False
# Cancel any pending after callbacks
if self.after_id:
self.parent.after_cancel(self.after_id)
self.after_id = None
self.original_text = new_text
self.position = 0
# If text fits in width, just display it
if len(new_text) <= self.width:
self.label.config(text=new_text)
return
# Start scrolling for longer text
self.is_scrolling = True
current_scroll_id = self.scroll_id
self._scroll_text(current_scroll_id)
def _scroll_text(self, scroll_id: int) -> None:
"""
Internal method that handles the scrolling animation.
Uses tkinter's after() method for smooth GUI updates.
"""
# Check if this scroll session is still valid
if scroll_id != self.scroll_id or not self.is_scrolling or not self.original_text:
return
# Create extended text for smooth looping
extended_text = self.original_text + " *** "
# Calculate visible portion
start = self.position % len(extended_text)
display_text = (extended_text[start:] + extended_text)[:self.width]
# Update the label
self.label.config(text=display_text)
# Move position for next update
self.position += 1
# Schedule next update
self.after_id = self.parent.after(self.speed, lambda: self._scroll_text(scroll_id))
def flash_black(self) -> None:
"""
Flash the text black for refresh indication.
"""
self.label.config(fg="black")
self.parent.after(750, lambda: self.label.config(fg="lime"))
def stop_scrolling(self) -> None:
"""
Stop the scrolling animation.
"""
self.is_scrolling = False
if self.after_id:
self.parent.after_cancel(self.after_id)
self.after_id = None
def destroy(self) -> None:
"""
Clean up resources when the widget is destroyed.
"""
self.stop_scrolling()
# Backward compatibility alias
ScrollingSummary = ScrollingTextWidget