1

I am currently learning python and have hit a roadblock. I started in java and enjoyed the use of JOptionPane for input dialogs, and using those dialogs to assign values to variables and parsing them from there.

In python I've noticed people use Tkinter for most basic gui set-ups, but I could not find a lot of information on how to use a text box created with tkinter to assign a value to a variable. My code is as follows:

import random
import tkinter as tk

def guess():
    global entry
    guess = entry.get()
    guessN = int(guess)


root1 = tk.Tk()

label = tk.Label(root1, text='What number am I thinking of between 1 and 100?')
entry = tk.Entry(root1)
entry.focus_set()

b = tk.Button(root1,text='okay',command=guess)
b.pack(side='bottom')

label.pack(side = tk.TOP)
entry.pack()

root1.mainloop():

x = random.randint(1,101)

guess()
tries = 0

while guessN != x:
    if (guessN < x):
        guess = input("Too low! Try again.")
        guessN = int(guess)
        tries += 1
    else:
        guess = input("Too high! Try again.")
        guessN = int(guess)        
        tries += 1

print('Congratulations you guessed the number', x, 'in', tries, 'tries!')
SystemExit

I want to use tkinter to assign the input to guess and then use guessN to check against the randomly generated number. I'm not really sure where to go from here, or how to continuously check, and re-assign the variable if the guess was not correct.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
Brendan H
  • 21
  • 1
  • 2

1 Answers1

3

Manually

As per The Tkinter Entry Widget:

First, you can just read the value from the Entry with

entry.get()

Second, you can bind it to a tkinter.Variable (it creates and wraps a Tcl global variable with an autogenerated name). Usually, its subclass StringVar is used -- it converts values to str when getting/setting.

v = tkinter.StringVar()
entry = tk.Entry(root1, textvariable=v)

<...>
value = v.get()

Not a big difference as you can see, only adds a level of indirection. Both methods will get you an str so you need to parse it with int(). But you can use an IntVar instead of Variable (or StringVar) that will parse it for you on .get() (and will raise ValueError if it's not a valid integer).

Automatically

To automagically update a Python variable when the Entry's value changes, use Variable.trace_add:

def callback(tcl_name,index,op):
    global myvar
    # See https://tcl.tk/man/tcl8.6/TclCmd/trace.htm#M14 about the arguments.
    # A callback is only passed the name of the underlying Tcl variable
    # so have to construct a new Variable of the same class on the fly 
    # that wraps it to get the value and convert it to the appropriate type.
    # Yes, it's this hacky.
    try: myvar = StringVar(tcl_name).get()
    except ValueError: myvar = None

v.trace_add("write",callback)

A less hacky solution for the callback would be to make the callback an instance method of the Variable -- this way, it will get a reference to it via self rather than having to construct a new class instance. The value could be made an instance attribute as well:

def callback(self,*args):
    try: self.value=self.get()
    except ValueError: self.value=None

v.callback=callback
v.trace_add("write",v.callback)

Note that this will be called on every change -- i.e. even as you type the value -- and thus may cause noticeable delays in GUI reaction. So unless you really need to constantly monitor the value, it's sufficient to just read it once at an appropriate moment.

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152