3

I am trying to create a window with a line label, an entry field, a current value label, and an "Update Value" button.

Here is an example:

enter image description here

This is what I have so far. I can get the entered value to print to console, but I can't seem to work out how to get an entered value and change the currentValue Label to reflect that value by pressing the button:

from tkinter import*
main=Tk()

#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")

#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
        content = entry.get()
        print(content)


#This kills the program
def exitProgram():
        exit()

#Title and window size
main.title("Title")
main.geometry("350x200")

#Descriptions on the far left
Label(main, text="Duration (min): ").grid(row=0, column=0)

#Entry boxes for values amidship
entry=Entry(main, width=10)
entry.grid(row=0, column=1)

#Displays what the value is currently set to.
currentValue = Label(textvariable=currentValue)
currentValue.grid(row=0,column=2)

#Takes any inputted values and sets them in the "Current" column using def setValues
setValues=Button(text='Set Values',width=30,command=setValues)
setValues.grid(row=9, column=0, columnspan=2)

#Red button to end program
exitButton=Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()
Ethan Field
  • 4,646
  • 3
  • 22
  • 43
Agent
  • 123
  • 2
  • 9

3 Answers3

4

There are a couple of problems with your code.

Firstly, you are overwriting the setValues function with the setValues Button widget, and similarly, you are overwriting the currentValue StringVar with the currentValue Label.

To set a StringVar, you use its .set method.

Don't use plain exit in a script, that's only meant to be used in an interactive interpreter session, the proper exit function is sys.exit. However, in a Tkinter program you can just call the .destroy method of the root window.

Here's a repaired version of your code.

import tkinter as tk
main = tk.Tk()

#StringVar for currentValue in R0C2
currentValue = tk.StringVar(main, "0")

#Called by the setValues button, looks for content in the entry box and updates the "current" label
def setValues():
    content = entry.get()
    print(content)
    currentValue.set(content)

#This kills the program
def exitProgram():
    main.destroy()

#Title and window size
main.title("Title")
main.geometry("350x200")

#Descriptions on the far left
tk.Label(main, text="Duration (min): ").grid(row=0, column=0)

#Entry boxes for values amidship
entry = tk.Entry(main, width=10)
entry.grid(row=0, column=1)

#Displays what the value is currently set to.
currentValueLabel = tk.Label(textvariable=currentValue)
currentValueLabel.grid(row=0,column=2)

#Takes any inputted values and sets them in the "Current" column using def setValues
setValuesButton = tk.Button(text='Set Values',width=30,command=setValues)
setValuesButton.grid(row=9, column=0, columnspan=2)

#Red button to end program
exitButton = tk.Button(main, text='Exit Program',fg='white',bg='red',width=30, height=1,command=exitProgram)
exitButton.grid(row=20, column = 0, columnspan=2)
main.mainloop()

BTW, it's a Good Idea to avoid "star" imports. Doing from tkinter import * dumps 130 names into your namespace, which is unnecessary and creates the possibility of name collisions, especially if you do star imports from several modules. It also makes the code less readable, since the reader has remember which names you defined and which ones came from the imported module(s).

