Skip to content

gh-75733: Show IDLE's trees in a ttk.Treeview - #157029

Open
serhiy-storchaka wants to merge 1 commit into
python:mainfrom
serhiy-storchaka:idle-treeview
Open

gh-75733: Show IDLE's trees in a ttk.Treeview#157029
serhiy-storchaka wants to merge 1 commit into
python:mainfrom
serhiy-storchaka:idle-treeview

Conversation

@serhiy-storchaka

Copy link
Copy Markdown
Member

idlelib.tree drew every row on a canvas: hardcoded pixel sizes that fit neither every font nor every monitor, an icon on every row whether it helped or not, and its own bindings for clicks and scrolling. This replaces the drawing with a ttk.Treeview, which takes its row height from the configured font and its indicators, colours and keys from ttk and the theme. That is the fix for the HiDPI clipping in this issue, and it removes the two blockers you listed: rows no longer need an icon, and a click no longer has to be handled by the tree itself.

The module keeps its name — idlelib/tree.py is now ScrolledTreeview (a ttk.Treeview with scrollbars, coloured from the configuration) and TreeWidget (a tree of TreeItems on top of it, asking an item for its children only when its row is opened). test_tree.py holds the tests for it.

Converted, in one commit because they share the widget: the Module and Path browsers, Debug ▸ Stack Viewer, the object browser, the remote stack viewer the Shell opens for a subprocess exception, and the stack, Locals and Globals panes of the Debug Control window. The stack pane was a ScrolledList listbox with its own scrollbar, popup menu and key bindings, all of which ttk provides.

The item protocol gains two methods and loses two:

  • GetValues() fills the columns after the tree column, so the stack views show a frame as module, function, line and source rather than one glued string, and the Locals/Globals panes are name/value tables.
  • GetTags() says what kind of row an item is, and the tree that shows it decides what a kind looks like. The Path Browser uses it to mark directories, packages and modules with the icons already in Icons/ (so a package row no longer needs ": package"); the Module Browser marks nothing.
  • GetIconName() and GetSelectedIconName() go: the canvas drew an image on every row and these chose which, while a Treeview draws none unless asked. plusnode.gif and minusnode.gif go with them, as ttk draws the indicators itself.

Also closed by this, since they cannot be done separately once the drawing changes:

The debugger's stack pane marks the frame it stopped in with an arrow and a bold row instead of prefixing the text with "> ", so rows no longer shift by two characters and the marker survives selecting another row. The arrow is drawn in code rather than read from a file, so it follows the configured font size and the theme's foreground — a shipped bitmap would be black on IDLE Dark.

idlelib.tree drew its rows on a canvas, with hardcoded pixel sizes that
fit neither every font nor every monitor, an icon on every row, and
bindings of its own for clicks and scrolling.  It now wraps a
ttk.Treeview, which takes its row height from the configured font and
its indicators, colors and keys from ttk and the theme.

Converted: the Module and Path browsers, Debug => Stack Viewer, the
object browsers, and the stack, Locals and Globals panes of the Debug
Control window.  Rows carry more than a text now: an item fills the
columns of its row with GetValues, and says with GetTags what kind of
row it is, which is how the stack views show a frame as module,
function, line and source, and how the Path Browser tells a directory,
a package and a module apart.

The stack pane of the debugger marks the frame it stopped in with a
drawn arrow instead of a "> " in front of the text.  The Locals and
Globals panes are read-only tables, as editing them never reached the
objects in the user process (pythongh-69184).  The Module Browser shows no
icons, its text saying already whether a row is a class or a function
(pythongh-69277).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@serhiy-storchaka

Copy link
Copy Markdown
Member Author

Trying it by hand. Each module runs its unit tests and then opens its window:

./python -m idlelib.tree          # the widget itself, on the attributes of sys
./python -m idlelib.stackviewer   # Stack Viewer: exception, frames, namespaces
./python -m idlelib.pathbrowser   # Path Browser: the icons
./python -m idlelib.browser       # Module Browser
./python -m idlelib.debugobj      # object browser: Name | Value

./python -m idlelib.idle_test.htest walks all of them with instructions in the master window.

In a running IDLE (./python -m idlelib): File ▸ Module Browser (Alt-C) and File ▸ Path Browser; Debug ▸ Stack Viewer after an exception in the Shell. The Debug Control panes have no htest — the # TODO: htest? at the end of debugger.py — so for those use Debug ▸ Debugger, enter

def inner(n): return 1/n
def outer(n): return inner(n)
outer(0)

and press Step until you are inside inner.

Worth looking at:

  • Keyboard: Up/Down move, Left/Right collapse and expand, Return opens a file at its line — none of which the canvas tree did.
  • Stack Viewer: Name | Line | Value; a frame fills all three, an exception and a namespace only the first, a variable the first and last.
  • Debug Control: Module | Function | Line | Source; the frame the debugger stopped in is bold with an arrow, and stays marked when you select another row. Locals and Globals are read-only tables, at most 15 rows tall, and a long value scrolls in its column rather than stretching the pane.
  • Path Browser: closed folder for a directory, open folder for a package, Python icon for a module; expand a module and its def/class rows have no icon.
  • Fonts and themes: change them in Options ▸ Configure IDLE and reopen a window — row height, colours and the debugger's arrow follow. Windows already open do not restyle themselves; that was true before as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting core review needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant