I've been writing this program using the Tkinter module in Python3.6.2. There are buttons to to open a list of teams and a list of competitors and I'd prefer to keep the outputs in one window, however if I click the "Teams" button followed by the "Individuals" button, the two elements open one after the other.
I'm hoping to add a button that resets the window (removing the outputs, leaving just the buttons), but I haven't found any solutions online that work with my program.
from tkinter import *
import tkinter as tk
bgcol = "#0B8CFF"
class MainMenu:
def __init__(self, master):
self.master = master
master.title("Scoring System GUI")
master.geometry("500x750+75+60")
self.label = Label(master, text="GUI")
self.label.pack()
self.team_button = Button(master, text="Teams", command=self.openTeams)
self.team_button.pack()
def openTeams(self):
self.label = Label(text="Team #1:")
self.label.pack()
team1 = open("team1.csv", "r")
message = team1.read()
text = Text(root, width = "50", height = "6", fg = "#000000")
text.pack()
text.insert(END, message)
redteam.close()
Here's a photo of the current output:
You have to clear the Text widget before inserting new strings. Just insert the following line before your text.insert(...) statement:
text.delete('1.0', END)
By the way, if you only want to display a list and not edit it (as I guess is the case here) a Listbox widget if often a better choice than a Text widget.
To do that you need to create another method inside your class and parse it to another button as callback command.
def reset_func(self):
self.text.delete('1.0', END)
with this method inside when you parse it as command to your button it will clear the content in text widget .
Related
I'm a beginner at Python and I don't know what to set command to so I can open one of the links in the class list (Sorry if I am calling it the wrong thing. Please include what to call it in your answer.) For example, if I wanted to open Slopes link, what would I type in the command for button_slope?
import webbrowser
from tkinter import *
from tkinter import ttk
root = Tk()
style = ttk.Style()
style.configure("TButton",
font="Serif 15",
padding=10)
class GameLibrary:
def __init__(self, game, link):
self.game = game
self.link = link
games = [
GameLibrary("Slope", "https://www.y8.com/games/slope"),
GameLibrary("Punch Boxing Championship", "https://www.y8.com/games/punch_boxing_championship"),
]
main_frame = Frame(root)
main_frame.pack()
main_frame.grid(row=0, columnspan=4)
button_slope = ttk.Button(main_frame, text='Slope', command='what do i type here').grid(row=1, column=0)
root.mainloop()
command should be set to a callback function that executes when the button is pressed. For instance.
def callback():
print "click!"
button_slope = ttk.Button(main_frame, text='Slope', command=callback)
button_slope.grid(row=1, column=0)
Will print click! when you click the button. You would want to take whatever action is appropriate for your program.
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:
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()
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).
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.
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.
May I know is it possible to create a event for a text in tkinter text widget?
Example, I click on a word on text box, and a small window will pop out and give a brief definition of the word.
You can add bindings to a text widget just like you can with any other widget. I think that's what you mean by "create a event".
In the following example I bind to the release of the mouse button and highlight the word under the cursor. You can just as easily pop up a window, display the word somewhere else, etc.
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.text = tk.Text(self, wrap="none")
self.text.pack(fill="both", expand=True)
self.text.bind("<ButtonRelease-1>", self._on_click)
self.text.tag_configure("highlight", background="green", foreground="black")
with open(__file__, "rU") as f:
data = f.read()
self.text.insert("1.0", data)
def _on_click(self, event):
self.text.tag_remove("highlight", "1.0", "end")
self.text.tag_add("highlight", "insert wordstart", "insert wordend")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Here's a simple example:
from tkinter import *
def callback(event):
info_window = Tk()
info_window.overrideredirect(1)
info_window.geometry("200x24+{0}+{1}".format(event.x_root-100, event.y_root-12))
label = Label(info_window, text="Word definition goes here.")
label.pack(fill=BOTH)
info_window.bind_all("<Leave>", lambda e: info_window.destroy()) # Remove popup when pointer leaves the window
info_window.mainloop()
root = Tk()
text = Text(root)
text.insert(END, "Hello, world!")
text.pack()
text.tag_add("tag", "1.7", "1.12")
text.tag_config("tag", foreground="blue")
text.tag_bind("tag", "<Button-1>", callback)
root.mainloop()
Clicking on "world" will pop up a small window which disappears when mouse pointer leaves the widget
Yes, it is possible. You can add a tag to a word or text region using the tag_add function, then use the tag_bind method (with a <Button> event) to make the text "clickable".
You can create a new TopLevel widget to pop up a new window in the callback function.
How can I change where the text is relative to the checkbox for a Tkinter Checkbutton?
By default, the text is to the right of the checkbox. I would like to change that, so the text is on the left or above of the checkbox.
I know this can be done by creating a Label with the required text and delicately positioning the two near each other, but I'd prefer to avoid that method.
Some sample code:
from Tkinter import *
root = Tk()
Checkbutton(root, text="checkButon Text").grid()
root.mainloop()
Well, I don't think you can do it directly, but you can do something that looks as it should. It is the Label-solution, but I altered it slightly, so the resulting compound of Checkbutton and Label is treated as a single Widget as wrapped in a Frame.
from Tkinter import *
class LabeledCheckbutton(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.checkbutton = Checkbutton(self)
self.label = Label(self)
self.label.grid(row=0, column=0)
self.checkbutton.grid(row=0, column=1)
root = Tk()
labeledcb = LabeledCheckbutton(root)
labeledcb.label.configure(text="checkButton Text")
labeledcb.grid(row=0, column=0)
root.mainloop()
When you create multiple frames (with their respective content - Checkbutton and Label) you can handle them easily. That way you would just have to position the Frames like you would do it with the Checkbuttons.
Hello and happy new year,
i'm trying to build a user interface and have a
problem with the Tix.ScrolledListbox.
(Python 2.6.5, Tix 8.4.3, Windows XP)
I wanted to use it to show items of varying number,
depending on a previous choice made by the user.
It's a GIS thing: the user picks a layer from a
ComboBox, presses a button and the Listbox
shows all fieldnames retrieved from the attribute
table. So for some layers there are 5, for others
30 fields. In principle it works.
But the scrollbar next to the listbox remains
grey with no function.
In a small test snippet, where, after pressing
a button, a random (0..100) number of items is shown
in the listbox the scrollbar works.
I have no idea.
Anybody had this before?
Edit: The following samplecode shows a not scrollable
scrolledListbox when arcpy is imported
import Tix
import random
import arcpy
class SampleApp(object):
def __init__(self):
self.window = Tix.Tk()
#listbox
self.lbx = Tix.ScrolledListBox(self.window, width = 30)
self.lbx.listbox.insert(Tix.END, " ")
self.lbx.listbox.bind("<<ListboxSelect>>", self.Choose)
#button to generate new list
self.btn = Tix.Button(self.window, text = "new list",
command = self.NewList)
#label shows chosen list item
self.lbl = Tix.Label(self.window, text = " ", bg = "white")
#pack
self.btn.pack(pady = 10)
self.lbx.pack(side="top", fill="both", expand=True, pady = 10)
self.lbl.pack(pady = 10)
self.window.mainloop()
#function to generate new listbox items on button command
def NewList(self):
self.lbx.listbox.delete(0, Tix.END)
r = random.randint(1, 30)
for i in range(r):
self.lbx.listbox.insert(Tix.END, i)
#event to show selected item in label
def Choose(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.lbl.config(text = value)
sa = SampleApp()
Did you attach the scrollbar to the listbox?
from Tkinter import *
root = Tk()
scrollbar = Scrollbar(root)
scrollbar.pack(side=RIGHT, fill=Y)
listbox = Listbox(root)
listbox.pack()
for i in range(100):
listbox.insert(END, i)
# attach listbox to scrollbar
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
mainloop()
stolen from: http://effbot.org/zone/tkinter-scrollbar-patterns.htm
edit: Tix.ScrolledListBox works differently so don't mix it up with the above solution.