Move animated text classes into textbox

master
En Yi 2018-07-21 22:21:10 +08:00
parent 7ddc13fdd1
commit 23be7cf449
3 changed files with 200 additions and 192 deletions

View File

@ -1,18 +1,15 @@
"""
This module contains all kinds of animated buttons
"""This module contains all the buttons used. A base class AnimBox handles the drawing and animation, inherited
by all the buttons.
"""
import math
import random
from PyQt5.QtCore import (QAbstractAnimation, Qt, QRectF, QLineF,
QPropertyAnimation, pyqtProperty, pyqtSignal)
from PyQt5.QtGui import QPen, QColor
from PyQt5.QtWidgets import (QGraphicsObject)
from general import extras
RANDOMCHAR = "~!@#$%^&*()_+`-=[]\{}|;:'<>,./?\""
from .textbox import AnimatedText
class AnimBox(QGraphicsObject):
@ -27,7 +24,6 @@ class AnimBox(QGraphicsObject):
self.y = y
self.width = width
self.height = height
#self.text = text
self.circumference = 2*(width+height)
# Set up pens for drawing
@ -54,7 +50,6 @@ class AnimBox(QGraphicsObject):
self.length = 0
# Set up the length to be animated
self.anim = QPropertyAnimation(self, b'length')
self.anim.setDuration(400) # Animation speed
self.anim.setStartValue(0)
for t in range(1, 10):
self.anim.setKeyValueAt(t / 10, self.logistic_func(t / 10))
@ -203,66 +198,4 @@ class MenuButton(AnimBox):
self.buttonClicked.emit(self.text)
class AnimatedText(QGraphicsObject):
def __init__(self, text, parent=None):
super().__init__(parent=parent)
self.parent = parent
self.actual_text = text
self.shown_text = ''
self.delay = 3
# Set up pens for drawing
self.default_pen = QPen()
self.default_pen.setColor(Qt.white)
self.randomchar_list = [c for c in RANDOMCHAR]
self.shown_length = 0
# Set up the length to be animated
self.anim = QPropertyAnimation(self, b'shown_length')
self.anim.setDuration(len(self.actual_text) * 50) # Animation speed
self.anim.setStartValue(0)
for t in range(1, 10):
self.anim.setKeyValueAt(t / 10, (len(self.actual_text) + self.delay) * t/10)
self.anim.setEndValue(len(self.actual_text) + self.delay)
self.visibleChanged.connect(self.show_text)
def show_text(self):
if self.isVisible():
self.toggle_anim(True)
else:
self.shown_length = 0
# Toggle the animation to be play forward or backward
def toggle_anim(self, toggling):
if toggling:
self.anim.setDirection(QAbstractAnimation.Forward)
else:
self.anim.setDirection(QAbstractAnimation.Backward)
self.anim.start()
def boundingRect(self):
return self.parent.boundingRect()
def paint(self, painter, style, widget=None):
painter.setPen(self.default_pen)
painter.drawText(self.parent.boundingRect(), Qt.AlignCenter, self.shown_text)
# Defining the length to be drawn as a pyqtProperty
@pyqtProperty(int)
def shown_length(self):
return self._shown_length
# Determine the length of the four lines to be drawn
@shown_length.setter
def shown_length(self, value):
self._shown_length = value
text_length = extras.bound_value(0, value-self.delay, len(self.actual_text))
text = self.actual_text[:text_length]
random.shuffle(self.randomchar_list)
text += ''.join(self.randomchar_list[:min(value, 3)])
self.shown_text = text[:min(self.shown_length, len(self.actual_text))]
self.update()

View File

@ -14,6 +14,7 @@ else:
hs_file = "./sudoku/general/highscore.txt"
from general import highscore as hs
from .textbox import AnimatedLabel
if not os.path.exists(hs_file):
print('Missing High Score file. Generating one. ')
@ -228,128 +229,6 @@ class NameInput(QWidget):
self.nameReceived.emit(name)
class AnimatedLabel(QLabel):
"""
QLabel that a message, which is displayed through animation.
"""
def __init__(self, text, speed=75, delay=20, parent=None):
"""
Does some text processing, and set up the animation to display the text
Parameters
----------
text: str
Text to be displayed
speed : int
The period at which a new character is printed
The total time is calculated as length of text * speed
0 means instant display, like a regular QLabel.
delay : int
The number of garbage to be printed before printing the actual text
parent: QWidget
Pass into QLabel init method
"""
super().__init__(text, parent)
self.speed = speed
self.setWordWrap(True)
self.setContentsMargins(0, 0, 0, 0)
# Text processing
# Make sure the garbage does not exceed the length of actual text
self.actual_text = text
self.shown_text = ''
if delay >= 0:
self.delay = min(delay, len(self.actual_text))
else:
self.delay = len(self.actual_text)
# Find out where the new paragraphs are so that it is retained
self.splitpoints = []
current_point = 0
line_splits = self.actual_text.split('\n')
for line in line_splits:
current_point += len(line)
self.splitpoints.append(current_point)
current_point += 1
# Set up the shown text length to be animated
self.shown_length = 0
self.anim = QPropertyAnimation(self, b'shown_length')
self.anim.setDuration(len(self.actual_text) * speed)
self.anim.setStartValue(0)
self.anim.setEndValue(len(self.actual_text) + self.delay)
#self.setStyleSheet("""
# color: rgb(0, 255, 0);
# """)
self.toggle_anim(True)
@pyqtProperty(int)
def shown_length(self):
"""
int : The value for the animation
When the value is set, the text to be printed is generated accordingly.
It determines whether actual text is to be printed, and retains the
paragraphs when printing garbage.
"""
return self._shown_length
@shown_length.setter
def shown_length(self, value):
self._shown_length = value
if value < self.delay:
# All printed text should be garbage
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in range(value)]]
# Retain the paragraphs
for num in self.splitpoints[:-1]:
if num < value:
garbage[num] = '\n'
self.setText(''.join(garbage))
else:
# Printed text contain some actual text
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in
range(min(len(self.actual_text) + self.delay - value, self.delay))]]
# Retain the paragraphs, but offset by the number of actual text
non_garbage = value - self.delay
for num in self.splitpoints[:-1]:
if num - non_garbage > 0 and num < value:
garbage[num - non_garbage] = '\n'
self.setText(self.actual_text[:value - self.delay] + ''.join(garbage))
def toggle_anim(self, toggling):
"""
Toggle the animation to be play forward or backward
Parameters
----------
toggling: bool
True for forward, False for backward
"""
if toggling:
self.anim.setDirection(QAbstractAnimation.Forward)
else:
self.anim.setDirection(QAbstractAnimation.Backward)
self.anim.start()
def replace_text(self, new_text):
self.shown_length = 0
self.actual_text = new_text
self.anim.setDuration(len(self.actual_text) * self.speed)
self.anim.setEndValue(len(self.actual_text) + self.delay)
self.toggle_anim(True)
if __name__ == '__main__':
app = 0
app = QApplication(sys.argv)

