Skip to main content

Keep Tkinter — embed a real system WebView in your Frame (wry, child-window embedding)

Project description

tkwry

License: MIT PyPI - Python Version GitHub Release PyPI Version Downloads Status: Alpha CI

Keep Tkinter — give it the WebView it never had.

Embed a real system WebView (wry) inside your Frame: modern HTML, JS, and IPC in the same layout as your buttons and tabs — one mainloop, no floating overlay.

Alpha — Early preview (see PyPI badge for the current version). APIs and behavior may change without notice. Not recommended for production use yet.


📖 Overview

Tkinter is still a solid GUI shell — it just had no first-class way to host modern web content inside a widget. Overlay-style WebViews drift out of sync when you move, resize, or switch tabs.

tkwry fills that missing piece:

  • True child embeddingbuild_as_child via HWND, NSView, or X11 window ID
  • One event loop — Tk mainloop only; no separate app runtime
  • IPC bridge — JavaScript → Python callbacks without freezing the UI
  • Layout-aware — tracks pack / grid / place, tabs, and PanedWindow

Pre-built abi3 wheels ship for Windows (x86_64) and macOS (Apple Silicon + Intel). Linux is supported via source install (sdist / git) — PyPI wheels for Linux are intentionally not published.


🔧 Requirements

  • Python 3.10+
  • Tkinter (included with most Python builds)
  • Windows (x86_64 only)
    • WebView2 Runtime must be installed (pre-installed on many Windows 10/11 systems).
    • Without WebView2, tkwry is not supported on Windows — there is no fallback engine.
  • macOS — 11 (Big Sur) or later; Apple Silicon (arm64) or Intel (x86_64); system WKWebView (no extra runtime)
  • Linux — WebKitGTK 4.1 + GTK 3 dev packages; X11 or XWayland ($DISPLAY); build the extension from source (see below)

📦 Installation

Install from PyPI (Windows / macOS wheels):

pip install tkwry

Developing or running examples from a git clone — use an editable install so Python picks up this repo (not an older copy in site-packages):

pip install -e .

Or install from GitHub for the latest changes:

pip install git+https://github.com/mashu3/tkwry.git

Linux (source install)

Linux is fully supported, but only as a source build — not via a PyPI wheel. Install system dependencies, then:

# Debian / Ubuntu
sudo apt install \
  libwebkit2gtk-4.1-dev \
  libgtk-3-dev \
  libglib2.0-dev

# Runtime (for end users of your app)
# sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0

pip install maturin
git clone https://github.com/mashu3/tkwry.git
cd tkwry
pip install .

GTK events are pumped automatically on a Tk timer while your app runs.


🚀 Usage

Basic WebView

import tkinter as tk
from tkwry import WebView

root = tk.Tk()
root.geometry("900x600")

frame = tk.Frame(root, bg="#222")
frame.pack(fill="both", expand=True, padx=8, pady=8)

web = WebView(frame, url="https://github.com")

root.mainloop()

IPC (JavaScript → Python)

def on_message(msg: str) -> None:
    print("from JS:", msg)

web = WebView(
    frame,
    html='<button onclick="window.ipc.postMessage(\'hi\')">send</button>',
    ipc_handler=on_message,
)

Load HTML / evaluate JavaScript

web.load_html("<h1>Hello</h1>")
web.eval_js("document.title = 'Hi'")
web.eval_js_with_callback("document.title", print)
web.load_url("https://example.com")
web.reload()
print(web.url)
web.focus()
web.open_devtools()

Navigation / lifecycle callbacks

from tkwry import NewWindowResponse, PageLoadEvent

web = WebView(
    frame,
    url="https://example.com",
    on_page_load=lambda evt, url: print(evt, url),
    on_title_changed=lambda title: root.title(title),
    on_navigation=lambda url: url.startswith("https://"),
    on_new_window=lambda url: NewWindowResponse.Deny,
)

Drag & drop (native OS path)

File drops from Finder / Explorer are handled by the OS WebView. Your handler runs on the Tk main thread (tkwry queues events from WebKit automatically).

from tkwry import DragDropEvent

def on_drop(event, paths, position):
    if event == DragDropEvent.Drop:
        print("files:", paths)

web = WebView(frame, html="...", drag_drop_handler=on_drop)

See examples/dnd_demo.py.

Cleanup

web.destroy()   # release native webview; host Frame is kept
# or destroy the host Frame — both tear down the webview

📚 API summary

Category Members
Content load_url, load_html, reload, url
JavaScript eval_js, eval_js_with_callback
IPC set_ipc_handler
Callbacks set_on_navigation, set_on_page_load, set_on_title_changed, set_on_new_window, set_drag_drop_handler
Appearance set_background_color, focus, focus_parent, open_devtools, close_devtools, is_devtools_open
Layout pack, grid, place (delegate to host Frame)
Lifecycle destroy, destroyed, native

Constructor options: url, html, ipc_handler, devtools, background_color, user_agent, initialization_script, focused, plus the callback hooks above.

Enums: PageLoadEvent, NewWindowResponse, DragDropEvent.


⚠️ Known limitations

  • Alpha — APIs may change; not recommended for production yet
  • Windows — WebView2 Runtime required; systems without it are unsupported
  • Linux — no pre-built PyPI wheel (source install only; this is intentional)
  • DevTools — macOS uses private APIs; avoid in Mac App Store release builds
  • macOS input — keyboard focus is shared between Tk and the WebView on the main thread; typing may feel slightly less snappy than a standalone browser (especially with IME on)
  • Drag & drop — drop target is the WebView area only (not arbitrary Tk widgets; use tkinterdnd2 for those)

