Skip to main content

FlowFrame

The reason I wrote this module/class:

I think that Python's defacto tkinter GUI program should at least have a geometry manager that offers flow behaviour. That is - when the size of the GUI changes, the widgets inside the gui can be responsive in a "flow" manner. Now tkinter windows are 'responsive' in that the size of the widgets can change and so forth, but my opinion is that a natural responsive design often incorporates 'flow'. Where as when the window changes, the contents will shift inside the window like a word-wrap. This is very common in html and the like (there is a flow type geometry manager in Java for example). Overall, responsiveness to the window size is very important as you just don't know what size screen your program will be viewed on now, or in the future.

Saying that, here is one solution to that problem. It is a 'FlowFrame' which is literally a tkinter 'Frame' i.e. it inherets from the 'Frame' class so this 'FlowFrame' can be used anywhere a 'Frame' can be used. It is identical in every way, except it has 2 methods in addition to its parent class the 'Frame'.

Note:

The flowframe will act as an ordinary frame unless addWidget(), organizeWidgetsWithGrid() or organizeWidgetsWithPlace() is called. You can use the keyword argument mode="place" or mode="grid" when making and instance of a FlowFrame. If none is specified, grid is used.

Here are 2 methods:

addWidget(yourWidget)                          #your widget might be a button, etc

and

destroyWidgets()
Update 8/2/2021

I added 3 more methods:

  • organizeWidgetsWithGrid()
  • organizeWidgetsWithPlace()
  • stopOrganizingWidgets()

Basically, you can use the FlowFrame as an ordinary frame, and then at any time make the children of the frame flow. Here is an example:

Example 1: Showing mode="grid" when FlowFrame instance is made and using addWidget():

from tkinter import *
from flowframe import *

def main():

    buttonArray=[]
    root = Tk()

    myframe=FlowFrame(root, mode="grid")
    #make sure frame expands to fill parent window
    myframe.pack(fill="both", expand=1) 

    buttonMakePlace=Button(myframe, text="---Use Place---",command=myframe.organizeWidgetsWithPlace)
    myframe.addWidget(buttonMakePlace)

    buttonMakeGrid=Button(myframe, text="---Use Grid---", command=myframe.organizeWidgetsWithGrid)
    myframe.addWidget(buttonMakeGrid)

    buttonDestroy=Button(myframe,text="---Destroy---", command = myframe.destroyWidgets)

    for i in range(10):
        buttonArray.append(Button(myframe,text=str(i)))

    root.mainloop()

main()

Example 2: Initially using as an ordinary frame, then call organizing functions:

from tkinter import *
from flowframe import *

def main():

    buttonArray=[]
    root = Tk()

    myframe=FlowFrame(root, mode="grid")
    #make sure frame expands to fill parent window
    myframe.pack(fill="both", expand=1) 

    buttonMakePlace=Button(myframe, text="---Use Place---",command=myframe.organizeWidgetsWithPlace)
    buttonMakePlace.pack()

    buttonMakeGrid=Button(myframe, text="---Use Grid---", command=myframe.organizeWidgetsWithGrid)
    buttonMakeGrid.pack()

    buttonDestroy=Button(myframe,text="---Destroy---", command = myframe.destroyWidgets)

    for i in range(10):
        buttonArray.append(Button(myframe,text=str(i)))

    root.mainloop()

main()

Example 3: Showing the .addWidget() with more widgets:

from tkinter import *
from flowframe import *

def main():

    root = Tk()

    myframe=FlowFrame(root)
    myframe.pack(fill="both", expand=True)          #IMPORTANT! make sure frame expands to fill parent window

    mybutton=Button(myframe, text="---Button---")
    myframe.addWidget(mybutton)

    mytextbox=Text(myframe,width=3,height=2)
    myframe.addWidget(mytextbox)

    mylabel=Label(myframe,text="----Label---")
    myframe.addWidget(mylabel, sticky="NSEW")

    root.mainloop()

main()

