PositronWindowWrapper Class
The PositronWindowWrapper class is the main interface object returned by openUI()
. It serves as a container that provides access to all PyPositron functionality, including DOM manipulation, window management, and Python-JavaScript integration. This object is passed as the ui
parameter to your main function.
Overview
The PositronWindowWrapper acts as the central hub for your PyPositron application. Through this object, you can:
- Access the DOM via the
document
property - Use browser window functionality via the
htmlwindow
property - Call exposed Python functions via the
exposed
property - Manage the execution context via the
context
property - Control the underlying webview window via the
window
property
Properties
Core Components
window
: The underlying webview.Window object that provides low-level window controlcontext -> PositronContext
: The PositronContext object for managing execution context, variables, and event handlersdocument -> Document
: The Document object for DOM manipulation and element selectionexposed -> ExposedFunctions
: The ExposedFunctions object for interacting with Python functions exposed to JavaScripthtmlwindow -> HTMLWindow
: The HTMLWindow object providing JavaScript window functionality (dialogs, timers, browser objects)
Threading
event_thread
: The threading.Thread object responsible for handling events and maintaining the UI responsiveness
Usage Examples
Basic Application Structure
import py_positron
def main(ui):
# ui is a PositronWindowWrapper instance
# Access the document for DOM manipulation
title = ui.document.getElementById("title")
title.innerText = "Welcome to PyPositron!"
# Use browser functionality
ui.htmlwindow.alert("Application loaded successfully!")
# Access exposed functions (if any were provided)
if hasattr(ui, 'exposed'):
# Use exposed functions here
pass
py_positron.openUI("index.html", main=main)
Comprehensive Application Example
import py_positron
import json
import time
def save_data(data):
"""Example exposed function"""
with open("app_data.json", "w") as f:
json.dump(data, f)
return "Data saved successfully"
def load_data():
"""Example exposed function"""
try:
with open("app_data.json", "r") as f:
return json.load(f)
except FileNotFoundError:
return {}
def main(ui):
# Initialize the application
setup_ui(ui)
setup_event_handlers(ui)
load_saved_data(ui)
def setup_ui(ui):
"""Set up the user interface"""
# Set page title
ui.document.title = "PyPositron Data Manager"
# Update header
header = ui.document.getElementById("header")
if header:
header.innerText = "Data Management Application"
header.style.textAlign = "center"
header.style.color = "#333"
header.style.padding = "20px"
# Style the main container
container = ui.document.getElementById("container")
if container:
container.style.maxWidth = "800px"
container.style.margin = "0 auto"
container.style.padding = "20px"
def setup_event_handlers(ui):
"""Set up event handlers for UI elements"""
# Save button
save_btn = ui.document.getElementById("saveBtn")
if save_btn:
def handle_save():
try:
# Get data from form
data = collect_form_data(ui)
# Use exposed function to save data
message = ui.exposed.save_data(data)
# Show success message
ui.htmlwindow.alert(message)
# Log to console
ui.htmlwindow.console.log(f"Data saved: {data}")
except Exception as e:
ui.htmlwindow.alert(f"Error saving data: {str(e)}")
ui.htmlwindow.console.error(f"Save error: {e}")
save_btn.addEventListener("click", handle_save)
# Load button
load_btn = ui.document.getElementById("loadBtn")
if load_btn:
def handle_load():
try:
# Use exposed function to load data
data = ui.exposed.load_data()
# Populate form with loaded data
populate_form_data(ui, data)
# Show success message
ui.htmlwindow.alert("Data loaded successfully!")
except Exception as e:
ui.htmlwindow.alert(f"Error loading data: {str(e)}")
load_btn.addEventListener("click", handle_load)
# Clear button
clear_btn = ui.document.getElementById("clearBtn")
if clear_btn:
def handle_clear():
if ui.htmlwindow.confirm("Are you sure you want to clear all data?"):
clear_form_data(ui)
ui.htmlwindow.console.log("Form data cleared")
clear_btn.addEventListener("click", handle_clear)
def collect_form_data(ui):
"""Collect data from form elements"""
data = {}
# Text inputs
name_input = ui.document.getElementById("nameInput")
email_input = ui.document.getElementById("emailInput")
if name_input:
data["name"] = name_input.value
if email_input:
data["email"] = email_input.value
# Select element
category_select = ui.document.getElementById("categorySelect")
if category_select:
data["category"] = category_select.value
# Checkboxes
checkboxes = ui.document.getElementsByName("preferences")
preferences = []
for checkbox in checkboxes:
if checkbox.checked:
preferences.append(checkbox.value)
data["preferences"] = preferences
# Add timestamp
data["timestamp"] = time.time()
return data
def populate_form_data(ui, data):
"""Populate form elements with data"""
if not data:
return
# Text inputs
if "name" in data:
name_input = ui.document.getElementById("nameInput")
if name_input:
name_input.value = data["name"]
if "email" in data:
email_input = ui.document.getElementById("emailInput")
if email_input:
email_input.value = data["email"]
# Select element
if "category" in data:
category_select = ui.document.getElementById("categorySelect")
if category_select:
category_select.value = data["category"]
# Checkboxes
if "preferences" in data:
checkboxes = ui.document.getElementsByName("preferences")
for checkbox in checkboxes:
checkbox.checked = checkbox.value in data["preferences"]
def clear_form_data(ui):
"""Clear all form data"""
# Text inputs
inputs = ui.document.getElementsByTagName("input")
for input_field in inputs:
if input_field.getAttribute("type") in ["text", "email", "password"]:
input_field.value = ""
elif input_field.getAttribute("type") == "checkbox":
input_field.checked = False
# Select elements
selects = ui.document.getElementsByTagName("select")
for select in selects:
select.selectedIndex = 0
def load_saved_data(ui):
"""Load saved data on application startup"""
try:
data = ui.exposed.load_data()
if data:
populate_form_data(ui, data)
ui.htmlwindow.console.log("Saved data loaded on startup")
except Exception as e:
ui.htmlwindow.console.warn(f"Could not load saved data: {e}")
def on_window_close(ui):
"""Called when the window is about to close"""
ui.htmlwindow.console.log("Application closing...")
# Optionally auto-save data before closing
try:
data = collect_form_data(ui)
if any(data.values()): # If there's any data to save
ui.exposed.save_data(data)
print("Data auto-saved before closing")
except Exception as e:
print(f"Error auto-saving data: {e}")
# Launch the application
py_positron.openUI(
"data_manager.html",
main=main,
after_close=on_window_close,
title="PyPositron Data Manager",
width=900,
height=700,
functions=[save_data, load_data]
)
Window Management Example
import py_positron
def main(ui):
# Window control buttons
setup_window_controls(ui)
# Display window information
display_window_info(ui)
# Window event handlers
setup_window_events(ui)
def setup_window_controls(ui):
"""Set up window control buttons"""
# Minimize button
minimize_btn = ui.document.getElementById("minimizeBtn")
if minimize_btn:
def minimize_window():
# Access the underlying webview window
ui.window.minimize()
minimize_btn.addEventListener("click", minimize_window)
# Maximize/Restore button
maximize_btn = ui.document.getElementById("maximizeBtn")
if maximize_btn:
is_maximized = False
def toggle_maximize():
nonlocal is_maximized
if is_maximized:
ui.window.restore()
maximize_btn.innerText = "Maximize"
is_maximized = False
else:
ui.window.maximize()
maximize_btn.innerText = "Restore"
is_maximized = True
maximize_btn.addEventListener("click", toggle_maximize)
# Close button
close_btn = ui.document.getElementById("closeBtn")
if close_btn:
def close_window():
if ui.htmlwindow.confirm("Are you sure you want to close the application?"):
ui.window.destroy()
close_btn.addEventListener("click", close_window)
def display_window_info(ui):
"""Display information about the window"""
info_div = ui.document.getElementById("windowInfo")
if info_div:
info_html = f"""
<h3>Window Information</h3>
<p><strong>Title:</strong> {ui.document.title}</p>
<p><strong>Inner Size:</strong> {ui.htmlwindow.innerWidth} x {ui.htmlwindow.innerHeight}</p>
<p><strong>Outer Size:</strong> {ui.htmlwindow.outerWidth} x {ui.htmlwindow.outerHeight}</p>
<p><strong>Position:</strong> ({ui.htmlwindow.screenX}, {ui.htmlwindow.screenY})</p>
"""
info_div.innerHTML = info_html
def setup_window_events(ui):
"""Set up window event handlers"""
def on_resize():
# Update window info when resized
display_window_info(ui)
ui.htmlwindow.console.log("Window resized")
def on_focus():
ui.htmlwindow.console.log("Window gained focus")
# You could update UI to show active state
def on_blur():
ui.htmlwindow.console.log("Window lost focus")
# You could update UI to show inactive state
# Add event listeners
ui.htmlwindow.addEventListener("resize", on_resize)
ui.htmlwindow.addEventListener("focus", on_focus)
ui.htmlwindow.addEventListener("blur", on_blur)
py_positron.openUI(
"window_manager.html",
main=main,
title="Window Management Demo",
width=800,
height=600
)
Context and Execution Example
import py_positron
def main(ui):
# Demonstrate context usage
demonstrate_context_features(ui)
def demonstrate_context_features(ui):
"""Demonstrate PositronContext features"""
# Access the context
context = ui.context
# Set global variables that can be accessed in <py> tags
context.globals['app_name'] = 'PyPositron Demo'
context.globals['version'] = '1.0.0'
context.globals['user_data'] = {'name': 'User', 'role': 'Developer'}
# Register a custom event handler
def custom_handler():
ui.htmlwindow.alert("Custom event triggered!")
ui.htmlwindow.console.log("Custom handler executed")
# Store the handler in context
context.event_handlers['custom_event'] = custom_handler
# Set up a button to trigger the custom event
trigger_btn = ui.document.getElementById("triggerBtn")
if trigger_btn:
trigger_btn.addEventListener("click", custom_handler)
# Execute Python code dynamically
execute_btn = ui.document.getElementById("executeBtn")
if execute_btn:
def execute_dynamic_code():
code_input = ui.document.getElementById("codeInput")
if code_input and code_input.value.strip():
code = code_input.value
try:
# Execute the code in the PyPositron context
success, error = context.execute(code)
result_div = ui.document.getElementById("result")
if success:
result_div.innerText = "Code executed successfully!"
result_div.style.color = "green"
ui.htmlwindow.console.log(f"Executed: {code}")
else:
result_div.innerText = f"Error: {error}"
result_div.style.color = "red"
ui.htmlwindow.console.error(f"Execution error: {error}")
except Exception as e:
ui.htmlwindow.alert(f"Execution failed: {str(e)}")
execute_btn.addEventListener("click", execute_dynamic_code)
# Display context information
context_info = ui.document.getElementById("contextInfo")
if context_info:
info_html = f"""
<h3>Context Information</h3>
<p><strong>Global Variables:</strong></p>
<ul>
<li>app_name: {context.globals.get('app_name', 'Not set')}</li>
<li>version: {context.globals.get('version', 'Not set')}</li>
<li>user_data: {context.globals.get('user_data', 'Not set')}</li>
</ul>
<p><strong>Event Handlers:</strong> {len(context.event_handlers)} registered</p>
<p><strong>Exposed Functions:</strong> {len(context.exposed_functions)} available</p>
"""
context_info.innerHTML = info_html
py_positron.openUI(
"context_demo.html",
main=main,
title="Context and Execution Demo",
width=900,
height=700
)
Properties Deep Dive
window
The window
property provides access to the underlying webview.Window object, which offers low-level window control:
def main(ui):
# Window operations
ui.window.minimize()
ui.window.maximize()
ui.window.restore()
ui.window.destroy()
# Window properties (may vary by backend)
# ui.window.width
# ui.window.height
# ui.window.x
# ui.window.y
context
The context
property provides access to the execution environment:
def main(ui):
# Access global and local variables
ui.context.globals['my_var'] = 'Hello World'
ui.context.locals['local_var'] = 42
# Execute Python code
success, error = ui.context.execute("print('Hello from context!')")
# Register event handlers
ui.context.event_handlers['my_event'] = my_handler_function
document
The document
property is your main interface for DOM manipulation:
def main(ui):
# Element selection
element = ui.document.getElementById("myElement")
elements = ui.document.getElementsByClassName("myClass")
# Element creation
new_element = ui.document.createElement("div")
# Document properties
ui.document.title = "New Title"
body = ui.document.body
exposed
The exposed
property provides access to Python functions exposed to JavaScript:
def my_function(x, y):
return x + y
def main(ui):
# Call exposed functions
result = ui.exposed.my_function(5, 3)
print(result) # 8
py_positron.openUI("app.html", main=main, functions=[my_function])
htmlwindow
The htmlwindow
property provides browser window functionality:
def main(ui):
# Dialogs
ui.htmlwindow.alert("Hello!")
result = ui.htmlwindow.confirm("Continue?")
name = ui.htmlwindow.prompt("Your name?")
# Timers
timer_id = ui.htmlwindow.setTimeout(my_callback, 1000)
ui.htmlwindow.clearTimeout(timer_id)
# Browser objects
console = ui.htmlwindow.console
navigator = ui.htmlwindow.navigator
location = ui.htmlwindow.location
Best Practices
-
Cache references: Store frequently used objects in variables:
def main(ui): doc = ui.document window = ui.htmlwindow # Use doc and window instead of ui.document and ui.htmlwindow
-
Error handling: Always handle potential errors when accessing UI components:
def main(ui): element = ui.document.getElementById("myElement") if element: element.innerText = "Found!" else: ui.htmlwindow.console.warn("Element not found")
-
Clean separation: Keep different concerns separate:
def main(ui): setup_ui(ui) # UI setup setup_events(ui) # Event handlers load_data(ui) # Data loading
-
Use context wisely: Don't overuse the context for storing application state:
def main(ui): # Good: Store configuration ui.context.globals['config'] = load_config() # Avoid: Storing complex application state # Use proper Python variables instead
Related Documentation
- Document: DOM manipulation through
ui.document
- HTMLWindow: Browser functionality through
ui.htmlwindow
- Internal Classes: PositronContext and ExposedFunctions
- Global Functions: The
openUI()
function that creates PositronWindowWrapper