SWB: Textausgabe mit Zeilenumbruch
Für die Textausgabe mit Zeilenumbruch wird lxml zum Extrahieren des Textes benutzt. Zur Berechnung der Positionen der Wörter und ihrer Ausgabe kommt im zweiten Schritt die Text-Widget-Klasse hinzu.
HTML parsen -> Text ausgeben
swb_03_show_text zeigt nur den Text des HTML-Dokuments an.
Als HTML-Parser wird lxml benutzt. Das
etree.HTMLParser(remove_blank_text=True) entfernt den
nicht benötigten Leerraum zwischen den Tags.
r = requests.get(url, headers={'user-agent': self.USER_AGENT})
self.html_sourcecode = r.text
html_parser = etree.HTMLParser(remove_blank_text=True)
html_tree = etree.fromstring(self.html_sourcecode, html_parser)
text = etree.tostring(html_tree, encoding='unicode', method='text')
self.text_box.set_text(text)
self.text_box.layout(self.g)
Download: Revision 117
svn checkout --revision 117 https://svn.sven-drieling.de/repos/trunk/playground/webbrowser/ yd-playground-webbrowser-117
Text mit Zeilenumbruch
swb_04_text_linebreak zeigt den Text mit Zeilenumbruch an.
Statt einer for-Schleife benutze ich den Iterator direkt und hole das jeweils nächste Wort mit
word = next(wordsIter), so ist der Quelltext linear in 1. Wort, nachfolgende Wörter bis
Zeile gefüllt und Zeilenende eingeteilt.
def layout(self, g):
self.text_width = 0
self.text_height = 0
wordsIter = iter(self.words)
try:
word = next(wordsIter)
(word_width, word_height) = g.font.size(word)
while True:
# First word in line
line_width = word_width
line_height = word_height
# Fill line with following words
word = next(wordsIter)
(word_width, word_height) = g.font.size(word)
while line_width + self.WORD_GAP + word_width < self.width:
line_width = line_width + self.WORD_GAP + word_width
line_height = max(line_height, word_height)
word = next(wordsIter)
(word_width, word_height) = g.font.size(word)
# Next line
self.text_width = max(self.text_width, line_width)
self.text_height = self.text_height + line_height + self.LINE_GAP
except StopIteration:
# Last line
self.text_width = max(self.text_width, line_width)
self.text_height = self.text_height + line_height
Download: Revision 119
svn checkout --revision 119 https://svn.sven-drieling.de/repos/trunk/playground/webbrowser/ yd-playground-webbrowser-119
Text-Widget
Zu Vereinfachung werden die vielen unterschiedlichen HTML-Elemente im Rendertree auf eine Handvoll
Widgets reduziert (Widget als grafisch dargestelltes Element zur deutlicheren Unterscheidung von den
nicht sichtbaren Nodes im HTML-Baum). Für viele Texte reichen so TextWidget mit dem
Textteilen, AttributeWidget zum Setzen der Schrift und Farben und VSpaceWidget
für den vertikalen Leerraum aus. Aus:
<h1>Überschrift</h1> <p>Paragraph.</p>
wird:
AttributeWidget(font='DejaVuSans.ttf', size=24) TextWidget(text='Überschrift') VSpace(width=0, height=8) AttributeWidget(font='DejaVuSerif.ttf', size=16) TextWidget(text='Paragraph')
Der erste Schritt dahin ist das swb_05_text_widget.
class TextWidget(Widget):
def __init__(self, text = ''):
super().__init__()
self.text = text
def calculate_size(self, g):
(self.width, self.height) = g.font.size(self.text)
def draw(self, g, left, top):
text_surface = g.font.render(self.text, True, g.fg, g.bg)
g.surface.blit(text_surface, (self.left + left, self.top + top))
Damit bekommt in der
TextBox
auch die Einteilung in layout() und draw() mehr Sinn. layout()
berechnet die Position und Größe der Text-Widgets und draw() braucht diese nun nur noch
auszugeben, ohne selbst Zeilenumbrüche zu berechnen.
def layout(self, g):
self.text_width = 0
self.text_height = 0
widgetsIter = iter(self.widgets)
try:
widget = next(widgetsIter)
widget.calculate_size(g)
while True:
# First widget in line
widget.left = 0
widget.top = self.text_height
line_width = widget.width
line_height = widget.height
# Fill line with following widgets
widget = next(widgetsIter)
widget.calculate_size(g)
widget.left = self.left + line_width
widget.top = self.text_height
while line_width + self.WORD_GAP + widget.width < self.width:
line_width = line_width + self.WORD_GAP + widget.width
line_height = max(line_height, widget.height)
widget = next(widgetsIter)
widget.calculate_size(g)
widget.left = self.left + line_width
widget.top = self.text_height
# Next line
self.text_width = max(self.text_width, line_width)
self.text_height = self.text_height + line_height + self.LINE_GAP
except StopIteration:
# Last line
self.text_width = max(self.text_width, line_width)
self.text_height = self.text_height + line_height
def draw(self, g):
g.surface.fill((255, 255, 255))
for widget in self.widgets:
widget.draw(g, self.left - self.scroll_left, self.top - self.scroll_top)
Download: Revision 121
svn checkout --revision 121 https://svn.sven-drieling.de/repos/trunk/playground/webbrowser/ yd-playground-webbrowser-121
