Text-Widget mit formatierter Ausgabe

Fragen zu Tkinter.
Antworten
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@Sirius3: Ja, Deine Lösung gefällt mir eindeutig besser. Nach so einer übersichtlichen Lösung hatte ich anfänglich gesucht, nichts gefunden, dann erst einmal mit XML probiert und dann noch einmal nach einen Ansatz mit HTML gesucht. Alles was ich für mich verständliches fand, war unten der letzte Code auf dieser Seite mit self.recordh2 = True und False und den hatte ich dann als Ansatz für einen Anfang benutzt, um ein Dictionary mit richtig durchnummerierten Schlüssen zu erhalten:

https://stackoverflow.com/questions/848 ... -from-tags

Doch so wie Du das geschrieben hast, ausprobiert habe ich es, sieht sauberer und übersichtlicher aus.
knut
User
Beiträge: 14
Registriert: Freitag 18. August 2017, 15:23

Liebe Freunde,

Für mich als Newbie waren Eure Kommentare sehr lehrreich und dafür herzlichen Dank.
Euer Wissen verlangt Respekt und Achtung. Man könnte dabei den Mut zum Weiterlernen verlieren. Mich aber spornt das an zu noch vielen weiteren Bemühungen.

Gruß Knut
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

Sirius3 hat geschrieben:@Melewo: ein Wort in einem Text fett haben zu wollen ist jetzt keine so große Ausnahme. Hat jetzt auch nichts mit kompliziertem CSS und DIV-Elementen zu tun. Eine Lösung, die halbwegs nur für die von Dir verwendete HTML-Struktur funktioniert, ist nicht robust.
Nun funktioniert das Script auch mit "strong" und mit "span class name" und mit einem hellbrau hinterlegten Bereich für Zitate oder ähnlichen, der dann aber bereits in HTML in einem div-Bereich gelegt werden muss. Beide "div class name" und "p class name" muss dann halt wie bei "span class name" mit den Tkinter-Tags übereinstimmen. Das Herumgemurkse ist geblieben, Tkinter nimmt nur Tags und da folgt dann nach einem Tag ein anderer Tag und wenn ein p oder br Tkinter-Tag normalen Text enthält, muss man halt hinter </span> wieder auf einen Tkinter-Tag "normal" wechseln.

Dass sich der Code noch verbessern ließe und weiter ausbauen, darüber bin ich mir fasst im Klaren, wobei ich mir dann überlegte, ob es einen Sinn ergibt, einzelne Zeilen in Funktionen auszulagern, wenn es in der nächsten Zeile bereits wieder Unterschiede gibt und an Stelle einer ausgelagerten Zeile dann ein Funktionsaufruf notiert wird. Na ja, kann ja nur von meinem jetzigen Kenntnisstand ausgehen und mit dem würde es noch nicht viel kürzer oder eleganter oder übersichtlicher werden.

Code: Alles auswählen

from tkinter import Tk, Text, Scrollbar, PhotoImage, END
from PIL import Image, ImageTk
from html.parser import HTMLParser

class MiniHTMLParser(HTMLParser):

    def __init__(self):
        HTMLParser.__init__(self)
        self.items = []
        self.tag = self.attrs = None

    def handle_starttag(self, tag, attrs):
        self.tag = tag
        self.attrs = attrs
        if tag == "img":
            self.items.append((self.tag, self.attrs, None))

    def handle_data(self, data):
        self.items.append((self.tag, self.attrs, data))


