Utilities

Dialogs, progress indicators, configuration, and infrastructure classes.

Dialog

class mytk.dialog.Dialog(title, buttons_labels=None, geometry=None, auto_position=None, auto_click=(None, None), *args, **kwargs)[source]

Bases: Base

A modal dialog window with configurable buttons and content.

class Replies(*values)[source]

Bases: StrEnum

Standard reply values returned by dialog buttons.

classmethod showinfo(message, title='Info', auto_click=(None, None), auto_position='center')[source]

Show an informational dialog with the given message.

classmethod showwarning(message, title='Warning', auto_click=(None, None), auto_position='center')[source]

Show a warning dialog with the given message.

classmethod showerror(message, title='Error', auto_click=(None, None), auto_position='center')[source]

Show an error dialog with the given message.

classmethod showprogress(message, title='Info', auto_click=(None, None))[source]

Show a progress dialog with the given message.

property is_disabled

Whether the dialog and its children are disabled.

create_widget(master, **kwargs)[source]

Create the Toplevel dialog window and populate its contents.

populate_buttons()[source]

Create and layout the dialog action buttons.

populate_widget_body()[source]

Populate the main body of the dialog. Override in subclasses.

run()[source]

Display the dialog modally and return the user reply.

create_behavior_buttons()[source]

Create Ok and Cancel buttons based on the configured button labels.

user_clicked_ok(event, button=None)[source]

Handle the Ok button click by setting the reply and closing.

user_clicked_cancel(event, button=None)[source]

Handle the Cancel button click by setting the reply and closing.

class mytk.dialog.SimpleDialog(dialog_type, message, *args, **kwargs)[source]

Bases: Dialog

A ready-made dialog that displays an icon and message for info, warning, or error.

populate_widget_body()[source]

Display the dialog icon and message label in the body area.

populate_buttons()[source]

Create buttons and assign default keyboard shortcuts.

assign_default_key_shortcuts()[source]

Bind Return to Ok and Escape to Cancel.

ProgressBar

class mytk.progressbar.ProgressBarNotification(*values)[source]

Bases: Enum

Notification types for controlling a ProgressBar via NotificationCenter.

class mytk.progressbar.ProgressBar(maximum=100, mode='determinate')[source]

Bases: Base

A determinate or indeterminate progress bar widget.

create_widget(master)[source]

Create the underlying ttk.Progressbar widget.

property value

The current progress value.

handle_notification(notification)[source]

Respond to step, start, and stop notifications.

step(delta)[source]

Advance the progress bar by delta, wrapping at maximum.

start(interval=50)[source]

Start the indeterminate progress animation.

stop()[source]

Stop the indeterminate progress animation.

class mytk.progressbar.ProgressWindow(title, message, *args, **kwargs)[source]

Bases: Dialog

A modal dialog that displays a message with an embedded progress bar.

populate_widget_body()[source]

Display the message label and progress bar in the dialog body.

populate_buttons()[source]

Create buttons and assign default keyboard shortcuts.

assign_default_key_shortcuts()[source]

Bind Return to Ok and Escape to Cancel.

Configurable

Configurable — easy settings management with automatic dialog generation.


Scientific instruments and applications almost always have parameters that need to be adjusted by the user: exposure time, gain, wavelength, threshold values, file paths, and so on. Managing those parameters by hand is tedious: you have to store each value somewhere, write code to check that the user has not entered something impossible (a negative exposure time, a wavelength outside the detector range), and build a dialog box so the user can change the settings interactively.

This module takes care of all of that for you.

The basic idea

You describe each parameter once — its name, its type, its allowed range, and a sensible default — and the framework handles validation, correction of bad values, and the dialog window automatically.

There are two ways to use it. The simple, recommended way is to inherit from Configurable and declare parameters as class attributes:

from mytk import App, Configurable, ConfigurableNumericProperty

class Microscope(Configurable):
exposure_time = ConfigurableNumericProperty(

default_value = 100, min_value = 1, max_value = 10000, displayed_name = “Exposure time (ms)”)

gain = ConfigurableNumericProperty(

default_value = 1.0, min_value = 0.1, max_value = 16.0, displayed_name = “Gain”)

scope = Microscope()

# Read and write parameters like ordinary Python attributes. scope.exposure_time = 500 print(scope.exposure_time) # 500

# Show a settings dialog. The user edits the values and clicks Ok; # the new values are applied to the object automatically. scope.show_config_dialog(title=”Microscope settings”)

# Get all current values at once as a plain dict. print(scope.values) # {‘exposure_time’: 500, ‘gain’: 1.0}

Values are always kept valid. If you accidentally assign a value outside the allowed range it is silently clamped to the nearest boundary:

scope.exposure_time = 99999 # stored as 10000 (the maximum) scope.exposure_time = -5 # stored as 1 (the minimum)

The second way — ConfigModel — is for situations where you need to build the list of parameters programmatically rather than at class definition time. Both approaches use the same ConfigurableProperty building blocks and produce the same dialog.

Available property types

ConfigurableNumericProperty

For numbers (integers or floats). You can set a minimum, maximum, a display multiplier, and a format string for the dialog.

ConfigurableStringProperty

For text values. You can restrict accepted values with a regular expression or a fixed set of allowed strings.

ConfigurableProperty

The base class. Use this when the built-in types do not fit; you can supply any validation function you like via validate_fct.

mytk.configurable.is_numeric(value) bool[source]

Check whether a value is a real number.

class mytk.configurable.ConfigurableProperty(name=None, default_value=None, displayed_name=None, validate_fct=None, valid_set=None, value_type=None)[source]

Bases: object

Descriptor that defines a single configurable parameter with validation.

Instances can be declared as class attributes on a Configurable subclass (descriptor-based approach) or collected into a ConfigModel for dynamic schema construction.

is_in_valid_set(value: Any) bool[source]

Return True if value belongs to the valid set, or if no set is defined.

is_valid_type(value: Any) bool[source]

Return True if value matches the expected type.

is_valid(value: Any) bool[source]

Return True if value passes all validation checks.

sanitize(value) Any[source]

Coerce value to the expected type, falling back to the default on failure.

class mytk.configurable.ConfigurableStringProperty(valid_regex=None, name=None, default_value=None, displayed_name=None, validate_fct=None, valid_set=None)[source]

Bases: ConfigurableProperty

String-typed configurable property with optional regex validation.

is_valid(value: str) bool[source]

Return True if the string passes base validation and matches the regex.

class mytk.configurable.ConfigurableNumericProperty(min_value=-inf, max_value=inf, multiplier=1, format_string=None, name=None, default_value=None, displayed_name=None, validate_fct=None, valid_set=None, value_type=None)[source]

Bases: ConfigurableProperty

Numeric configurable property with range clamping and optional formatting.

is_valid_type(value: Any) bool[source]

Return True if value is numeric or matches the explicit type.

is_in_valid_range(value: Any) bool[source]

Return True if value falls within the allowed min/max range.

is_valid(value: Any) bool[source]

Return True if value passes type, set, and range validation.

sanitize(value) Any[source]

Coerce and clamp value to the allowed numeric range.

static int_property_list(keys: list[str])[source]

Build a list of integer properties from the given key names.

class mytk.configurable.Configurable[source]

Bases: object

Mixin that turns declared ConfigurableProperty attributes into a managed configuration.

property values: dict

Return all current configurable values as a plain dict.

update_values(new_values: dict)[source]

Apply a possibly partial dict of new values.

Each value is sanitized by its property descriptor on assignment.

is_valid(values: dict) dict[source]

Return a per-key dict of booleans indicating validity per property schema.

all_valid(values: dict) bool[source]

Return True only if every value in the dict passes its schema.

show_config_dialog(title='Configuration', **kwargs)[source]

Show a modal configuration dialog built from declared properties.

If the user clicks Ok the values are applied back to self via update_values(). Extra keyword arguments are forwarded to ConfigurationDialog (e.g. buttons_labels, auto_click, geometry).

class mytk.configurable.ConfigModel(properties: list[ConfigurableProperty] = None, values: dict = None)[source]

Bases: object

Explicit-list configuration model for dynamically built property schemas.

property values

Return the current configuration values as a dict.

update_values(new_values)[source]

Set new configuration values after validation.

all_valid(values) bool[source]

Return True only if every value passes its property validation.

is_valid(values)[source]

