Open 004e7dd2-69eb-4f02-9b35-5bed19281be7 opened 3 years ago
Attempting to use a ttk.Frame with wm_manage() causes a TclError:
_tkinter.TclError: window ".!frame" is not manageable: must be a frame, labelframe or toplevel
The (Tcl) documentation for wm manage states "Only frame, labelframe and toplevel widgets can be used with this command." One might reasonably expect a ttk.Frame to appropriately fall under this requirement, especially since the name 'frame' is used for them, but it does not. One must use a tk.Frame instead to make this work.
At the very least, this needs to be documented. Looking at the error message and seeing it complain that a 'frame' is not one of 'frame', 'labelframe' or 'toplevel' is extremely confusing. There is nothing to lead to the conclusion that a ttk Frame is not a 'frame'. Better than documenting it, of course, would be to make wm_manage actually work properly with a ttk.Frame, as developers would expect.
You are confusing the widget path component, an arbitrary string of chars other than the separator '.', with the English word 'frame', which is also a tk command. In tk docs, 'a *frame*' is a widget (tk window) created with the 'frame' command.
By default, tk gives each widget(window) a unique but meaningless string of digits as its path component. A user can override this by giving an explicit name option on creation.
A few years ago, tkinter started always overriding the tk default with a readable name. Serhiy and I agreed on using a '!' prefix since it was unlikely though not impossible to be used by tkinter users. We must have agreed on not specifically flagging ttk widgets in the path component, as opposed to the widget name (see below). A numerical suffix is added to duplicates. The system is not perfect, but overall we prefer it to the tk digit sequences, in spite of the following possible confusion.
>>> c = ttk.Combobox(r, name='!frame')
>>> c
<tkinter.ttk.Combobox object .!frame>
>>> c.widgetName
'ttk::combobox'
>>> c.master.wm_manage(c)
...
_tkinter.TclError: window ".!frame" is not manageable: must be a frame, labelframe or toplevel
For debugging in 'python -i' or IDLE 'run module' mode, one can followup by checking the passed-in widget's widgetName if it is not otherwise obvious.
If you want tk or its tk wm_manage doc at https://www.tcl.tk/man/tcl8.6/TkCmd/wm.htm#M53 changed, you have to ask the tcl.tk people. Extremely unlikely I suspect. I presume that there are technical reasons why a ttk Frame is not a drop-in replacement for a tk Frame in this context. And since a *ttk::frame is clearly different from a *frame, the doc is clear enough. For all other commands, the window can only be a *toplevel*, so the exception for wm manage is an extension to frame and labelframe, rather than a restriction.
Our 3-paragraph doc for the corresponding Wm class does not discuss the individual methods but implicitly defers to the tkinter.__init__ code and the tk doc.
Our ttk doc does not discuss the ttk widgets that are essentially copies of tk widgets except the mostly documented differences. So there is not a good place to say anything and I am dubious that we should.
So I think we should close as 'not a bug' unless Serhiy disagrees.
I think you are confusing the perspective of the implementor with that of the typical developer _using_ the toolkit without reading through its source code.
In my tkinter applications, I pretty much always use ttk widgets where they are available. This is largely because of the consistent background colour (on a Mac, at least). In the case of Frame specifically, a regular Frame has a white background that doesn't go well with ttk widgets, while a ttk.Frame has a grey background. So naturally, when I started trying to implement a pop-out window, I was using ttk.Frame everywhere.
Then, when I started getting the error cited above, telling me that ".!frame" was not a frame, I was more than a little perplexed. Because in my view, I *had* a frame. I don't really care what the widget's unique name is, contrary to your suggestion that I'm confused by it. If I had given my ttk.Frame the name "garply", and the error was '".garply" is not manageable: must be a frame, labelframe or toplevel', I would have looked back at my code, and seen that, yep, garply was indeed a ttk.Frame, so what's the problem?
It took me a long time to figure out that only a tkinter Frame, and not a ttk Frame, will work with wm_manage() (disregarding labelframe and toplevel in this context). Because as a regular developer using the library, it simply wasn't at all clear that using a ttk.Frame is fundamentally different under the covers, and isn't actually considered to be a frame for the purposes of wm_manage(). Who'd have thought? Seriously. Regular developers naturally assume that ttk components are a kind of specialised version of their non-ttk counterparts, albeit with different options and style support, rather than a parallel world. You noted that "Our ttk doc does not discuss the ttk widgets that are essentially copies of tk widgets except the mostly documented differences". I think it *would* be worthwhile to say something about the fact that these are parallel components, and not derivatives, because, as this issue clearly illustrates, it can be important to understand this.
I even read through the tkinter and ttk source code to try to understand what was going on. The doc string for wm_manage() would have been a good place to say something, but there's nothing. I do understand that that is outside of ttk per se, but still, the two are not so separate that a comment couldn't help explain the constraint, and it really is important to the use of this method to understand that a ttk Frame is not a Frame.
It's unfortunate that the readable names used in the path aren't different for tkinter and ttk widgets, especially given how different they are. That would have helped. I realise, though, that changing it now is likely not a viable option.
In the end it was a hunch, perhaps born out of desperation and a lack of anything else to try, that led me to discover that a ttk Frame is not a Frame. I wasted a lot of time on this. I filed this issue in the hope that some documentation might be added so that others like myself don't also have to waste their time.
As an IDLE maintainer, I am a tkinter user also and that is my involvement in tkinter changes. One of my projects for IDLE has been to switch to ttk widgets, including ttk.Frame, wherever possible, for the reasons you gave.
It is known the tkinter docs we control are quite inadequate, and dependent on outside docs that we do not control. That is why the tkinter doc starts with 7 references for tkinter and 5 for tcl/tk. I am sorry that you fell into one of the gaps. But no one has yet volunteered to rewrite the tkinter/ttk docs to be complete, correct, and not dependent on outside resources. Until then, I do not see a good place to put the note you request. What would you say, and more important, where?
wm_manage is an anomaly for at least two reasons. The tk docs define the wm call sequences as "'wm' \<subcommand> atoplevel \<maybe subcommand args>". This translates to tkinters calls "atoplevel.wm_subcommand(subcommand_args)", where 'atoplevel' is the self arg for the call. The tk doc contradicts itself by saying that for wm_manage, atoplevel can instead be a *frame or *labelframe (** indicates italics in the tk docs). For tkinter, this translate to aframe.wm_manage(), but this is impossible since Frames do not subclass the Wm class, nor are they given this one method. It also turns out that atoplevel.wm_manage() does not work either.
Instead, one must call atoplevel.wm_manage(toplevel_frame_or_labelframe). This would roughly be equivalent, in tk, to "'wm' 'manage' atoplevel toplevel_frame_or_labelframe".
Another anomaly is that wm_manage is not really needed, at least not for frames. On can create a toplevel and pack a frame of any type that fills the toplevel. (Yes, a bit more work.)
Minor correction: Tk does not generate names as digit sequences. Its syntax requires a name to be always specified. Past versions of Tkinter generated names as digit sequences, now it generates more readable and informative names.
If we ever add documentation for wm_manage it would be nice to mention explicitly that it does not work with corresponding ttk widgets.
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields: ```python assignee = None closed_at = None created_at =
labels = ['type-feature', 'expert-tkinter', 'docs']
title = 'wm_manage fails with ttk.Frame'
updated_at =
user = 'https://bugs.python.org/mfncooper'
```
bugs.python.org fields:
```python
activity =
actor = 'serhiy.storchaka'
assignee = 'docs@python'
closed = False
closed_date = None
closer = None
components = ['Documentation', 'Tkinter']
creation =
creator = 'mfncooper'
dependencies = []
files = []
hgrepos = []
issue_num = 43411
keywords = []
message_count = 5.0
messages = ['388161', '388558', '388577', '388596', '388622']
nosy_count = 4.0
nosy_names = ['terry.reedy', 'docs@python', 'serhiy.storchaka', 'mfncooper']
pr_nums = []
priority = 'low'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue43411'
versions = []
```