tkhtml3

Difference between version 25 and 26 - Previous - Next
'''[http://tkhtml.tcl.tk/%|%Tkhtml 3.0]''' is a new [html] rendering [widget] for [Tk]. It is a rewrite of the
existing Tkhtml widget 2.0 that is included with [ActiveTcl] and other
[batteries included%|%batteries-included] distributions. This page is a tutorial that showcases the capabilities and design of the
new widget without getting bogged down in 
details. Instead of explaining interfaces there are just code fragments.
''Please'' leap in to ask questions, make suggestions or heap ridicule.
The development of Tkhtml 3.0 was sponsored by [Eolas].

[APN] License is, curiously enough, LGPL. Strange, coming from drh.

** Download **

The sources are available on this fossil repository: [http://tkhtml.tcl.tk/fossil%|%sources]. You need to login as anonymous on that repository in order to get the links for downloading ZIP or tarball archives. Being logged in, you can go to the 'Timeline', click on the linked hexadecimal check-in number and then just choose the download you want to have. The lastest check-in is from 2011 (9 Jan): [http://tkhtml.tcl.tk/fossil/info/4ee7aaa953d6cb59]

Note that the 'Sources' link given at tkhtml.tcl.tk is out of date. 




** Documentation **


    [http://tkhtml.tcl.tk/tkhtml.html%|%official reference]:   



** Introduction **

By itself, Tkhtml 3.0 doesn't provide much of the functionality that 
embedding a web browser would. Tkhtml has no idea that there is anything
special about an `<a>` tag, let alone the `"href"` attribute, so clicking on 
a hyper-link does nothing by default. Without extra configuration, Tkhtml 
doesn't understand the significance of a `<style>`, `<title>` or `<img>` tag.

Instead, the widget concentrates on providing interfaces that allow the
majority of policy decisions to be made by the user. For example, the
widget can be queried for the document node that generated the content
at any point in the viewport. When an end-user makes a mouse-click, the
script can query the [html] widget for the relevant document node and decide for
itself if a hyper-link should be followed, some [javascript] executed, the
selection cleared, or some other application specific action.

If an application designer deems that the contents of any `<style>` tags
in the document should be parsed as [CSS] style sheets, they configure
Tkhtml to pass the contents of each parsed `<style>` tag to a handler
script that in turn passes it back to the Tkhtml `style` command.

Tkhtml doesn't really have too much of a dependancy on HTML either.
Most HTML behaviour, i.e. the fact that a `<b>` tag means use bold font,
is configured using a built-in default stylesheet document. Execute the
following script if you want to see this document:

======
package require Tkhtml 3.0
html .h
.h cget -defaultstyle
======

Right now the parser is a holdover from Tkhtml 2.0 and only recognizes 
valid html tags. But in the long run it will be possible to display any
old [XML] document formatted using CSS stylesheets.

Tkhtml is designed with the expectation that most users will use a 
megawidget that provides many of these features. A megawidget to
support common HTML constructs, [Hv3], is being developed and distributed 
as part of Tkhtml, But Tkhtml is useful by itself as well.



*** Running the Examples ***

[hv3] is a demo application of Tkhtml 3. [starkit%|%starkits] are available that wrap Tkhtml
into a minimal web browser so you can see how it goes on complicated web
pages available via HTTP.  There are screenshots there too.



** A Fancy Label Widget **

The simplest use of the html widget is as a fancy label widget. For example:

======
# Load the Tkhtml package
package require Tkhtml 3.0

# Create and populate an html widget.
html .label -shrink 1
.label parse -final {
    <b>Hello <i>world</i></b> example
}

# Pack the new html widget
pack .label
bind .label <KeyPress-q> exit
focus .label
======

This code creates and packs a somewhat unremarkable label containing the 
HTML-formatted text. There are no default bindings, those all have to be
supplied by the user.

The most visible difference between Tkhtml 3.0 and it's predecessor is
that Tkhtml supports stylesheets and the `"style"` attribute. To illustrate:

======
package require Tkhtml 3.0

# Create and populate an html widget
html .button -shrink 1
.button parse -final {<html><div>Exit!</div> Click to Exit :)}
.button style {
    /* This is a CSS style sheet */
    div {
        border:solid 2px;
        border-color: white grey30 grey30 white;
        background: grey85;
        padding: 5px 0px;
        margin: 0px auto;
        text-align: center;
        width: 10ex;
    }
    html {
        background: grey85;
        font-family: Helvetica;
        font-weight: bold;
        padding: 5px;
    }
}

# Pack the new html widget
pack .button
bind .button <1> exit
focus .button
======

Tkhtml 3.0 supports most of the CSS 1.0 properties and selectors,
giving the programmer good control over the document layout. A precise
description of what is supported and what is not may be found at 
http://tkhtml.tcl.tk/support.html .


** A Geometry Manager **

Tkhtml is good for more than just static text and borders, it can also
manage other Tk widgets. Here's a simple example - this time featuring a 
real live button, not a fake like before.

======
package require Tkhtml 3.0

# Create and populate an html widget
html .manager -shrink 1
.manager parse -final {
    <html>
    <div
        widgetcmd="button .manager.button -text Exit! -command exit"
        style="margin: auto"
    />
    Click the above button to exit.
}

# The tricky bit!
foreach nodeHandle [.manager search {[widgetcmd]}] {
    $nodeHandle replace [eval [$nodeHandle attribute widgetcmd]]
}

# Pack the new html widget
pack .manager
======

Once Tkhtml has parsed a document, it exposes the tree structure to the
application via "node-handles". Each node-handle is itself a Tcl command,
with a set of sub-commands that can be used to query and manipulate the
document node. For example the command:

======
$nodeHandle attribute widgetcmd
======

returns the value of the "widgetcmd" attribute of node $nodeHandle. Assuming
the variable $nodeHandle contains the node-handle for the <div> in the example
above, this command would return the string "button .manager.button -text
Exit! -command exit".

The command:

======
$nodeHandle replace $widget
======

tells Tkhtml that instead of drawing content for the node $nodeHandle, map
the Tk window $widget into the html display. The other new command introduced
here is:

======
$html search $selector
======

This command searches the document tree for nodes that match the criteria
specified by $selector. The format for the search criteria is a CSS 1.0
selector. The selector used in the above example, "[widgetcmd]" matches
all nodes that have an attribute named "widgetcmd".

Here's a more elaborate example of the same idea:

======
package require Tkhtml 3.0

# Create and populate an html widget
html .manager -shrink 1
.manager parse -final {
    <html>
    <body>
        <h1 style="text-align:center">XYZ Company Complaints Interface</h1>
        <table border=0 align=center style="border:1px solid">
            <tr>
                <td>First Name<span style="color:red">*</span>:
                <td><div widgetcmd="entry .manager.entry1">
            <tr>
                <td>Last Name<span style="color:red">*</span>:
                <td><div widgetcmd="entry .manager.entry2">
            <tr>
                <td>Employer:
                <td><div widgetcmd="entry .manager.entry3">
        </table>
        <hr>
        <div widgetcmd="text .manager.text" />
        <hr>
        <table border=0 align=center cellpadding=10 style="border:1px solid"><tr>
        <td><div widgetcmd="button .manager.send -text Send -width 20" />
        <td><div widgetcmd="button .manager.cancel -text Cancel -width 20" />
        </table>
    </html>
}

# Trickery!
foreach nodeHandle [.manager search {[widgetcmd]}] {
  $nodeHandle replace [eval [$nodeHandle attribute widgetcmd]]
}

.manager.text insert 0.0 "Enter message here."

# Pack the new html widget
pack .manager -fill both -expand true
======

''Please Note:'' The code in the above examples executes Tcl scripts
embedded in the document passed to the html widget. This is Ok, because
in this case the document is embedded in the application itself. There
is no way for the html widget to get hold of an external document that
may contain malicious scripts. It would be very foolhardy indeed to use
the same techniques in an application that might obtain documents from
external sources. Cough... internet explorer cough...

Tkhtml provides no special support for html forms other than the ability to
replace document nodes with Tkhtml windows as demonstrated above.
Implementing that sort of thing is up to applications or megawidget
frameworks. This allows the same "replace-node" interface to be used
for web plugin implementations, or to embed a canvas widget configured to
render an embedded SVG image.

Tkhtml does provide ways to register scripts for execution:

   * When a replacement window is no longer required (e.g. because a newdocument is loaded),
   * To configure the colors, fonts etc. of replaced windows according to the document and stylesheets, and
   * As soon a document node that matches a specified selector has been parsed (allows for incremental parsing of documents with embedded forms).

See the full widget man page at http://tkhtml.tcl.tk/tkhtml.html for details.



** Displaying Images **

Html documents aren't much fun without images. With a little help, Tkhtml can 
support background-images, list-marker images and images used to replace
entire nodes. Here's an example:

======
image create photo idir -data {
    R0lGODdhEAAQAPIAAAAAAHh4eLi4uPj4APj4+P///wAAAAAAACwAAAAAEAAQAAADPVi63P4w
    LkKCtTTnUsXwQqBtAfh910UU4ugGAEucpgnLNY3Gop7folwNOBOeiEYQ0acDpp6pGAFArVqt
    hQQAO///
}
image create photo ibg -data {
    R0lGODdhIAAbAJEAAAAAAP///wAA/wAAACwAAAAAIAAbAAACeoyPqYvgD6Oc
    LwAhHN758v6BgMVpn1l6KXmqG/q6mQVjNdi+7M3LImvz9UIOYIwolI0eyGbO
    tks6UzPX8LmSYo8lmpaKXQanXKq4jB63jGqwG8rctsvn63t8nutxWfK+tmSX
    xlf3NaiRx3eYxKb4p+Tl50joRWF5OVIAADs=
}


package require Tkhtml 3.0

# Create and populate an html widget
html .images -shrink 1 -imagecmd get_image -width 200
.images parse -final {
    <html>
    <body style="background-image: url(ibg); color: white ; font-weight:bold">
    <img src="idir" width=100 height=50 align=left>
    Html documents aren't much fun without images. With a little help, Tkhtml
    can support background-images, list-marker images and images used to
    replace entire nodes. The example only shows backgrounds and replaced
    images.
    </body>
    </html>
}
proc get_image {uri} {return $uri}

pack .images
bind .images <KeyPress-q> exit
focus .images
======

The '''`-imagecmd`''' option of the html widget takes a script. When 
the widget finds an image URI, it appends the [URI] to the script and executes
it. The script should return the name of a Tk image to be used by the
html widget. The image may be populated or overwritten by the script
at a later time and the widget display is automatically updated.

By default, Tkhtml deletes images when it has finished using them but it can
be configured to invoke a user-provided script instead. There are also interfaces
to ensure that relative URIs can be interpreted unambiguously (for example 
a relative URI from an external stylesheet may be interpreted differently
to a relative URI embedded in the html document itself).


Here's a slightly fancier, more complete `get_image` procedure that will let you specify a Tk image, a file, or a http url. it needs some error checking incase the file or url specified is not actually an image. It has the added bonus of not creating a new Tk image for repeat use of the same file or url.

======
package require Img
package require http

proc get_url url {
       set token [::http::geturl $url]
       set data [::http::data $token]
       ::http::cleanup $token
       return $data
}

proc get_image uri {
     #if the 'url' passed is an image name
     if { [lsearch [image names]  $uri] > -1 } {
          return $uri
     }

     # if the 'url' passed is a file on disk
     if { [file exists $uri] } {
          #create image using file
          image create photo  $uri -file $uri
          return $uri
     }

     #if the 'url' is an http url. 
     if { [string equal -length 7 $uri http://] } {
          image create photo $uri -data [get_url $uri]
          return $uri
     }
}
======


----

Please post any bugs you find with Tkhtml at this website:

http://tkhtml.tcl.tk/fossil/



** Discussion **

[rdt] I built this on a Mandrake 2006.0 distro and checked out all these snippets.  It's nice.  Thanks.


** See also **

   [tkhtml]:   The main page for Tkhtml


----
'''[JOB] - 2017-01-23'''

[A TclOO Tkhtml 3.0 megawidget - example of how to render html+css]

----
'''[fpigorsch] - 2017-08-16 13:35:00'''

http://tkhtml.tcl.tk/ seems to be down. Anyone knows what's going on there?

https://github.com/olebole/tkhtml3 has a relatively recent snapshot of the original repo.

----
'''[ak] - 2017-08-22 19:56:12'''

Machines moved, updating the DNS records lagged.
Everything should be ok again.

----
"[stlgy] - 2022-02-15"

Some websites are now increasingly using images in svg format instead of gif/png/jpg formats.  The thing with the svg is that the image data tends to be inline and the url part for these seem to be slightly different from what is expected.  An example is below.  

Does Tk support svg format so that one could convert the svg data into an image so Tkhtml can display it?

Example svg data as encountered by tkhtml:

======

Unsupported URL: data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iMzQ4LjMzM3B4IiBoZWlnaHQ9IjM0OC4zMzNweCIgdmlld0JveD0iMCAwIDM0OC4zMzMgMzQ4LjMzNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzQ4LjMzMyAzNDguMzM0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PGc+PHBhdGggZmlsbD0iIzU2NTY1NiIgZD0iTTMzNi41NTksNjguNjExTDIzMS4wMTYsMTc0LjE2NWwxMDUuNTQzLDEwNS41NDljMTUuNjk5LDE1LjcwNSwxNS42OTksNDEuMTQ1LDAsNTYuODVjLTcuODQ0LDcuODQ0LTE4LjEyOCwxMS43NjktMjguNDA3LDExLjc2OWMtMTAuMjk2LDAtMjAuNTgxLTMuOTE5LTI4LjQxOS0xMS43NjlMMTc0LjE2NywyMzEuMDAzTDY4LjYwOSwzMzYuNTYzYy03Ljg0Myw3Ljg0NC0xOC4xMjgsMTEuNzY5LTI4LjQxNiwxMS43NjljLTEwLjI4NSwwLTIwLjU2My0zLjkxOS0yOC40MTMtMTEuNzY5Yy0xNS42OTktMTUuNjk4LTE1LjY5OS00MS4xMzksMC01Ni44NWwxMDUuNTQtMTA1LjU0OUwxMS43NzQsNjguNjExYy0xNS42OTktMTUuNjk5LTE1LjY5OS00MS4xNDUsMC01Ni44NDRjMTUuNjk2LTE1LjY4Nyw0MS4xMjctMTUuNjg3LDU2LjgyOSwwbDEwNS41NjMsMTA1LjU1NEwyNzkuNzIxLDExLjc2N2MxNS43MDUtMTUuNjg3LDQxLjEzOS0xNS42ODcsNTYuODMyLDBDMzUyLjI1OCwyNy40NjYsMzUyLjI1OCw1Mi45MTIsMzM2LjU1OSw2OC42MTF6Ii8+PC9nPjwvc3ZnPg==
    while executing
"::http::geturl $uri        ..."

======

Source URL: https://www.trustpilot.com/review/americanchairs.com 



<<categories>> Widget | HTML | Package