Return a per-key dict of booleans indicating which values are valid.

sanitize(values)[source]

Return a dict of values coerced to valid types by their properties.

class mytk.configurable.ConfigurationDialog(properties=None, values=None, populate_body_fct=None, *args, **kwargs)[source]

Bases: Dialog, ConfigModel

Modal dialog that presents configurable properties as editable fields.

populate_widget_body()[source]

Create label-entry pairs for each configurable property in the dialog body.

widget_values() dict[source]

Read and sanitize current values from the dialog entry widgets.

run()[source]

Display the dialog and update values if the user clicks Ok.

NotificationCenter

One-to-many notification system for decoupled observer communication.

This implements a notification system where one class can notify many other objects that something has happened. You use this strategy when the notifier does not need to know who does what, but it knows that other objects may need to adjust in response to a change.

At the center of this mechanism is the NotificationCenter: a singleton class that manages the observers and posts the notifications. Notification names must be defined as Enum subclasses.

Example:

class DeviceNotification(Enum):
    will_move = "will_move"
    did_move  = "did_move"

NotificationCenter().post_notification(
    DeviceNotification.did_move, self, user_info={"position": (x, y, z)}
)

The NotificationCenter is thread-safe.

class mytk.notificationcenter.Notification(name, object=None, user_info=None)[source]

Bases: object

A notification object carrying a name, source object, and optional user info.

class mytk.notificationcenter.ObserverInfo(observer, method=None, notification_name=None, observed_object=None)[source]

Bases: object

Record describing an observer registration in the NotificationCenter.

matches(other_observer) bool[source]

Check whether this observer record matches another for lookup purposes.

class mytk.notificationcenter.NotificationCenter(*args, **kwargs)[source]

Bases: object

Singleton notification center for one-to-many observer communication.

All notification names must be Enum members. The center is thread-safe.

destroy()[source]

Destroy the singleton instance and reset the class-level reference.

add_observer(observer, method, notification_name=None, observed_object=None)[source]

Register an observer to be notified when a notification is posted.

Parameters:
  • observer – The object that wants to receive notifications.

  • method – Callable to invoke with the Notification as its argument.

  • notification_name – Enum member identifying the notification to observe.

  • observed_object – If provided, only notifications from this object will be forwarded.

Raises:

ValueError – If notification_name is not None and not an Enum member.

remove_observer(observer, notification_name=None, observed_object=None)[source]

Unregister an observer so it no longer receives notifications.

Parameters:
  • observer – The observer object to remove.

  • notification_name – If provided, remove only for this notification.

  • observed_object – If provided, remove only for this observed object.

Raises:

ValueError – If notification_name is not None and not an Enum member.

post_notification(notification_name, notifying_object, user_info=None)[source]

Post a notification, invoking all matching observer callbacks.

Parameters:
  • notification_name – Enum member identifying the notification.

  • notifying_object – The object posting the notification.

  • user_info – Optional dict of additional data for observers.

Raises:

ValueError – If notification_name is not an Enum member.

observers_count()[source]

Return the total number of registered observer entries.

clear()[source]

Remove all registered observers.

EventCapable

Event mixin class for widget behavior.

Provides the EventCapable class, a mixin designed to add event-related capabilities to GUI widgets that expose a widget attribute compatible with tk.Widget. This includes scheduling timed callbacks, cancelling them, and binding or generating Tkinter events.

It is used for Base and App, which handle their widgets differently.

Also includes the HasWidget protocol to allow static checking of widget presence for type-checkers.

class mytk.eventcapable.HasWidget(*args, **kwargs)[source]

Bases: Protocol

Protocol for objects that expose a widget attribute of type tk.Widget.

This can be used with isinstance(obj, HasWidget) to check interface compliance.

class mytk.eventcapable.EventCapable(*args, **kwargs)[source]

Bases: object

Mixin class providing event-related methods for classes exposing a widget attribute.

Designed to be used alongside other base classes that define self.widget as a tk.Widget. This class should not be used on its own.

Responsibilities: - Scheduling and cancelling timed callbacks (after, after_cancel, etc.) - Event binding and generation via widget.bind and widget.event_generate - Lifecycle cleanup via __del__

after(delay: int, function: Callable) int[source]

Schedules a function to be called after a given time delay.