PM 2Ring
  • 54,345
  • 6
  • 82
  • 182
  • Thank you, this gets me exactly the result I wanted and I understand the various places I went wrong now. Also addresses a few other things I was struggling with on account of related mistakes I'd made. – Agent Aug 18 '17 at 09:47
  • @Agent As Ethan points out, there are various ways to improve the logic & organization of your code; I just wanted to get your code working correctly with minimal modifications. – PM 2Ring Aug 18 '17 at 09:49
  • 1
    And I appreciate it :) This is my first day trying to write a gui in python, I've just sort of laid everything out so I can easily see and understand why it does or doesn't work in its own context, and I'm really just learning in baby steps how to do each thing. I expect it looks a bit cringey to most, but once I get a better understanding of how and why the things do what they do, then I can learn how to optimize it as I put it into functional programs. – Agent Aug 18 '17 at 10:17
  • @Agent You're doing quite well considering this is your first day of GUI programming. There's lot to learn, and it takes a while to get your head around [event-driven programming](https://en.wikipedia.org/wiki/Event-driven_programming), but it eventually comes with practice, like most things in programming. – PM 2Ring Aug 18 '17 at 10:20
3

In my opinion the easiest way to do this would be using an object orientated method. This way you could declare a button with a command that calls a def which runs self.label.configure(text=self.entry.get()).

This can be seen below:

import tkinter as tk

class App:
    def __init__(self, master):
        self.master = master
        self.label = tk.Label(self.master)
        self.entry = tk.Entry(self.master)
        self.button = tk.Button(self.master, text="Ok", command=self.command)
        self.label.pack()
        self.entry.pack()
        self.button.pack()
    def command(self):
        self.label.configure(text=self.entry.get())

root = tk.Tk()
app = App(root)
root.mainloop()

The above creates a label, entry and button. The button has a command which calls a def within the class App and updates the value of the label to be the text contained within the entry.

This all works very smoothly and cleanly and more importantly is drastically easier (in my opinion) to read and update in the future.

Ethan Field
  • 4,646
  • 3
  • 22
  • 43
  • @PM2Ring Updated for appeasement ;) – Ethan Field Aug 18 '17 at 10:00
  • @PM2Ring Make a new account and upvote again, plz thanks – Ethan Field Aug 18 '17 at 10:09
  • I'll take that into consideration – Ethan Field Aug 18 '17 at 10:23
  • Cheers for the input, using classes is 'unmapped territory' for me at the moment but I will take all that on board when the time comes. Like I said on the other post, I'm still just at 'baby steps' for now. – Agent Aug 18 '17 at 10:24
  • 1
    @Agent that's understandable, classes can be really useful when used in conjunction with tkinter. It's something that I didn't really consider using when I first started working with Python, but once you wrap your head around it you'll wish you'd looked at it sooner. Also, I'm not sure what documentation you're using for tkinter but http://effbot.org/tkinterbook/ is your best friend when it comes to anything tkinter related. – Ethan Field Aug 18 '17 at 10:28
1

From your code you are setting the 'currentValue', which is a StringVar:

#StringVar for currentValue in R0C2
currentValue = StringVar(main, "0")

to an object Label further down in your code. You cannot do this!

 #Displays what the value is currently set to.
    currentValue = Label(textvariable=currentValue) ** this line is wrong
    currentValue.grid(row=0,column=2)

You should name the label something different like:

#Displays what the value is currently set to.
        lblCurrentValue = Label(textvariable=currentValue)
         lblCurrentValue.grid(row=0,column=2)

Then in your "setValues" method you should use 'StringVar.set(value) to update the label like so:

def setValues():
    content = entry.get()
    currentValue.set(entry.get())------------------Here I set the value to the entry box value
    print(content)

I tend to avoid stringVar and just use:

Label.config(text='*label's text*')

If you need more help I can post you my solution but try and solve it first becasue its the best way to learn. My tip is to make sure you are using correct naming conventions. In tkinter I tend to use lbl..., entryBox... etc before widgets so I know what they are and not to confuse them with variables.

Daniel
  • 2,028
  • 20
  • 18
  • Thanks for your feedback, I had not realized that I'd been overwriting my variable with the label object, but that makes sense now. Also is there a particular reason to avoid stringVar? Does it have accepted 'proper' and 'improper' usages, or is it just preference? I'm still quite new to python and trying to learn the best practices as I go – Agent Aug 18 '17 at 09:50
  • Hi, Just preference. I only started using tkinter this month. If the stringvar object is used in many places then yeah, It would be better to update that variable than update every single Label object individually. The disadvantage is that when you have a bug you may be thinking 'why isn't this label updating!' That would be because you assigned it ' label(self, text =' some text' ) instead of Label(self, textvariable='some text') It might be harder for someone new to read your code and see why something isn't being updated but either is fine. :) – Daniel Aug 18 '17 at 13:41