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