Parameters:
  • delay (int) – Delay in milliseconds.

  • function (Callable) – Function to invoke.

Returns:

Identifier of the scheduled task, which can be used with after_cancel.

Return type:

int

after_cancel(task_id: int)[source]

Cancels a previously scheduled task by its ID.

Parameters:

task_id (int) – ID of the task returned by after().

after_cancel_many(task_ids: Sequence[int])[source]

Cancels multiple tasks given a sequence of IDs.

Parameters:

task_ids (Sequence[int]) – List or tuple of task IDs to cancel.

after_cancel_all()[source]

Cancel all currently scheduled tasks for this object.

bind_event(event: str, callback: Callable)[source]

Binds a callback function to a specific event on the underlying widget.

Parameters:
  • event (str) – Tkinter event string (e.g. “<Button-1>”).

  • callback (Callable) – Function to be called when the event occurs.

event_generate(event: str)[source]

Triggers an event on the underlying widget programmatically.

Parameters:

event (str) – Event name to trigger (e.g., “<<CustomEvent>>”).

ModulesManager

class mytk.modulesmanager.ModulesManager[source]

Bases: object

Utility for checking, installing, and importing Python modules at runtime.

classmethod validate_environment(pip_modules, ask_for_confirmation=True)[source]

Ensure all required pip modules are installed and imported.

classmethod is_installed(module_name)[source]

Check whether a module can be imported successfully.

classmethod is_not_installed(module_name)[source]

Check whether a module is not installed.

classmethod is_imported(module_name)[source]

Check whether a module has already been imported into sys.modules.

classmethod install_and_import_modules_if_absent(pip_modules, ask_for_confirmation=True)[source]

Install missing modules via pip, optionally prompting the user, then import them.

classmethod install_module(pip_name)[source]

Install a single module using pip.

Vectors

mytk.vectors.same_basis(e1, e2)[source]

Return True if two elements share the same basis.

mytk.vectors.is_standard_basis(basis)[source]

Return True if the basis is None or is the standard (identity) basis.

mytk.vectors.same_origin(e1, e2)[source]

Return True if two elements share the same origin.

class mytk.vectors.PointDefault(basis=None)[source]

Bases: object

Context manager to temporarily override the default basis for Points.

class mytk.vectors.Vector(*args, basis=None)[source]

Bases: object

Two-dimensional vector with optional basis for coordinate transformations.

property c0

Return the first component of the vector.

property c1

Return the second component of the vector.

property length

Return the Euclidean length of the vector in standard coordinates.

property is_unitary

Return True if the vector has unit length within floating-point tolerance.

is_perpendicular(rhs)[source]

Return True if this vector is perpendicular to rhs.

dot(rhs: Vector)[source]

Compute the dot product with another vector in the same basis.

normalized()[source]

Return a unit-length vector in the same direction and basis.

scaled(scale)[source]

Return a new vector with each component multiplied by the corresponding scale factor.

in_basis(new_basis)[source]

Express this vector in a different basis by projection.

change_basis(new_basis)[source]

Re-express this vector in-place in the given basis.

standard_tuple()[source]

Return the components as a tuple in the standard basis.

standard_coordinates()[source]

Return an equivalent vector expressed in the standard basis.

class mytk.vectors.Point(*args, basis: Basis = None, reference_point: Point = None)[source]

Bases: object

Two-dimensional point with basis and optional reference point for coordinate transforms.

property x

Return the x (first) coordinate.

property y

Return the y (second) coordinate.

property c0

Return the first component of the point.

property c1

Return the second component of the point.

is_same_as(rhs)[source]

Return True if this point is equal to rhs.

standard_tuple()[source]

Return the components as a tuple in the standard basis.

standard_coordinates()[source]

Return an equivalent point expressed in the standard basis.

in_reference_frame(basis, new_reference_point)[source]

Express this point in a new reference frame defined by basis and origin.

class mytk.vectors.Basis(e0: Vector = None, e1: Vector = None)[source]

Bases: object

Orthogonal 2D basis defined by two vectors, defaulting to the standard basis.

property e0

Return the first basis vector.

property e1

Return the second basis vector.

property is_standard_basis

Return True if this is the standard Cartesian basis.

property is_orthogonal

