Skip to content

Scripts Panel

Lasha Kandelaki edited this page May 19, 2026 · 2 revisions

Scripts Panel

One floating panel listing every .py file in the active page. Open a window's behavior file, or add a shared library module (helpers.py, api.py, sub-packages) that any behavior file in the same page can import.

Opening

How Notes
F6 Keyboard shortcut
View → Scripts Menu toggle
Scripts button on the workspace strip Sits to the left of Data at the top of the canvas

The panel is scoped to the active page. Switching pages refreshes the list. Pages do not share scripts — each page exports as an independent .py, so a project-wide layer would break the per-page export.

What's in the list

Kind Visual Origin Actions
Behavior file Orange color + (window) suffix Auto-created when you add a window Open in editor only — rename / delete go through the window chrome
Library script Default color You add it from the panel toolbar Open in editor, Rename, Delete, Drag into folders
Sub-folder Light blue Created from this panel (or the Assets Panel) Drag files into it, drag the folder itself between parents

The panel has two columns:

Column What it shows
Name (tree) The file / folder structure
Attached to For library scripts: the comma-separated list of windows that have this module attached (see Attached column below). For behavior files: the window name. Empty for folders and un-attached library scripts.

Toolbar

Element Action
+ Add script Prompt for a name (helpers.py, services/auth.py, …). Creates the file plus any missing parent folders + __init__.py chain.
+ Add folder Prompt for a folder name. Creates the sub-folder with an empty __init__.py so library imports resolve.

The panel auto-refreshes whenever it regains focus, so files you create, rename, or delete in an external editor (VS Code, Notepad++, file explorer, …) appear as soon as you click back into CTkMaker. No manual refresh button. It also auto-refreshes on attach / detach via the document_attached_scripts_changed event so the Attached column stays in sync.

Right-click on a row

Row Menu
Library script Open in editor • Rename… • Delete
Behavior file Open in editor only
Sub-folder Rename… • Delete (drops to recycle bin, including contents)

Double-click or Enter — opens in your configured editor (Settings → Editor). Same chain as Event Handlers uses: VS Code → Notepad++ → IDLE fallback.

Delete sends the file to the OS recycle bin (Send2Trash) — recoverable.

Attached column

A library script becomes attached to a window when you mark it as available to that window's Event Handlers. Only attached modules show up in the event target picker's Library category, and only attached modules export with a matching from . import <module> line.

Two ways to attach / detach:

How Where
Click the Attached cell on a library row Opens a window picker — toggle each window on or off, multiple allowed.
Drag a script onto a window row (when shown via the Window's Properties panel Attached Scripts group) Attaches that one script to that one window.

A library script with zero attachments is still importable by hand-edited code, but the event picker won't list it. Behavior files have no Attached cell — they're always paired with their single window.

Drag and drop

Library scripts and sub-folders are draggable inside the tree:

  • Script → folder — moves the file into that folder. Path-as-identity rule applies: every event binding that pointed at the script's old path is invalidated and needs re-picking. The Attached column also clears, because the old rel_path reference no longer matches.
  • Folder → folder — moves the whole sub-package. Same path-as-identity caveat for every script inside it.
  • Drag onto empty area or root — moves to the page-root.

A green highlight on the drop-target row confirms where the release will land. Drag is opt-in past a 5-pixel threshold so accidental clicks don't trigger moves.

Behavior files are not draggable — they're locked to the per-window slug. Rename the window if you need to rename the file.

Library scripts

A library script is any .py file in the page's scripts folder whose name does NOT match a window's behavior file slug. Use them for shared helpers across the windows on a single page.

Folder layout

<project>/assets/scripts/<page>/
├── <window>.py        Behavior file — auto-managed
├── helpers.py         Library script — manual
├── api.py             Library script — manual
└── services/
    ├── __init__.py
    └── auth.py        Library script in a sub-package

Import pattern

From any behavior file in the same page:

from . import helpers
from .services import auth

class LoginPage:
    def on_submit(self):
        if helpers.validate_email(self.email_entry.get()):
            auth.sign_in(...)

Survives export — when you export the page, the whole assets/scripts/<page>/ folder is copied next to the output .py, so the same relative import resolves at runtime.

Why page-scoped?

Variables follow the same rule: Global = page-scope, not project-scope. Each page exports independently, so cross-page sharing would force every page to carry the same code at runtime. If two pages need the same helper today, copy it into each page.

Tips

  • Naming a library file the same as a window slug (login.py when a window is named Login) is rejected — it would shadow the behavior file.
  • The + Add script prompt accepts paths (services/auth.py) — sub-folders are created automatically with empty __init__.py files so the import resolves.
  • A library script is a normal .py — no decorator, no registration, no contract. Just functions, classes, constants. Behavior files import them like any other Python module.

See alsoEvent Handlers · Assets Panel · Exporting Code · Variables · Settings

Clone this wiki locally