View File

@ -0,0 +1,196 @@
import random
from PyQt5.QtCore import (QAbstractAnimation, Qt, QPropertyAnimation, pyqtProperty)
from PyQt5.QtGui import QPen
from PyQt5.QtWidgets import QGraphicsObject, QLabel
class AnimatedText(QGraphicsObject):
def __init__(self, text, parent=None):
super().__init__(parent=parent)
self.parent = parent
self.actual_text = text
self.shown_text = ''
self.delay = 3
# Set up pens for drawing
self.default_pen = QPen()
self.default_pen.setColor(Qt.white)
self.shown_length = 0
# Set up the length to be animated
self.anim = QPropertyAnimation(self, b'shown_length')
self.anim.setDuration(len(self.actual_text) * 50) # Animation speed
self.anim.setStartValue(0)
for t in range(1, 10):
self.anim.setKeyValueAt(t / 10, (len(self.actual_text) + self.delay) * t/10)
self.anim.setEndValue(len(self.actual_text) + self.delay)
self.visibleChanged.connect(self.show_text)
def show_text(self):
if self.isVisible():
self.toggle_anim(True)
else:
self.shown_length = 0
# Toggle the animation to be play forward or backward
def toggle_anim(self, toggling):
if toggling:
self.anim.setDirection(QAbstractAnimation.Forward)
else:
self.anim.setDirection(QAbstractAnimation.Backward)
self.anim.start()
def boundingRect(self):
return self.parent.boundingRect()
def paint(self, painter, style, widget=None):
painter.setPen(self.default_pen)
painter.drawText(self.parent.boundingRect(), Qt.AlignCenter, self.shown_text)
# Defining the length to be drawn as a pyqtProperty
@pyqtProperty(int)
def shown_length(self):
return self._shown_length
# Determine the length of the four lines to be drawn
@shown_length.setter
def shown_length(self, value):
self._shown_length = value
if value < self.delay:
# All printed text should be garbage
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in range(value)]]
self.shown_text = ''.join(garbage)
else:
# Printed text contain some actual text
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in
range(min(len(self.actual_text) + self.delay - value, self.delay))]]
self.shown_text = self.actual_text[:value - self.delay] + ''.join(garbage)
self.update()
class AnimatedLabel(QLabel):
"""
QLabel that a message, which is displayed through animation.
"""
def __init__(self, text, speed=75, delay=20, parent=None):
"""
Does some text processing, and set up the animation to display the text
Parameters
----------
text: str
Text to be displayed
speed : int
The period at which a new character is printed
The total time is calculated as length of text * speed
0 means instant display, like a regular QLabel.
delay : int
The number of garbage to be printed before printing the actual text
parent: QWidget
Pass into QLabel init method
"""
super().__init__(text, parent)
self.speed = speed
self.setWordWrap(True)
self.setContentsMargins(0, 0, 0, 0)
# Text processing
# Make sure the garbage does not exceed the length of actual text
self.actual_text = text
self.shown_text = ''
if delay >= 0:
self.delay = min(delay, len(self.actual_text))
else:
self.delay = len(self.actual_text)
# Find out where the new paragraphs are so that it is retained
self.splitpoints = []
current_point = 0
line_splits = self.actual_text.split('\n')
for line in line_splits:
current_point += len(line)
self.splitpoints.append(current_point)
current_point += 1
# Set up the shown text length to be animated
self.shown_length = 0
self.anim = QPropertyAnimation(self, b'shown_length')
self.anim.setDuration(len(self.actual_text) * speed)
self.anim.setStartValue(0)
self.anim.setEndValue(len(self.actual_text) + self.delay)
#self.setStyleSheet("""
# color: rgb(0, 255, 0);
# """)
self.toggle_anim(True)
@pyqtProperty(int)
def shown_length(self):
"""
int : The value for the animation
When the value is set, the text to be printed is generated accordingly.
It determines whether actual text is to be printed, and retains the
paragraphs when printing garbage.
"""
return self._shown_length
@shown_length.setter
def shown_length(self, value):
self._shown_length = value
if value < self.delay:
# All printed text should be garbage
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in range(value)]]
# Retain the paragraphs
for num in self.splitpoints[:-1]:
if num < value:
garbage[num] = '\n'
self.setText(''.join(garbage))
else:
# Printed text contain some actual text
garbage = [chr(num) for num in
[random.choice(range(33, 127)) for _ in
range(min(len(self.actual_text) + self.delay - value, self.delay))]]
# Retain the paragraphs, but offset by the number of actual text
non_garbage = value - self.delay
for num in self.splitpoints[:-1]:
if num - non_garbage > 0 and num < value:
garbage[num - non_garbage] = '\n'
self.setText(self.actual_text[:value - self.delay] + ''.join(garbage))
def toggle_anim(self, toggling):
"""
Toggle the animation to be play forward or backward
Parameters
----------
toggling: bool
True for forward, False for backward
"""
if toggling:
self.anim.setDirection(QAbstractAnimation.Forward)
else:
self.anim.setDirection(QAbstractAnimation.Backward)
self.anim.start()
def replace_text(self, new_text):
self.shown_length = 0
self.actual_text = new_text
self.anim.setDuration(len(self.actual_text) * self.speed)
self.anim.setEndValue(len(self.actual_text) + self.delay)
self.toggle_anim(True)