Return True if the two basis vectors are perpendicular.

property is_orthonormal

Return True if the basis is orthogonal and both vectors are unitary.

class mytk.vectors.DynamicBasis(source, basis_name)[source]

Bases: Basis

Basis that reads its vectors dynamically from an attribute on a source object.

property e0

Return the first basis vector resolved from the source at access time.

property e1

Return the second basis vector resolved from the source at access time.

class mytk.vectors.Doublet(*args)[source]

Bases: tuple

Immutable two-element tuple with arithmetic operations for 2D math.

property x

Return the first element.

property y

Return the second element.

property length

Return the Euclidean length.

dot(rhs)[source]

Compute the dot product with another two-element sequence.

normalized()[source]

Return a unit-length doublet in the same direction.

scaled(scale)[source]

Return a new doublet with each element multiplied by the corresponding scale factor.

class mytk.vectors.ReferenceFrame(basis=None, scale=None, reference_point: Point = None)[source]

Bases: object

Coordinate reference frame defined by a basis, scale, and origin point.

property scale

Return the scale factors as a tuple of basis vector lengths.

convert_to_local(point: Point)[source]

Convert a point from standard coordinates to local frame coordinates.

convert_to_canvas(local_point)[source]

Convert a local-frame point to canvas (standard) coordinates.

scale_to_canvas(size)[source]

Scale a size tuple from local units to canvas units.

scale_to_local(size)[source]

Scale a size tuple from canvas units to local units.

property unit_vectors_scaled

Return the unit vectors multiplied by their respective scale factors.

property unit_vectors

Return the unit vectors of the frame.

class mytk.vectors.TestCase(methodName='runTest')[source]

Bases: TestCase

Unit tests for Vector, Point, and Basis coordinate operations.

test_point()[source]

Test basic point creation and standard coordinate conversion.

test_point_reference_frame_same_origin()[source]

Test reference frame conversions with the origin at (0, 0).

test_point_reference_frame_new_origin()[source]

Test reference frame conversions with a shifted origin.

test_point_reference_frame_new_origin_not_standard_coordinates()[source]

Test reference frame with a non-standard-basis origin point.

test_define_default_basis()[source]

Test that PointDefault context manager sets a default basis.

test_define_default_reference()[source]

Test that PointDefault context manager sets a default reference point.

test_define_default()[source]

Test PointDefault with both basis and reference point.

test_get_line_in_canvas_coordinates()[source]

Test converting a sequence of local-basis points to standard coordinates.

test_point_subtraction()[source]

Test that subtracting two points produces a Vector.

test_vector()[source]

Test basic vector dot product computation.

test_basis()[source]

Test point subtraction within a non-standard basis.

test_basis_change()[source]

Test changing a vector from one basis to another.

test_basis_change2()[source]

Test changing basis with a scaled (non-unitary) basis.

Utilities

mytk.utils.is_main_thread() bool[source]

Check whether the current thread is the main thread.

mytk.utils.parse_geometry(geometry)[source]

Parse a Tkinter geometry string into its size and offset components.

Parameters:

geometry (str | None) – A geometry string such as “800x600”, “+100+200”, “800x600+100+200”, or None.

Returns:

(size_str, offset_str) where either element may be None.

Return type:

tuple

Examples

“800x600+100+200” -> (“800x600”, “+100+200”) “800x600” -> (“800x600”, None) “+100+200” -> (None, “+100+200”) None -> (None, None)

mytk.utils.apply_window_position(widget, position, size_str=None)[source]

Set only the +X+Y offset of a Tk or Toplevel window.

The window size is never modified. When size_str is provided the offset is computed and applied immediately; otherwise the call is deferred to the first idle tick (after the event loop has laid out all content) and the window is briefly withdrawn to avoid a visible jump.

Parameters:
  • widget – A tk.Tk or tk.Toplevel instance.

  • position (str) – One of “center”, “top-left”, “top-right”, “bottom-left”, “bottom-right”.

  • size_str (str | None) – The “WxH” portion of a geometry string (e.g. “800x600”). When None the size is measured from the widget after layout.

Raises:

ValueError – If position is not a recognised name.

mytk.utils.package_app_script(filepath=None)[source]

Bundle the utility module and an optional script into a single self-contained string.