so i was making a Ping pong game, and i forgot something very important, adding text! so i searched up a tutorial, and i found NONE, looked at some of posts, NONE, so i decided, to ask the comunity once again, (because i am new at python) anyways, i need to put text inside of this code.
import tkinter as tk
class Main:
def __init__ (self,root):
self.root = root
self.root.title("Ping Pong in Python")
self.root.geometry("2000x2000")
self.canvas = tk.Canvas(root, width=400, height=400, background="red")
self.canvas.pack(fill="both", expand=True)
if __name__ == '__main__':
root = tk.Tk()
obj = Main(root)
root.mainloop()
i tried searching up at youtube, found NONE, which i expected, because nowadays people only explain what they think is useful at youtube, so i searched up at stack overflow (this website) which i found one, but was closed, and didn't even work like last time! so i expected this again, so i decided to ask the comunity once again.
Google is your best friend. "Tkinter Text" lead to https://www.tutorialspoint.com/python/tk_text.htm
import tkinter as tk
class Main:
def __init__ (self,root):
self.root = root
self.root.title("Ping Pong in Python")
self.root.geometry("2000x2000")
self.canvas = tk.Canvas(root, width=400, height=400, background="red")
self.canvas.pack(fill="both", expand=True)
# Add text
self.text = tk.Label(self.root, text="Ping Pong text")
self.text.pack()
self.text.place(relx=0.5, rely=0.1, anchor=tk.N)
if __name__ == '__main__':
root = tk.Tk()
obj = Main(root)
root.mainloop()
The "relx" parameter specifies the horizontal position of the text (0 being the left edge and 1 being the right edge). The "rely" parameter specifies the vertical position of the text (0 being the top edge and 1 being the bottom edge). The "anchor" parameter specifies which point of the text widget should be placed at the specified position. For example, tk.N specifies that the top of the text widget should be placed at the top of the window.
Edit: In line 9, just add parameter bg='red' in tk.Label widget.
for some reason, it has a background that isn't the same color as the
background, is there a solution for that?
You don't need place().
Code:
import tkinter as tk
class Main:
def __init__ (self,root):
self.root = root
self.root.title("Ping Pong in Python")
self.root.geometry("200x200")
self.canvas = tk.Canvas(self.root, width=400, height=400, background="red")
self.canvas.pack(fill="both", expand=True)
# Add text
self.text = tk.Label(self.canvas, text="Ping Pong text", background="red")
self.text.pack(padx=5, pady=5, anchor=tk.N)
if __name__ == '__main__':
root = tk.Tk()
obj = Main(root)
root.mainloop()
Output:
Related
This is about moving a label on a canvas in Python 3.7 (I think) using tkinter.
There are lots of answers on Google and here on this site, but none of them have answered my question and yet I can't imagine my code couldbe much simpler. I'm not terribly experienced when it comes to Python and clearly I'm doing something fundamentally wrong.
What I want to do: move a label to a position on a canvas dictated by the click of a mouse.
Here we are:
root = tk.Tk()
root.geometry("800x600")
def ClickedCallback(event):
#print(f'Event: {event}, l2: {l2}, tags: {canvas.gettags()}')
canvas.move(l2, 5, 0)
canvas = tk.Canvas(root, width=1000, height=600, bg='blue')
canvas.bind("<Button-1>", ClickedCallback)
canvas.place(relwidth=0.9, relheight=0.8, relx = 0.05, rely = 0.05)
l2 = tk.Label(canvas, bg='red')
l2.bind("<Button-1>", ClickedCallback)
l2.place(relx=0.2, rely=0.2)
l2['text'] = "Test"
root.mainloop()
Now that causes a straight up error. "line 2591, in move
self.tk.call((self._w, 'move') + args)
_tkinter.TclError: invalid boolean operator in tag search expression"
I then saw an example that showed the object name entered into the method as a string rather than the object itself. So the line became:
canvas.move('l2', 5, 0)
Now this doesn't cause an error. But it also doesn't do anything.
I don't even know if moving on a canvas is the best way to do this. I just want to move a label around inside the window and this seemed to be the one that appeared in searches.
To place widget (ie. Label) on Canvas you have to use
label_id = canvas.create_window(position, window=l2,...)
not place()/grid()/pack()
And later you use this label_id to move it.
Simple example - Label is moved when you click Canvas
import tkinter as tk
# --- functions ---
def clicked_callback(event):
#canvas.move(label_id, 5, 0)
canvas.coords(label_id, event.x, event.y)
# --- main ---
root = tk.Tk()
root.geometry("800x600")
canvas = tk.Canvas(root, width=1000, height=600, bg='blue')
canvas.bind("<Button-1>", clicked_callback)
canvas.place(relwidth=0.9, relheight=0.8, relx=0.05, rely=0.05)
l2 = tk.Label(canvas, text="Test", bg='red')
#l2.bind("<Button-1>", clicked_callback)
label_id = canvas.create_window((100, 100), window=l2)
root.mainloop()
Is there a way to tell Tkinter that I want some widget to always remain focused? I've created a minimal example that can be run to show my issue , here's an example window with small toplevel windows also overlayed:
Now if I click the upper title tk, the main window comes into focus and suddenly the small windows are behind the main window
I want to treat these smaller windows as if they are always in focus until the user specifically closes them. Of course this is a minimal example that is an idea behind a small subsection of my large application , is there any easy setting I can use for the toplevel that guarantees it will always remain in focus regardless of other windows? Here's the actual code that can be run to replicate this:
from Tkinter import *
class PropertyDialog(Toplevel):
def __init__(self, root, string):
Toplevel.__init__(self)
self.wm_overrideredirect(1)
self.root = root
self.\
geometry('+%d+%d' %
(root.winfo_pointerx(),
root.winfo_pointery()))
try:
self.tk.call('::Tk::unsupported::MacWindowStyle',
'style', self._w,
'help', 'noActivates')
except TclError:
pass
window_frame = Frame(self)
window_frame.pack(side=TOP, fill=BOTH, expand=True)
exit_frame = Frame(window_frame, background='#ffffe0')
exit_frame.pack(side=TOP, fill=X, expand=True)
button = Button(exit_frame, text='x', width=3, command=self.free,
background='#ffffe0', highlightthickness=0, relief=FLAT)
button.pack(side=RIGHT)
text_frame = Frame(window_frame)
text_frame.pack(side=TOP, fill=BOTH, expand=True)
label = Label(text_frame, text=string, justify=LEFT,
background='#ffffe0',
font=('tahoma', '8', 'normal'))
label.pack(ipadx=1)
def free(self):
self.destroy() # first we destroy this one
for val,widget in enumerate(dialogs): # go through the dialogs list
if widget is self: # when we find this widget
dialogs.pop(val) # pop it out
break # and stop searching
if dialogs: # if there are any dialogs left:
for widget in dialogs: # go through each widget
widget.lift(aboveThis=self.root) # and lift it above the root
def bind():
"""
toggle property window creation mode
"""
root.bind('<ButtonPress-1>', create)
def create(event):
"""
Create actual window upon mouse click
"""
dialogs.append(PropertyDialog(root, 'help me'))
root = Tk()
dialogs = []
root.geometry('%dx%d' % (300,400))
Button(root, text='create', command=bind).pack()
root.mainloop()
change this:
if dialogs: # if there are any dialogs left:
for widget in dialogs: # go through each widget
widget.lift(aboveThis=self.root) # and lift it above the root
to this:
if dialogs: # if there are any dialogs left:
for widget in dialogs: # go through each widget
widget.lift() # and lift it above the root
the widgets will stay above the main window.
EDIT:
Sorry that only half worked... the widows will stay above sometimes with that code
:-X
It was keeping the widgets on top until you closed one of them.... this code does keep the widgets on top
it uses the self.attributes("-topmost", True) when you spawn the windows.
Sorry again.
from Tkinter import *
class PropertyDialog(Toplevel):
def __init__(self, root, string):
Toplevel.__init__(self)
self.wm_overrideredirect(1)
self.root = root
self.\
geometry('+%d+%d' %
(root.winfo_pointerx(),
root.winfo_pointery()))
try:
self.tk.call('::Tk::unsupported::MacWindowStyle',
'style', self._w,
'help', 'noActivates')
except TclError:
pass
window_frame = Frame(self)
window_frame.pack(side=TOP, fill=BOTH, expand=True)
exit_frame = Frame(window_frame, background='#ffffe0')
exit_frame.pack(side=TOP, fill=X, expand=True)
button = Button(exit_frame, text='x', width=3, command=self.free,
background='#ffffe0', highlightthickness=0, relief=FLAT)
button.pack(side=RIGHT)
text_frame = Frame(window_frame)
text_frame.pack(side=TOP, fill=BOTH, expand=True)
label = Label(text_frame, text=string, justify=LEFT,
background='#ffffe0',
font=('tahoma', '8', 'normal'))
label.pack(ipadx=1)
self.attributes("-topmost", True)
def free(self):
self.destroy() # first we destroy this one
def bind():
"""
toggle property window creation mode
"""
root.bind('<ButtonPress-1>', create)
def create(event):
"""
Create actual window upon mouse click
"""
dialogs.append(PropertyDialog(root, 'help me'))
root = Tk()
dialogs = []
root.geometry('%dx%d' % (300,400))
Button(root, text='create', command=bind).pack()
root.mainloop()
I recommend moving away from Toplevel widgets, since those are separate windows and you're suppressing their window-like behavior. This version makes PropertyDialog inherit from Frame instead of Toplevel, using the place() geometry manager. When you click the main window, it first checks whether the widget clicked was the main window or a popup window to prevent a new popup from appearing when you close an existing one. Changed areas are marked with #CHANGED#.
from Tkinter import *
class PropertyDialog(Frame): #CHANGED#
def __init__(self, root, string, event): #CHANGED#
Frame.__init__(self) #CHANGED#
self.root = root
try:
self.tk.call('::Tk::unsupported::MacWindowStyle',
'style', self._w,
'help', 'noActivates')
except TclError:
pass
exit_frame = Frame(self, background='#ffffe0') #CHANGED#
exit_frame.pack(side=TOP, fill=X, expand=True)
button = Button(exit_frame, text='x', width=3, command=self.free,
background='#ffffe0', highlightthickness=0, relief=FLAT)
button.pack(side=RIGHT)
text_frame = Frame(self) #CHANGED#
text_frame.pack(side=TOP, fill=BOTH, expand=True)
label = Label(text_frame, text=string, justify=LEFT,
background='#ffffe0',
font=('tahoma', '8', 'normal'))
label.pack(ipadx=1)
self.place(x=event.x, y=event.y, anchor=NW) #CHANGED#
def free(self):
self.destroy()
# other things you want to do - if there's nothing else,
# just bind the close button to self.destroy
def bind():
"""
toggle property window creation mode
"""
root.bind('<ButtonPress-1>', create)
def create(event):
"""
Create actual window upon mouse click
"""
if event.widget is root: #CHANGED#
dialogs.append(PropertyDialog(root, 'help me', event))
root = Tk()
dialogs = []
root.geometry('%dx%d' % (300,400))
Button(root, text='create', command=bind).pack()
root.mainloop()
I'm trying to pack the button below the Text and Scrollbar widget.
#!/usr/bin/python
try:
from Tkinter import *
except ImportError:
from tkinter import *
class Chat(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack(anchor=N, fill=BOTH)
self.create_widgets()
self.count = 0
def create_widgets(self):
self.scrolly = Scrollbar(self)
self.scrolly.pack(side=RIGHT, fill=Y)
self.chattext = Text(self, borderwidth=5, yscrollcommand=self.scrolly.set)
self.chattext.pack(side=LEFT)
self.scrolly.config(command=Text.yview(self.chattext))
self.button1 = Button(self, text="Add text", command=self.add_text)
self.button1.pack()
def add_text(self):
self.count += 1
self.chattext.insert("end", "%i\n" % self.count)
self.chattext.update_idletasks()
def main():
root = Tk()
root.title("Test Chat Client")
root.geometry("600x500")
#root.resizable(0,0)
app = Chat(root)
root.mainloop()
if __name__ == "__main__":
main()
This is what it looks like
I want the button to be below and not in between the other widgets.
I have tried the following:
self.button1.pack(after=self.scrolly)
self.button1.pack(after=self.chattext)
How may i pack the button at the bottom?
Another issue is that the scrollbar does not work, when i try to scroll nothing happens.
(Yes, i have tried to fill the Text widget with alot of lines, more than it can view.)
Also, why is the scrollbar viewed/packed outside/"far" away from the Text widget?
Try using the grid geometry manager instead.
http://www.tkdocs.com/tutorial/grid.html
I think you should consider replacing the text field with a ScrolledText field.
It's a lot easier to use and doesn't require manual scrollbar placement.
(Don't use pack to place it though. Use grid)
import tkinter as tk
import tkinter.scrolledtext as tkst
self.chattext = tkst.ScrolledText(
master = self,
wrap = tk.WORD,
width = 20,
height = 10
)
I'm trying to resize a window in my GUI but one of my frames is getting left out and I'm not sure why. The window resizes fine horizontally, but when I try to resize vertically the frame with the button disappears. This is my first GUI so I'm sure there is something I'm missing...
from Tkinter import *
from ttk import *
class GUI(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.root = root
lbFrame = Frame(self.root)
nbFrame = Frame(self.root)
self.note = Notebook(nbFrame)
self.note.pack(fill=BOTH, expand=YES)
lbFrame.pack(side=LEFT, fill=BOTH, expand=YES)
nbFrame.pack(side=RIGHT, fill=BOTH, expand=YES)
self.make_file_viewer()
# Label
lblabel = Label(lbFrame, text='Files', background='#E8E8E8')
lblabel.pack(side=TOP, expand=YES, padx=10, pady=10)
# Listbox
self.lb = Listbox(lbFrame, height=49, borderwidth=0, font=('Purisa', 11), selectmode=EXTENDED)
self.lb.pack(side=BOTTOM, expand=YES, padx=10, pady=10)
def make_file_viewer(self):
fvwr = Frame(self.note)
dataFrm = Frame(fvwr)
btnFrm = Frame(fvwr)
dataFrm.pack(side=TOP, fill=BOTH, expand=YES)
btnFrm.pack(side=BOTTOM, fill=BOTH, expand=YES)
fvwr.config(borderwidth=2)
self.note.add(fvwr, text='File View')
# Label
self.lbl_fvwr_search = Label(dataFrm, text='Search Hits\t0', justify=LEFT)
self.lbl_fvwr_search.pack(side=TOP, anchor=W, expand=YES)
# Scrollbar
scrollbar_fvwr = Scrollbar(dataFrm)
scrollbar_fvwr.pack(side=RIGHT, fill=Y, expand=YES)
# Textbox
self.outputPanel_fvwr_text = Text(dataFrm, wrap='word', height=40, width=115, yscrollcommand=scrollbar_fvwr.set)
self.outputPanel_fvwr_text.pack(side=LEFT, fill=BOTH, expand=YES)
scrollbar_fvwr.config(command=self.outputPanel_fvwr_text.yview)
# Start button
viewBtn = Button(btnFrm, text='Start', width=8)
viewBtn.pack(anchor=W, expand=YES)
if __name__ == '__main__':
root = Tk()
app = GUI(root)
root.mainloop()
The absolute best thing you can do is to start over, and do your layout step-by-step. Start by creating the main areas, and make sure they resize properly. In your case, create the left and right sides. Again, get those two sides resizing properly with respect to each other.
Once you are done, focus on one section. Since you know the main section resizes properly, you only need to focus on the elements within that particular side. Again, break it down into pieces, and get those pieces working before tackling any widgets inside the main pieces.
When you do your layout this way, it's much easier to get the whole GUI working right, because you aren't trying to juggle the behavior of a half dozen widgets at once.
In your specific case, the root of the problem is that you have expand=YES for just about everything. As a general rule of thumb, you only want to set that to YES for one widget in an given parent window. For example, in your main window you want the right to expand but not the left (I'm guessing), and in the right window you want the text widget to expand but not the other widgets.
Set expand=NO for scrollbar_fvwr, self.lbl_fvwr_search, and btnFrm to get the right side to resize properly. For the left side, add fill=BOTH for self.lb, and expand=NONE for lblabel.
Something like this, would make the widget appear normally:
Label(self, text = 'hello', visible ='yes')
While something like this, would make the widget not appear at all:
Label(self, text = 'hello', visible ='no')
You may be interested by the pack_forget and grid_forget methods of a widget. In the following example, the button disappear when clicked
from Tkinter import *
def hide_me(event):
event.widget.pack_forget()
root = Tk()
btn=Button(root, text="Click")
btn.bind('<Button-1>', hide_me)
btn.pack()
btn2=Button(root, text="Click too")
btn2.bind('<Button-1>', hide_me)
btn2.pack()
root.mainloop()
One option, as explained in another answer, is to use pack_forget or grid_forget. Another option is to use lift and lower. This changes the stacking order of widgets. The net effect is that you can hide widgets behind sibling widgets (or descendants of siblings). When you want them to be visible you lift them, and when you want them to be invisible you lower them.
The advantage (or disadvantage...) is that they still take up space in their master. If you "forget" a widget, the other widgets might readjust their size or orientation, but if you raise or lower them they will not.
Here is a simple example:
import Tkinter as tk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.frame = tk.Frame(self)
self.frame.pack(side="top", fill="both", expand=True)
self.label = tk.Label(self, text="Hello, world")
button1 = tk.Button(self, text="Click to hide label",
command=self.hide_label)
button2 = tk.Button(self, text="Click to show label",
command=self.show_label)
self.label.pack(in_=self.frame)
button1.pack(in_=self.frame)
button2.pack(in_=self.frame)
def show_label(self, event=None):
self.label.lift(self.frame)
def hide_label(self, event=None):
self.label.lower(self.frame)
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I know this is a couple of years late, but this is the 3rd Google response now for "Tkinter hide Label" as of 10/27/13... So if anyone like myself a few weeks ago is building a simple GUI and just wants some text to appear without swapping it out for another widget via "lower" or "lift" methods, I'd like to offer a workaround I use (Python2.7,Windows):
from Tkinter import *
class Top(Toplevel):
def __init__(self, parent, title = "How to Cheat and Hide Text"):
Toplevel.__init__(self,parent)
parent.geometry("250x250+100+150")
if title:
self.title(title)
parent.withdraw()
self.parent = parent
self.result = None
dialog = Frame(self)
self.initial_focus = self.dialog(dialog)
dialog.pack()
def dialog(self,parent):
self.parent = parent
self.L1 = Label(parent,text = "Hello, World!",state = DISABLED, disabledforeground = parent.cget('bg'))
self.L1.pack()
self.B1 = Button(parent, text = "Are You Alive???", command = self.hello)
self.B1.pack()
def hello(self):
self.L1['state']="normal"
if __name__ == '__main__':
root=Tk()
ds = Top(root)
root.mainloop()
The idea here is that you can set the color of the DISABLED text to the background ('bg') of the parent using ".cget('bg')" http://effbot.org/tkinterbook/widget.htm rendering it "invisible". The button callback resets the Label to the default foreground color and the text is once again visible.
Downsides here are that you still have to allocate the space for the text even though you can't read it, and at least on my computer, the text doesn't perfectly blend to the background. Maybe with some tweaking the color thing could be better and for compact GUIs, blank space allocation shouldn't be too much of a hassle for a short blurb.
See Default window colour Tkinter and hex colour codes for the info about how I found out about the color stuff.
I'm also extremely late to the party, but I'll leave my version of the answer here for others who may have gotten here, like I did, searching for how to hide something that was placed on the screen with the .place() function, and not .pack() neither .grid().
In short, you can hide a widget by setting the width and height to zero, like this:
widget.place(anchor="nw", x=0, y=0, width=0, height=0)
To give a bit of context so you can see what my requirement was and how I got here.
In my program, I have a window that needs to display several things that I've organized into 2 frames, something like this:
[WINDOW - app]
[FRAME 1 - hMainWndFrame]
[Buttons and other controls (widgets)]
[FRAME 2 - hJTensWndFrame]
[other Buttons and controls (widgets)]
Only one frame needs to be visible at a time, so on application initialisation, i have something like this:
hMainWndFrame = Frame(app, bg="#aababd")
hMainWndFrame.place(anchor="nw", x=0, y=0, width=480, height=320)
...
hJTensWndFrame = Frame(app, bg="#aababd")
I'm using .place() instead of .pack() or .grid() because i specifically want to set precise coordinates on the window for each widget. So, when i want to hide the main frame and display the other one (along with all the other controls), all i have to do is call the .place() function again, on each frame, but specifying zero for width and height for the one i want to hide and the necessary width and height for the one i want to show, such as:
hMainWndFrame.place(anchor="nw", x=0, y=0, width=0, height=0)
hJTensWndFrame.place(anchor="nw", x=0, y=0, width=480, height=320)
Now it's true, I only tested this on Frames, not on other widgets, but I guess it should work on everything.
For hiding a widget you can use function pack_forget() and to again show it you can use pack() function and implement them both in separate functions.
from Tkinter import *
root = Tk()
label=Label(root,text="I was Hidden")
def labelactive():
label.pack()
def labeldeactive():
label.pack_forget()
Button(root,text="Show",command=labelactive).pack()
Button(root,text="Hide",command=labeldeactive).pack()
root.mainloop()
I was not using grid or pack.
I used just place for my widgets as their size and positioning was fixed.
I wanted to implement hide/show functionality on frame.
Here is demo
from tkinter import *
window=Tk()
window.geometry("1366x768+1+1")
def toggle_graph_visibility():
graph_state_chosen=show_graph_checkbox_value.get()
if graph_state_chosen==0:
frame.place_forget()
else:
frame.place(x=1025,y=165)
score_pixel = PhotoImage(width=300, height=430)
show_graph_checkbox_value = IntVar(value=1)
frame=Frame(window,width=300,height=430)
graph_canvas = Canvas(frame, width = 300, height = 430,scrollregion=(0,0,300,300))
my_canvas=graph_canvas.create_image(20, 20, anchor=NW, image=score_pixel)
vbar=Scrollbar(frame,orient=VERTICAL)
vbar.config(command=graph_canvas.yview)
vbar.pack(side=RIGHT,fill=Y)
graph_canvas.config(yscrollcommand=vbar.set)
graph_canvas.pack(side=LEFT,expand=True,fill=BOTH)
frame.place(x=1025,y=165)
Checkbutton(window, text="show graph",variable=show_graph_checkbox_value,command=toggle_graph_visibility).place(x=900,y=165)
window.mainloop()
Note that in above example when 'show graph' is ticked then there is vertical scrollbar.
Graph disappears when checkbox is unselected.
I was fitting some bar graph in that area which I have not shown to keep example simple.
Most important thing to learn from above is the use of frame.place_forget() to hide and frame.place(x=x_pos,y=y_pos) to show back the content.
For someone who hate OOP like me (This is based on Bryan Oakley's answer)
import tkinter as tk
def show_label():
label1.lift()
def hide_label():
label1.lower()
root = tk.Tk()
frame1 = tk.Frame(root)
frame1.pack()
label1 = tk.Label(root, text="Hello, world")
label1.pack(in_=frame1)
button1 = tk.Button(root, text="Click to hide label",command=hide_label)
button2 = tk.Button(root, text="Click to show label", command=show_label)
button1.pack(in_=frame1)
button2.pack(in_=frame1)
root.mainloop()
import tkinter as tk
...
x = tk.Label(text='Hello', visible=True)
def visiblelabel(lb, visible):
lb.config(visible=visible)
visiblelabel(x, False) # Hide
visiblelabel(x, True) # Show
P.S. config can change any attribute:
x.config(text='Hello') # Text: Hello
x.config(text='Bye', font=('Arial', 20, 'bold')) # Text: Bye, Font: Arial Bold 20
x.config(bg='red', fg='white') # Background: red, Foreground: white
It's a bypass of StringVar, IntVar etc.