Tkinter grid autosize help

Rick Johnson rantingrickjohnson at gmail.com
Sat Aug 2 22:24:27 EDT 2014


On Saturday, August 2, 2014 5:53:12 PM UTC-5, Nicholas Cannon wrote:
> So i have a basic calculator program and i
> have a label that i want to go across the top to show the
> numbers and stuff like on a normal calculator. The only
> way i can make the buttons look neat and then when i keep
> pressing one the label gets larger and then half the
> buttons move out of the screen. 

A Tkinter Label widget will "naturally" adjust its size to
accommodate the text it contains.

> I cant seem to fix this i have tried columnspan,
> columnconfigure and heaps of other stuff and non works it
> always expands. is there a way i can stop the grid from
> expanding?

The "grid is expanding" because the first row of the grid
(which contains a label that is being updated by user input)
is expanding, and as such, all subsequent rows will expand
to match the first row.

You should use an Entry instead of a Label because: 

  1. Entry will accommodate values that exceed their current
  size *WITHOUT* growing.
      
  2. Label widgets do not allow direct input from the user.
  Sure, in some cases you want to prevent the user from
  editing text via the keyboard but *NOT* in this case!  All
  calculator apps should allow the use a choice between
  mouse clicks or keyboard entry.
  
*HOWEVER*, if you do decide to implement the "numberView" as
an Entry widget, you will need to create a keypress filter
to prevent illegal input!
  

> ok here is the code:
> #window setup
> main = Tk()
> main.title('Calculator')
> main.geometry('300x350')
> main.resizable()
> app = Frame(main)
> app.grid()
> app.columnconfigure(0, weight=500)
> app.columnconfigure(1, weight=500)
> #number view label
> number = ' '
> numberView = Label(app, text= number)
> numberView.grid(row=0, column=0, columnspan=100)
> #Num Pad Buttons below
> num1 = '1'
> button1 = Button(app, text='1', command= lambda: add(num1), width=5)
> button1.grid(row=1, column=0)
> num2 = '2'
> button1 = Button(app, text='2', command= lambda: add(num2), width=5)
> button1.grid(row=1, column=1)
> num3 = '3'
> button1 = Button(app, text='3', command= lambda: add(num3), width=5)
> button1.grid(row=1, column=2)
> num4 = '4'
> button1 = Button(app, text='4', command= lambda: add(num4), width=5)
> button1.grid(row=2, column=0)
> num5 = '5'
> button1 = Button(app, text='5', command= lambda: add(num5), width=5)
> button1.grid(row=2, column=1)
> num6 = '6'
> button1 = Button(app, text='6', command= lambda: add(num6), width=5)
> button1.grid(row=2, column=2)
> num7 = '7'
> button1 = Button(app, text='7', command= lambda: add(num7), width=5)
> button1.grid(row=3, column=0)
> num8 = '8'
> button1 = Button(app, text='8', command= lambda: add(num8), width=5)
> button1.grid(row=3, column=1)
> num9 = '9'
> button1 = Button(app, text='9', command= lambda: add(num9), width=5)
> button1.grid(row=3, column=2)
> num0 = '0'
> button1 = Button(app, text='0', command= lambda: add(num0), width=5)
> button1.grid(row=4, column=1)
> main.mainloop()


A few points about your code:

  1. "add" is a horrendous name for a function that updates
  the numerical display, ESPECIALLY in an application that
  is used to add, subtract, blah-blah-blah!
  
  2. You should use a loop to layout the "grid of buttons",
  which could be accomplished in just a mere couple lines of
  code.
  
  3. Declaring the value of the lambda arguments seems
  superfluous to me.
  
Finally, there is always more to an interface than we
initially imagine. For instance, the width of the
"numberView" should fill the containing window to allow the
user "view flexibility", however, if the entry is allowed to
be dynamic and the "number grid" is not dynamic, then the
application is not going to feel very professional. Of
course, at this time, just getting something working is most
important. We can jazz it up later :)

Here is a slightly modified version of your code that may
help you get going in the correct direction. Note, i am
*NOT* going to write this code for you, i will offer *slight*
suggestions and comments where i believe improvements could
be made, but you are required to do the heavy lifting.

############################################################
# START CODE
############################################################
import Tkinter as tk 
from Tkconstants import E, W, END

def update_entry(arg):
    oldValue = entry.get()
    entry.delete(0, END)
    entry.insert(0, oldValue + arg)

def onKeyPress_entry(event):
    key = event.keysym.lower()
    print 'The user pressed {0}'.format(key)
    #
    # The following conditional showcases how to prevent
    # illegal input but utilizing a return value of "break"
    if key == 'w':
        print 'The char "w" is not allowed!'
        return "break"

app = tk.Tk()
app.title('Calculator')
app.geometry('300x350')

entry = tk.Entry(app)
entry.grid(row=0, column=0, sticky=E+W, columnspan=3)
entry.bind("<KeyPress>", onKeyPress_entry)

if True:
    # OPTION_1: Create buttons with repetitive code:
    w = tk.Button(app, text='1', command=lambda: update_entry('1'), width=5)
    w.grid(row=1, column=0)
    w = tk.Button(app, text='2', command=lambda: update_entry('2'), width=5)
    w.grid(row=1, column=1)
    w = tk.Button(app, text='3', command=lambda: update_entry('3'), width=5)
    w.grid(row=1, column=2)
    w = tk.Button(app, text='4', command=lambda: update_entry('4'), width=5)
    w.grid(row=2, column=0)
    w = tk.Button(app, text='5', command=lambda: update_entry('5'), width=5)
    w.grid(row=2, column=1)
    w = tk.Button(app, text='6', command=lambda: update_entry('6'), width=5)
    w.grid(row=2, column=2)
    w = tk.Button(app, text='7', command=lambda: update_entry('7'), width=5)
    w.grid(row=3, column=0)
    w = tk.Button(app, text='8', command=lambda: update_entry('8'), width=5)
    w.grid(row=3, column=1)
    w = tk.Button(app, text='9', command=lambda: update_entry('9'), width=5)
    w.grid(row=3, column=2)
else:
    # OPTION_2: Create Buttons by off-loading the work onto Python.
    number = 1
    for r in range(1, 4):
        for c in range(3):
            print r, c, number
            # Can you figure out what to do here?
            number += 1

w = tk.Button(app, text='0', command=lambda: update_entry('0'), width=5)
w.grid(row=4, column=1)

if __name__ == '__main__':
    app.mainloop() 
############################################################
# END CODE
############################################################




More information about the Python-list mailing list