class LesetestHTML(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.images = []

        self.title("Lesetest")
        self.config(bg="#d9cda3")

        self.textfeld = Text(
            self, height=44, pady=12, padx=12, wrap="word")
        scrollbar = Scrollbar(self)
        scrollbar.config(command = self.textfeld.yview)
        self.textfeld.config(yscrollcommand = scrollbar.set)
        scrollbar.pack(side="right", fill="y")
        self.textfeld.pack(pady=24, padx=24)

        self.textfeld.tag_config(
            "h1", font=("cambria", 22),
            foreground="#c7a621", spacing3=10)
        self.textfeld.tag_config(
            "h2", font=("cambria", 18),
            foreground="#98732e", spacing3=28)
        self.textfeld.tag_config(
            "h3", font=("cambria", 12, "bold"),
            foreground="#74521c", spacing1=22)
        self.textfeld.tag_config(
            "p", font=("cambria", 12))
        self.textfeld.tag_config(
            "br", font=("cambria", 12))
        self.textfeld.tag_config(
            "normal", font=("cambria", 12))
        self.textfeld.tag_config(
            "klein", font=("cambria", 6))
        self.textfeld.tag_config(
            "strong", font=("cambria", 12, "bold"))
        self.textfeld.tag_config(
            "mittig", font=("cambria", 12), justify="center")
        self.textfeld.tag_config(
            "img", justify="center", spacing1=6)
        self.textfeld.tag_config(
            "bildnotizen", font=("cambria", 10, "italic"),
            foreground="#867a44", justify="center")
        self.textfeld.tag_config(
            "boldgrau", font=("cambria", 12, "bold"),
            foreground="#404040")
        self.textfeld.tag_config(
            "boldbraun", font=("cambria", 12, "bold"),
            foreground="#9b4c21")
        self.textfeld.tag_config(
            "fehler",  font=("cambria", 12),
            foreground="#ff8808", justify="center")
        self.textfeld.tag_config(
            "quotes", background="#e6e5da")
        self.textfeld.tag_config(
            "zitate",  font=("cambria", 12, "italic"),
            background="#e6e5da", justify="center",
            rmargin=20, lmargin1=20, lmargin2=20,
            spacing1=22, spacing3=22)

    def insert_content(self, anfang, content, ende, tag):
        self.textfeld.insert(END, "{0}{1}{2}"
            .format(anfang, content, ende), tag)

    def oeffne_htmlseite(self, filename):
        parser = MiniHTMLParser()
        try:
            with open(filename) as datei:
                dateistring = datei.read().replace(
                              "</span>", "[endspan]").replace(
                              "</strong>", "[endstrong]")
                parser.feed(dateistring)
        except FileNotFoundError:
            parser.feed("<h3>Die Datei wurde nicht gefunden!</h3>")

        # Wenn ein 'class name' aus dem HTML-Dokument verwendet werden soll,
        # wird dieser abgefragt und als Tkinter-Tag angelegt.
        # 'letzte_tagdata' enhält die Länge von content, bei einem leeren Endtag
        # ist dieser 0 bis 1, so dass z.B. ermittelt wird, ob der letzte Tag
        # Content enthielt und noch ein Leertag gesetzt werden kann oder ob
        # Span-Bereiche mit einem " " Leerzeichen oder mit "" keinem beginnen.
        # 'br_umbrueche' dient ebenfalls dazu, um nur einen abschließenden leeren
        # Tag zu setzen. 'letzter_tag' ist für br, falls img vorausging.

        br_umbrueche = 1
        letzte_tagdata = 1
        letzter_tag = None
        for tag, attrs, data in parser.items:
            if tag in ("h1", "h2"):
                content = data.replace("  ", "")
                self.insert_content("", content, "", tag)

            elif tag == "h3":
                content = data.replace("  ", "")
                if len(content) > 2:
                    self.insert_content("\n", content, "", tag)
                else:
                    self.insert_content("\n", content, "", "klein")
                letzte_tagdata = len(content)
                letzter_tag = tag

            elif tag == "div":
                if "class" in dict(attrs):
                    if dict(attrs)["class"] == "quotes":
                        self.insert_content("\n", "", "\n", "normal")
    
            elif tag == "p":
                content = " ".join(data.split())
                if not "class" in dict(attrs):
                    self.insert_content("", content, "", "normal")
                elif dict(attrs)["class"] == "mittig":
                    anfang = ("\n" if letzter_tag != "br" else "")
                    self.insert_content(anfang, content, "", "mittig")
                elif dict(attrs)["class"] == "zitate":
                    if len(content):
                        self.insert_content("", content, "\n", "zitate")
                    elif letzte_tagdata > 2:
                        self.insert_content("\n", "", "\n", "klein")
                letzte_tagdata = len(content)
                letzter_tag = tag

            elif tag == "br":
                content = " ".join(data.split())
                if len(content) != br_umbrueche and letzter_tag != "img":
                    self.insert_content("\n", content, "", "normal")
                    br_umbrueche = len(content)
                letzte_tagdata = len(content)
                letzter_tag = tag

            # Inline-Tags ohne "\n" am Ende, mit Ausnahme von "bildnotizen".
            elif tag == "span" and dict(attrs)["class"]:
                tag = dict(attrs)["class"]
                spandata = data.split("[endspan]")

                if tag == "boldbraun" or tag == "boldgrau":
                    anfang = ("" if letzte_tagdata < 2 else " ")

                    content = " ".join(spandata[0].split())
                    self.insert_content(anfang, content, " ", tag)
                    if len(spandata) > 1:
                        content = " ".join(spandata[1].split())
                        self.insert_content(anfang, content, " ", "normal")

                elif tag == "bildnotizen":
                    content = " ".join(spandata[0].split())
                    if len(spandata)> 1:
                        self.insert_content("", content, "\n\n", tag)
                letzte_tagdata = len(spandata)
                letzter_tag = tag

            elif tag == "strong":
                anfang = ("" if letzte_tagdata < 2 else " ")

                strongdata = data.split("[endstrong]")
                content = " ".join(strongdata[0].split())
                self.insert_content(anfang, content, " ", tag)
                if len(strongdata) > 1:
                    content = " ".join(strongdata[1].split())
                    self.insert_content(anfang, content, " ", "normal")
                letzte_tagdata = len(strongdata)
                letzter_tag = tag

            elif tag == "img":
                try:
                    image = Image.open(dict(attrs)["src"])
                    image = ImageTk.PhotoImage(image)
                    self.insert_content("\n", " ", "", "img")
                    self.textfeld.image_create(END, image=image)
                    letzter_tag = tag
                    self.insert_content(""," ", "\n", "img")
                    self.images.append(image)
                except FileNotFoundError:
                    self.textfeld.insert(
                        END, "Das Image wurde nicht gefunden.\n\n",
                        "fehler")


def main():
    root = LesetestHTML()
    root.oeffne_htmlseite("lorem-ipsum.html")
    root.mainloop()

if __name__ == "__main__":
    main()
Bild

[codebox=html5 file=Unbenannt.html]<!DOCTYPE html>
<html>

<head>
<title>HTML Test</title>
<style type="text/css">
body {with font-family:cambria; font-weight:normal; font-size:16px}
div.wrapper{width:668px; padding:12; margin:auto}
h1 {font-family:cambria; font-weight:bold; font-size:24px}
h2 {font-family:cambria; font-weight:bold; font-size:20px}
h3 {font-family:cambria; font-weight:bold; font-size:16px}
.mittig {text-align:center}
.bildnotizen {
font-family:cambria;
font-style:italic;
font-size:10px;
color:#867a44
}
.boldgrau {font-weight:bold; color:#404040}
.boldbraun {font-weight:bold; color:#9b4c21}
.quotes {background-color:#e6e5da; border:1px solid #ff0000}
.zitate {
font-family:cambria;
font-style:italic;
font-size:16px;
text-align:center;
margin:20px
}
@media only all and (max-width:698px) {
div.wrapper {width:100%}
img.images {max-width:100%; height:auto}
</style>
</head>

<body>
<div class="wrapper">
<h1>Nur ein HTML-Test</h1>
<h2>Untertitel</h2>
<p>Lorem ipsum dolor sit amet, <strong>Lconsetetur sadipscing</strong> elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
diam voluptua.<br>
Stet clita kasd gubergren, no sea <span class="boldbraun">takimata</span> sanctus
est Lorem ipsum dolor sit amet.</p>
<h3>Punkt 1</h3>
<p><span class="boldbraun">Lorem ipsum</span> dolor sit amet, consetetur
sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna
aliquyam erat, sed diam voluptua.</p>
<p class="mittig">
<img src="testbild_1.png" alt="Test" width="240" height="192" class="images"><br>
<span class="bildnotizen">Bild 1: Notizen unterm Bild</span>
</p>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</p>
<div class="quotes">
<p class="zitate">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed
diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed
diam voluptua.</p>
</div>
<p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod
tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.<br>
<br>
Stet clita kasd gubergren.</p>
</div>
</body>
</html>[/code]
Antworten