This frame should be easy to use if you are somewhat familiar with using tkinter in Python. Here are the key points:

  1. The FlowFrame is a frame. Use it anywhere you would use a Frame.
  2. In order for widgets to flow in this frame, the frame must stick to its parent. In other words, when you resize the frame's parent window, the frame must resize also, or else nothing will happen. (This can be achieved using the pack with fill=BOTH expand=True, or grid with sticky=NSEW conventions) Either way, this frame must stick to its parent container.
  3. Use the frames .addWidget to add the widget into the frame, or call an organizing function later, i.e. myFlowFrame.organizeWidgetsUsingPlace() i.e. myFlowFrame.addWidget(mybutton)
  4. The order widgets are added to the frame determines the order they appear in the frame, much like using the 'pack' geometery manager.
  5. Use the FlowFrames addWidgets method to add to the frame, rather than gridding to the frame. The FlowFrame uses the grid method in its addWidget method, but mixing and matching in an ad hoc fashion has not been really tested much, so just add to the frame with the frames method.
  6. Don't mix geometry managers - in other words, don't try to pack something into the frame, then try to use the frames's addWidget method. This will cause errors just like trying to mix pack, grid, and place geometry managers. Technically, the frame.addWidget() method uses the grid geometry manager, so you will not always get errors. But the bottom line is, you should simply add to the frame using its addWidgets method rather than trying to grid to the frame. This may lead to less than predictable results.
  7. The method is FlowFrame.destroyWidgets() which destroys the objects and removes them from the frame. This is like a reset. It may not be the most intricate or nuanced method, but in practice, this simple method adds substantial functionality to the package as a whole. If I get requests for a more nuanced approach, I may revisit the module, but at this time, the package remains quite usable as is.

Example 4: Showing the .addWidget() and .destroyWidgets() methods:

from tkinter import *
from flowframe import *

def _destroyWidgets():
    myframe.destroyWidgets()

def main():

    root = Tk()

    global myframe
    myframe=FlowFrame(root)
    myframe.pack(fill="both", expand=True)     #make sure frame expands to fill parent window

    button=Button(myframe, text="---Button---")
    myframe.addWidget(button, sticky=NSEW)

    textbox=Text(myframe,width=3,height=2)
    myframe.addWidget(textbox)

    label=Label(myframe,text="Label")
    myframe.addWidget(label,sticky=NSEW)

    entry=Entry(myframe)
    myframe.addWidget(entry, sticky=NSEW)

    radioButton=Radiobutton(myframe,text="radio button")
    myframe.addWidget(radioButton)

    checkButton=Checkbutton(myframe,text="CheckButton")
    myframe.addWidget(checkButton)

    scale_widget = Scale(myframe, from_=0, to=100, orient=HORIZONTAL)
    myframe.addWidget(scale_widget)

    button2=Button(myframe, text="----Remove All---", command=_destroyWidgets)
    myframe.addWidget(button2)

    root.mainloop()

main()

Summary:

  • Object: FlowFrame
  • Inherets from: Frame
Methods:
      addWidget(widget)
      destroyWidgets()
      organizeWidgetsUsingGrid()
      organizeWidgetsUsingPlace()
      stopOrganizingWidgets()


Release files for flowframe 0.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for flowframe 0.0.1
File Size Uploaded
flowframe-0.0.1.tar.gz 6.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for flowframe 0.0.1
File Interpreter ABI Platform
flowframe-0.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 12.5 kB

Release files / flowframe-0.0.1.tar.gz

Download URL flowframe-0.0.1.tar.gz
Size 6.2 kB
Tags Source
SHA-256 checksum
How to use checksums
25be9ea8a390966e374a64477e750f7895796057baf90c3f3156eb3a64a065ee
BLAKE2b-256 checksum
How to use checksums
4e2f8685b62fe1b7e2fb3082d2128f012b87bdf26c25fb338f7f87b56d4b5b2a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.8.10

Release files / flowframe-0.0.1-py3-none-any.whl

Download URL flowframe-0.0.1-py3-none-any.whl
Size 6.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e0f83d6e46fcf46c145d84c8c17d4e456435619309395cde02a15e797a8e0fe0
BLAKE2b-256 checksum
How to use checksums
f1e56087ce105cc26bb639a0952485618134361bf6b8f40f47624b1300646904
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/3.4.1 importlib_metadata/4.6.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.8.10

Release history Release notifications | RSS feed

This release

0.0.1 This release

2 release files

0.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page