I have a program with some Label() widgets, some Button() widgets, some Text() widgets, and a few Entry() widgets. A couple of revisions ago, I didn't have the labels, and I had less Entry() widgets, and I mixed .pack() and .grid() as was convenient and I was fine. I had to do some refactoring, and added the extra widgets in the process - all the new things added used .grid(). Nothing about the other widgets changed. Now, I get an error along the lines of "unable to use grid in .", etc. (I can post the full error message if necessary). Why, and how can I fix this? (I can post code if necessary as well.)
You can't mix grid and pack with widgets that share the same parent.
Why? Because grid will try to lay widgets out, possibly growing or shrinking widgets according to various options. Next, pack will try to do the same according to its rules. This may require that it change widget widths or heights.
grid will see that widgets have changed size so it will try to rearrange the widgets accirding to its rules. pack will then notice that some widgets have changed size so it will rearrange the widgets according to its rules. grid will see that widgets have changed size so it will try to rearrange the widgets according to their rules. pack will then notice that some widgets have changed size so it will rearrange the widgets according to its rules. grid will see that ...
Related
I want to make elements in row in one layout and a lot of layouts will be in GroupBox, it must be like this.
Result Interface
I try to release this
formLayout = QFormLayout()
for i in range(50):
formLayout.addRow(QLabel(i), QPushButton("Start"))
groupBox.setLayout(formLayout)
self.scrollArea.setWidget(groupBox)
self.scrollArea.setWidgetResizable(True)
Result from code
I know that i should make in grib layout, because i have a lot of elements, but how can I create a layout with layouts which everyone have 9 elements?
Just explain how it should be grouped , like this scrollArea->groupBox->formLayout.addrow(elements)
I don't need full code, him I can write myself.
The layout you're showing is not a form layout, it could be a grid layout, but it actually seems more like a QTableView (or QTableWidget) or even a QTreeView (if those small arrows on the left are used to expand elements). Using nested layouts in this case might not be a good solution, as each layout would be independent from the others, with the result that the widgets might not be properly aligned. This small arrows for expand element in that case a QTreeView with a QStandardItemModel or a QTreeWidget might help, then use setItemWidget() to add buttons. –
musicamante
I know you can't use pack and grid together, but why? Why does it raise an error?
_tkinter.TclError: cannot use geometry manager pack inside . which already has slaves managed by grid
The reason is that each one wants to control the geometry of all widgets inside a given container (Frame, Toplevel, etc), and each one will reapply its rules when it detects that a widget it is controlling changes size.
For example, if you start by using pack, pack will add widgets to the window according to its own algorithm. Depending on the size and orientation of the widgets, this may cause the window to grow or shrink and may cause other widgets with the same master to grow or shrink.
Now, if you add a widget using grid, it's going to do the same thing -- it will add widgets using its own algorithm. Like pack, this might cause the window to grow or shrink, or the widget to change size.
Next, because pack is managing some widgets, when it detects that the window has changed size, it will reapply its own algorithm, possibly changing the size or position of some widgets.
Next, because some of the widgets are managed by grid it will detect that they have changed size and it will try to reapply its algorithm. This might cause the window to grow or shrink, or change the size of some widgets.
Next, because some of the widgets are managed by pack it will detect that they have changed size so it will try to reapply its algorithm. This might cause the window to grow or shrink, or change the size of some widgets.
Next, because some of the widgets are managed by grid it will detect that they have changed size so it will try to reapply its algorithm. This might cause the window to grow or shrink, or change the size of some widgets.
Next, because some of the widgets are managed by pack it will detect that they have changed size so it will try to reapply its algorithm. This might cause the window to grow or shrink, or change the size of some widgets.
... and so on until the end of time, or until something causes this cycle to end.
It actually is possible to use both for widgets that share a common parent if you are very careful and know exactly what will happen, but I've never come across a valid reason to do so.
You also absolutely can (and should) use both pack and grid in an application as a whole. Both have strengths and weaknesses. For example, you might use pack to add a full width toolbar, a full width statusbar, and middle section for the rest of the app. If the rest of the app is a form, it might make sense to use grid for the widgets inside the middle section of the GUI.
I want to eliminate strange extra space that seems to resist any size tweaking in my layout when using grid() alone, but calling in pack() sometimes make things worse: The GUI simply disappear entirely!
I read a few eye-opening layout answers from #Bryan Oakley such as:
When to use pack or grid layouts in tkinter?
and
Tkinter: grid or pack inside a grid?
but when I get down to write my own stuff, I still often have troubles.
My understanding:
I must have a Frame to fill the root window, otherwise there'd be no hope to fill the extra space in the window, however I tweak widgets alone.
For all the child widgets sitting inside a common parent Frame, I must use either pack() or grid() but not both.
When using grid() in a Frame, it's mandatory to specify Frame.grid_rowconfigure() and .grid_columnconfigure() with non-zero weight arguments. Otherwise, nothing would show up.
It's thus possible to have the main Frame using pack(), but its immediate child Frames all using grid(); Inside each of these child Frames on the grid, we could then pack() their own child widgets. In other words, we could interleave grid() and pack() by "regions" or container hierarchy levels, but never mix them in the same container: The only restriction.
By a careful weight design, I could fill a horizontal space in a parent Frame with a child Frame full of widgets laid out horizontally, e.g., all widgets use grid(sticky='nsew'), and the child Frame uses pack(side='top', fill='both', expand=True).
If my understanding was correct, then I could never figure out why #5 couldn't work for me, e.g., there is always unused extra space towards the right end of my horizontal child Frame inside the main Frame of the root window.
UPDATE 2
I figured it out. #5 didn't work for me because I forgot to specify .grid_columnconfigure(0, weight=1) in the main Frame before using grid(). My bad! Case closed.
UPDATE
I'm on macOS High Sierra, running python 3.6.4 Homebrew.
In what cases Tkinter's grid() cannot be mixed with pack()?
In all cases, you cannot use both grid and pack for widgets that have a common master. Within a master, all direct children must use the same geometry manager. Within an application as a whole, you can mix pack and grid all you want as long as you follow that one rule that you can't use them both for widgets that have the same parent.
I must have a Frame to fill the root window, otherwise there'd be no hope to fill the extra space in the window, however I tweak widgets alone.
This is not correct. You can easily fill all of the space in the root window without using a frame.
For all the child widgets sitting inside a common parent Frame, I must use either pack() or grid() but not both.
That is correct. The third option is to use place, though it's rarely the best choice.
When using grid() in a Frame, it's mandatory to specify Frame.grid_rowconfigure() and .grid_columnconfigure() with non-zero weight arguments. Otherwise, nothing would show up.
That is not true -- configuring rows and columns to have a non-zero weight isn't mandatory. It's usually a best practice, but it's not required in order for widgets to show up. The weight only applies to how grid manages extra space. Any widgets with a non-zero size should appear whether you use weights or not.
It's thus possible to have the main Frame using pack(), but its immediate child Frames all using grid()
Correct.
By a careful weight design, I could fill a horizontal space in a parent Frame with a child Frame full of widgets laid out horizontally, e.g., all widgets use grid(sticky='nsew'), and the child Frame uses pack(side='top', fill='both', expand=True).
That is correct.
I am writing a program which has a TreeCtrl on the left and a RichTextCtrl on the right.
Following is the code of the splitter, panel and other elements.
The problem is that in windows, the bottom of the treectrl and textctrl is hidden. The statusbar covers the bottom of the splitter. But even after removing the statusbar I cannot see the bottom of the treectrl (hides up to 6 rows).
self.panel=wx.Panel(self,wx.ID_ANY)
self.splitter=wx.SplitterWindow(
self.panel,-1,size=wx.DisplaySize(),style=wx.SP_LIVE_UPDATE)
self.splitter.SetMinimumPaneSize(5)
self.datatree=wx.TreeCtrl(self.splitter,1,style=wx.TR_HIDE_ROOT|wx.TR_ROW_LINES)
self.display=wx.richtext.RichTextCtrl(
self.splitter,1,style=wx.VSCROLL|wx.HSCROLL|wx.WANTS_CHARS)
self.display.SetFont(self.displayfont)
self.handler=wx.richtext.RichTextXMLHandler()
self.splitter.SplitVertically(self.datatree,self.display)
self.logger=self.CreateStatusBar()
I think the issue here may be that you've explicitly told the SplitterWindow to take up the entire display size. Try omitting the size argument to the constructor, or adjust it down some, to see if that has any effect.
If omitting the size parameter does not help, I'd suggest creating Panels with Sizers that contain your Tree and your Rich Text Control, then splitting those Panels vertically within the Splitter Window.
What's the main difference between the Tkinter geometry managers grid and pack?
What do you use for your projects ?
If grid is better to align object, what the main purpose of pack?
grid is used to lay out widgets in a grid. Another answer says it "overlays a graph" which is a bit of a misnomer. It doesn't overlay anything, it merely arranges widgets along row and column boundaries. It is great for creating tables and other structured types of layouts.
pack lays things out along the sides of a box. It excels at doing layouts where everything is on a single row or in a single column (think rows of buttons in a toolbar or dialog box). It's also useful for very simple layouts such as a navigator on the left and a main work area on the right. It can be used to create very complex layouts but it gets tricky until you fully understand the packing algorithm.
You cannot use both grid and pack with widgets that have a common parent. Your app may work but it is much more likely to get into an infinite loop as each manager tries to layout the widgets, then the other notices the widgets change size and try to adjust, etc. etc.
The third manage is place. Place is great for doing either absolute positioning (ie: place widget at a given x/y) or relative (eg: place a widget on the right edge of some other widget).
While you cannot mix grid and pack within the same container (a container is typically a frame), you can use both grid and pack within a single application. This is very, very common since each has strengths and weaknesses. I use both on a regular basis.