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:
BaseA modal dialog window with configurable buttons and content.
- 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.
- create_behavior_buttons()[source]¶
Create Ok and Cancel buttons based on the configured button labels.
ProgressBar¶
- class mytk.progressbar.ProgressBarNotification(*values)[source]¶
Bases:
EnumNotification types for controlling a ProgressBar via NotificationCenter.
- class mytk.progressbar.ProgressBar(maximum=100, mode='determinate')[source]¶
Bases:
BaseA determinate or indeterminate progress bar widget.
- property value¶
The current progress value.
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¶
ConfigurableNumericPropertyFor numbers (integers or floats). You can set a minimum, maximum, a display multiplier, and a format string for the dialog.
ConfigurableStringPropertyFor text values. You can restrict accepted values with a regular expression or a fixed set of allowed strings.
ConfigurablePropertyThe base class. Use this when the built-in types do not fit; you can supply any validation function you like via
validate_fct.
- class mytk.configurable.ConfigurableProperty(name=None, default_value=None, displayed_name=None, validate_fct=None, valid_set=None, value_type=None)[source]¶
Bases:
objectDescriptor that defines a single configurable parameter with validation.
Instances can be declared as class attributes on a
Configurablesubclass (descriptor-based approach) or collected into aConfigModelfor dynamic schema construction.
- class mytk.configurable.ConfigurableStringProperty(valid_regex=None, name=None, default_value=None, displayed_name=None, validate_fct=None, valid_set=None)[source]¶
Bases:
ConfigurablePropertyString-typed configurable property with optional regex validation.
- 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:
ConfigurablePropertyNumeric 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.
- class mytk.configurable.Configurable[source]¶
Bases:
objectMixin that turns declared ConfigurableProperty attributes into a managed configuration.
- 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 toConfigurationDialog(e.g. buttons_labels, auto_click, geometry).
- class mytk.configurable.ConfigModel(properties: list[ConfigurableProperty] = None, values: dict = None)[source]¶
Bases:
objectExplicit-list configuration model for dynamically built property schemas.
- property values¶
Return the current configuration values as a dict.
- class mytk.configurable.ConfigurationDialog(properties=None, values=None, populate_body_fct=None, *args, **kwargs)[source]¶
Bases:
Dialog,ConfigModelModal dialog that presents configurable properties as editable fields.
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:
objectA 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:
objectRecord describing an observer registration in the NotificationCenter.
- class mytk.notificationcenter.NotificationCenter(*args, **kwargs)[source]¶
Bases:
objectSingleton notification center for one-to-many observer communication.
All notification names must be Enum members. The center is thread-safe.
- 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.
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:
ProtocolProtocol 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:
objectMixin 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.
- 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.
DragAndDropCapable¶
Drag-and-drop mixin class for widget behavior.
Provides the DragAndDropCapable class, a mixin designed to add OS-level drag-and-drop (files dropped from the system file manager) to GUI widgets that expose a widget attribute compatible with tk.Widget. It mirrors EventCapable: a small mixin combined into Base, never used on its own.
OS drag-and-drop is not part of core Tk; the heavy lifting (loading the tkdnd extension onto the window and parsing the dropped payload) lives in mytk.dnd. This mixin is the per-widget API on top of it.
- class mytk.draganddropcapable.DragAndDropCapable(*args, **kwargs)[source]¶
Bases:
objectMixin adding drag-and-drop methods for classes exposing a widget.
Designed to be used alongside base classes that define self.widget as a tk.Widget (and, like the dropped-file callback here, alongside EventCapable for self.after). This class should not be used on its own.
Responsibilities: - Checking whether drag-and-drop can be enabled (is_drag_and_drop_available) - Registering a widget as a target for dropped files (accept_dropped_files)
- is_drag_and_drop_available()[source]¶
Whether OS drag-and-drop can be enabled on this widget’s window.
Loads the tkdnd extension on first call (pulling in the optional tkinterdnd2 dependency); returns False if it cannot be enabled.
- accept_dropped_files(callback)[source]¶
Accept files dropped onto this widget from the OS file manager.
callback(paths)is invoked on each drop with a list of filesystem paths. Every dropped file is delivered — it is up to the callback to try to use them and report anything it cannot handle. Call this after the widget exists (e.g. after grid_into / pack_into / place_into).Returns True if drag-and-drop is available in this environment, or False if it could not be enabled — in which case the widget keeps working, just without drops. Enabling it pulls in the optional
tkinterdnd2dependency on first use (seemytk.dnd).
Drag and Drop helpers¶
Drag-and-drop support for myTk — accept files dropped from the OS.
Tk has no native OS-level drag-and-drop. This wraps the tkdnd Tcl extension
(via the tkinterdnd2 package) and retrofits it onto myTk’s existing root
window, so any widget can opt in with Base.accept_dropped_files() without
the app having to create a special drag-aware root.
tkdnd ships as a compiled library built against a specific Tcl major version, so
the right tkinterdnd2 release is chosen from the running Tcl: the 0.4.x line
for Tcl 8.x, the latest for Tcl 9.x. If the extension still cannot be loaded
(for instance an incompatible build is already installed), drag-and-drop is
simply reported as unavailable and the calling code carries on without it.
- mytk.dnd.ensure_tkdnd(root, ask_for_confirmation=True)[source]¶
Load tkdnd onto
root, installing a compatible tkinterdnd2 if needed.Returns the imported
tkinterdnd2module when drag-and-drop is available on this root, orNoneif it could not be enabled (missing or incompatible extension). Importing the package also patches Tk’s widget classes with thedrop_target_register/dnd_bindmethods.
ModulesManager¶
- class mytk.modulesmanager.ModulesManager[source]¶
Bases:
objectUtility 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_imported(module_name)[source]¶
Check whether a module has already been imported into sys.modules.
Vectors¶
- mytk.vectors.is_standard_basis(basis)[source]¶
Return True if the basis is None or is the standard (identity) basis.
- class mytk.vectors.PointDefault(basis=None)[source]¶
Bases:
objectContext manager to temporarily override the default basis for Points.
- class mytk.vectors.Vector(*args, basis=None)[source]¶
Bases:
objectTwo-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.
- class mytk.vectors.Point(*args, basis: Basis = None, reference_point: Point = None)[source]¶
Bases:
objectTwo-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.
- class mytk.vectors.Basis(e0: Vector = None, e1: Vector = None)[source]¶
Bases:
objectOrthogonal 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:
BasisBasis 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:
tupleImmutable 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.
- class mytk.vectors.ReferenceFrame(basis=None, scale=None, reference_point: Point = None)[source]¶
Bases:
objectCoordinate 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.
- 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:
TestCaseUnit tests for Vector, Point, and Basis coordinate operations.
- 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_reference()[source]¶
Test that PointDefault context manager sets a default reference point.
Utilities¶
- 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:
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:
- Raises:
ValueError – If position is not a recognised name.