-
Notifications
You must be signed in to change notification settings - Fork 2
PositronWindowWrapper
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.
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
-
window
: The underlying webview.Window object that provides low-level window control -
context -> PositronContext
: The PositronContext object for managing execution context, variables, and event handlers -
document -> Document
: The Document object for DOM manipulation and element selection -
exposed -> ExposedFunctions
: The ExposedFunctions object for interacting with Python functions exposed to JavaScript -
htmlwindow -> HTMLWindow
: The HTMLWindow object providing JavaScript window functionality (dialogs, timers, browser objects)
-
event_thread
: The threading.Thread object responsible for handling events and maintaining the UI responsiveness
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)
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]
)
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
)
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
)
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
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
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
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])
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
-
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
-
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