See CHANGELOG.md for release history.


🌐 Platform notes

OS Arch Parent handle Engine Notes
Windows x86_64 Frame.winfo_id() → HWND WebView2 WebView2 Runtime required
macOS arm64, x86_64 Toplevel content NSView WKWebView See macOS embedding below
Linux winfo_id() → X11 window ID WebKitGTK GTK pumped on a Tk timer; source install

macOS embedding

On macOS, Tk child Frames usually do not get their own NSView — that is a property of the Tk Aqua backend, not something tkwry can turn into per-frame native views without upstream Tk changes.

tkwry works around this by:

  1. Attaching the WebView to the toplevel content view
  2. Positioning it with set_bounds to match your Frame (<Configure>)
  3. Hiding it with set_visible(False) when the frame is unmapped (<Unmap>) — e.g. another ttk.Notebook tab is selected

Keyboard focus (macOS): Rust routes clicks between Tk widgets and the WebView. You may notice slight input latency compared to a normal browser; v0.0.1 treats this as a known limitation.

You do not need extra code for tabs or panes — see examples/multi_demo.py. IPC, page-load, title, eval, and drag-and-drop handlers are dispatched on the Tk main thread via an internal queue (avoids WebKit deadlocks).


💡 Why child-window embedding?

Tkinter apps already have a window and a layout. The web belongs inside a Frame — same mainloop, same tabs and panes — not in a separate top-level webview that floats beside your UI. tkwry wraps wry's build_as_child against the native surface Tk gives your widgets.


🧩 Features

  • Child-window embedding — WebView is a native child of your Tk window surface, not a floating overlay
  • Bounds & visibility sync — follows <Configure>, <Map>, and <Unmap> (tabs / Notebook work out of the box on macOS)
  • Deferred callbacks — IPC, page load, title, eval results, and DnD queue to Tk (avoids macOS deadlocks)
  • URL safety — normalizes and validates URLs before navigation
  • DevToolsopen_devtools() / devtools=True for debugging
  • Native drag & drop — OS-level file drops into the WebView (no tkinterdnd2)
  • Navigation hookson_navigation, on_page_load, on_title_changed, on_new_window
  • Multiple layouts — works with pack, grid, place, Notebook, and PanedWindow (see examples)
  • Plotly-ready — load HTML + eval_js for interactive charts
  • Alpha, but tested — CI on Ubuntu (Xvfb + WebKitGTK), Windows, and macOS

📁 Examples

python -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -e .
Script Description
examples/url_demo.py URL bar + embedded page
examples/ipc_demo.py JavaScript ↔ Tkinter IPC
examples/multi_demo.py Multiple WebViews, tabs, panes
examples/plotly_demo.py Plotly charts (pip install plotly)
examples/dnd_demo.py Native file drag & drop into WebView
python examples/url_demo.py
python examples/ipc_demo.py
python examples/multi_demo.py
python examples/plotly_demo.py
python examples/dnd_demo.py

📝 License

This project is licensed under the MIT License. See LICENSE.

This project links against wry, which is dual-licensed (Apache-2.0 or MIT). tkwry uses wry under MIT; see NOTICE for attribution.


👨‍💻 Author

mashu3

Contributors

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tkwry-0.0.1.tar.gz (55.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

tkwry-0.0.1-cp310-abi3-win_amd64.whl (337.7 kB view details)

Uploaded CPython 3.10+Windows x86-64

tkwry-0.0.1-cp310-abi3-macosx_11_0_arm64.whl (376.9 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

tkwry-0.0.1-cp310-abi3-macosx_10_12_x86_64.whl (400.6 kB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file tkwry-0.0.1.tar.gz.

File metadata

  • Download URL: tkwry-0.0.1.tar.gz
  • Upload date:
  • Size: 55.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for tkwry-0.0.1.tar.gz
Algorithm Hash digest
SHA256 9c865b5f1eea0c18dd9ce66a3a41b5595bdfbe60b8ffbf42310e7a565eda1977
MD5 ed2131e394f96e21c0a844b82c13cb1a
BLAKE2b-256 55da88b3a3769365b78f33a747f457f93e5f7cbdd6f401da47a4c12e5153fc56

See more details on using hashes here.

File details

Details for the file tkwry-0.0.1-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: tkwry-0.0.1-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 337.7 kB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for tkwry-0.0.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 c01db063fc378c61fff6337714c2e3ad0901a7fd32e892cd7f9afb21ec7499d4
MD5 d81123a13badcd519d13cbb6493e28b9
BLAKE2b-256 6e7f9dcb6098f8435a055dd641ecd8a2492b4c58a385565c657f55bddd73c76b

See more details on using hashes here.

File details

Details for the file tkwry-0.0.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for tkwry-0.0.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 5e4a76ccc47594ec4c30d4c2527066db0be907782e5bf4aa5e3f25c5ecefd150
MD5 791f30d93a831e18b5a1643d3b672dee
BLAKE2b-256 bbd5c4ddb5de4385cf60ef0ce3ca42a0c57503e0eeb8dd63079d49e5d5fc93c5

See more details on using hashes here.

File details

Details for the file tkwry-0.0.1-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for tkwry-0.0.1-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 27b1ae5bf17b515c5af15212a5a2b7bde84dcb2567c4a709bc7ea8e4de4596ff
MD5 ecd8eae5271fbdfba6c71b2b16e07976
BLAKE2b-256 626511dd2619d10701dfd667521b5c24c54e0601a9b6a1d94b2ddfdbb19bba8f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page