How to add a margin to a tkinter window - python

So I have so far a simple python tkinter window and i'm adding text, buttons, etc.
snippet:
class Cfrm(Frame):
def createWidgets(self):
self.text = Text(self, width=50, height=10)
self.text.insert('1.0', 'some text will be here')
self.text.tag_configure('big', font=('Verdana', 24, 'bold'))
self.text["state"] = "disabled"
self.text.grid(row=0, column=1)
self.quitw = Button(self)
self.quitw["text"] = "exit",
self.quitw["command"] = self.quit
self.quitw.grid(row=1, column=1)
def __init__(self, master=None):
Frame.__init__(self, master)
self.pack()
self.createWidgets()
the problem is, I want to have about a 15-20 px margin around the window, I looked everywhere, and I couldn't find a solution. Also
self.text.tag_configure('big', font=('Verdana', 24, 'bold'))
doesn't work. Any possible solutions?

Ok, here is the solution I found for question 1:
self.grid(padx=20, pady=20)
Removing .text seems to change the whole frame. I still haven't solved problem 2.

Use the pad options (padx, pady, ipadx, ipady) for the grid command to add padding around the text widget. For example:
self.text.grid(row=0, column=1, padx=20, pady=20)
If you want padding around the whole GUI, add padding when you pack the application frame:
self.pack(padx=20, pady=20)
When you say the tag command doesn't work, how do you define "doesn't work"? Are you getting an error? Does the font look big but not bold, bold but not big, ...? The command looks fine to me, and when I run it it works fine.
Your example doesn't show that you're actually applying that tag to a range of text. Are you? If so, how? If you do the following, what happens?
self.text.insert("1.0", 'is this bold?', 'big')

A quick way to do it is adjust your relief style to flat, then you only have to adjust your border width.
self.Border = Tkinter.Frame(self, relief='flat', borderwidth=4)

You can add an innerFrame with some borderwidth or ipadx,ipady attributes to the root Tk() object. Then put everything in it. And to be sure that innerFrame's width and height values are as the window's, use fill and expand attributes.
root = tk.Tk()
innerFrame = tk.Frame(root, borderwidth=25, bg="red")
innerFrame.pack(fill="both", expand=True)
someButton = tk.Button(innerFrame, text="Button1")
someButton.pack()
or
root = tk.Tk()
innerFrame = tk.Frame(root, bg="red")
innerFrame.pack(ipadx=15, ipady=15, fill="both", expand=True)
someButton = tk.Button(innerFrame, text="Button1")
someButton.pack()

Related

customtkinter - align text in CTkLabel

I want my text to be aligned to the left (or west).
My code:
import customtkinter as ctk
import tkinter as tk
root = tk.Tk()
root.geometry("300x100")
label = ctk.CTkLabel(master=root,
text="this is a label",
text_color="#fff",
bg_color="green",
width=250,
justify="left",
anchor="w"
)
label.place(x=0, y=0)
root.mainloop()
Even with justify="left" and anchor="w" nothing changes and the text is centered. Why? And how can I fix it?
Actually CTKLabel is a Frame and the text is a Label inside that frame. The text is put at center of the frame using place(relx=0.5, rely=0.5, anchor='c'). So the justify and anchor options passed to CTKLabel does not work.
However, you can move the text after creating the instance as below:
label = ctk.CTkLabel(master=root,
text="this is a label",
text_color="#fff",
bg_color="green",
width=250,
justify="left",
anchor="w"
)
label.text_label.place(relx=0, anchor='w') # move the text to the left side of frame
label.place(x=0, y=0)
Or making the text to fill the frame horizontally:
label.text_label.place(relwidth=1)
This could be solve your problem: anchor=ctk.W
And here is the code:
label = ctk.CTkLabel(master=root,
text="this is a label",
text_color="#fff",
bg_color="green",
anchor=ctk.W)
Adding justify worked for me. I was able to center align the text inside the Custom TKinter textbox (CTKEntry)
example:
testEntry = customtkinter.CTkEntry(master=f1,
justify=CENTER,
width=120,
height=120,
corner_radius=2)
Regards,
V.M.Guruprasath

How to custom button and text box using Python GUI?

I would like to ask how to make a custom button and custom text box by using Python?
A custom button should has: transparent feature with only border, round corner, shadow feature, icon need to be placed, animate feature like color changed when click and hover on it.
A custom text box should has: no border but only underline, round corner, transparent feature, icon need to be placed, animate feature like underline becomes thicker when click on it.
Below is my code:
frame = tk.Frame(root, bg='#000000', bd=0)
frame.place(relx=0.5, rely=0.1, relwidth=0.75, relheight=0.1, anchor='n')
entry = tk.Entry(frame, font=60, relief='flat')
entry.place(relwidth=0.65, relheight=1)
button = tk.Button(frame, text="Run", relief='flat', font=40, command=lambda: get_weather(entry.get()))
button.place(relx=0.7, relheight=1, relwidth=0.3)
Here is the reference image design that I prefer:
Any help would be appreciated, thanks!
Tkinter comes with the module ttk which stands for themed tk. It provides a way to create widget themes.
How to do it is under-documented, but tkdocs.com has a good discussion of the fundamentals.
At the end of this question is code which can create frames that have rounded corners, a shadow, and a unique color to represent focus, to serve as an example of what you can do. Answering all your questions is a bit beyond the scope of what stackoverflow is for, but hopefully, this is enough to show that what you want is possible.
import tkinter as tk
from tkinter import ttk
focusBorderImageData = '''
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
Ry/99NIz//oGrZpUUEAAOw==
'''
borderImageData = '''
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
'''
root = tk.Tk()
style = ttk.Style()
borderImage = tk.PhotoImage("borderImage", data=borderImageData)
focusBorderImage = tk.PhotoImage("focusBorderImage", data=focusBorderImageData)
style.element_create("RoundedFrame",
"image", borderImage,
("focus", focusBorderImage),
border=16, sticky="nsew")
style.layout("RoundedFrame",
[("RoundedFrame", {"sticky": "nsew"})])
frame1 = ttk.Frame(style="RoundedFrame", padding=10)
text1 = tk.Text(frame1, borderwidth=0, highlightthickness=0, wrap="word",
width=40, height=4)
text1.pack(fill="both", expand=True)
text1.bind("<FocusIn>", lambda event: frame1.state(["focus"]))
text1.bind("<FocusOut>", lambda event: frame1.state(["!focus"]))
text1.insert("end", "This widget has the focus")
frame2 = ttk.Frame(style="RoundedFrame", padding=10)
text2 = tk.Text(frame2, borderwidth=0, highlightthickness=0, wrap="word",
width=40, height=4)
text2.pack(fill="both", expand=True)
text2.bind("<FocusIn>", lambda event: frame2.state(["focus"]))
text2.bind("<FocusOut>", lambda event: frame2.state(["!focus"]))
text2.insert("end", "This widget does not have the focus")
root.configure(background="white")
frame1.pack(side="top", fill="both", expand=True, padx=20, pady=20)
frame2.pack(side="top", fill="both", expand=True, padx=20, pady=20)
frame1.focus_set()
root.mainloop()
This code was originally posted as an answer to the question Tkinter: How to make a rounded corner text widget?. The original version of this code was written in Tcl in 2007, before stackoverflow existed.

How to align tkinter widgets?

How do I align my Radiobuttons? I can add spaces to test4 but that solution doesn't seem proper. Here's what it looks like at the moment—as you can see text111111 has extra chars. I've tried using padx.
My code:
from tkinter import *
class GUI:
def __init__(self, master):
self.iconnum = IntVar()
self.master = master
self.master.title('test')
self.master.resizable(width=False, height=False)
self.master.maxsize(500, 250)
self.master.minsize(500, 250)
self.test1 = Radiobutton(master, text="test11111111", variable=self.iconnum,
value=1, )
self.test2 = Radiobutton(master, text="test2", variable=0, value=2, )
self.test3 = Radiobutton(master, text="test3", variable=0, value=3, )
self.test4 = Radiobutton(master, text="test4", variable=0, value=4)
self.test1.grid(row=2, columnspan=1)
self.test2.grid(row=2, columnspan=2)
self.test3.grid(row=2, column=1)
self.test4.grid(row=3, columnspan=1)
self.Checker = Radiobutton(master, text="test5", indicatoron=0, height=1, width=35,
value=0, command=self.icon_switcher) #var=Selection)
self.Turbo = Radiobutton(master, text="test6", indicatoron=0, height=1, width=35,
value=1, command=self.icon_switcher) #var#=Selection)
self.Checker.grid(row=1)
self.Turbo.grid(row=1, column=1, )
def icon_switcher(self):
print("Hello")
root = Tk()
gui = GUI(root)
root.mainloop()
You should use the sticky keyword argument in order to align your widgets better when using grid.
import Tkinter as tk
window = tk.Tk()
radio = tk.Radiobutton(window, text="I'm a radio")
radio.grid(column=0, row=0, sticky=tk.N+tk.S+tk.W+tk.E)
window.mainloop()
You can use any combination of the N, S, W and E members of the Tkinter module. This parameter will make your widgets stick to the sides of the cell you have specified, somewhat like justification in text. If your widget is resizable, such as with Button, the widget will also automatically resize to fit the cell if you use all of the N, S, W and E members.
Important to note is that this can only do so much as to make the widgets stick to the edges of the cell. Sometimes it is necessary to actually resize the cell or move your widget to another cell.
In your example image, you have Buttons with a set size that is larger than the default size (the example code you provide is incomplete). This causes the cell, and the whole columns that the cells of these Buttons are in, to become wider. In this case, you might want to use the columnspan keyword argument to divide your column into smaller, resizable, parts, so that your Radiobuttons can be aligned still better.
import Tkinter as tk
window = tk.Tk()
radio_one = tk.Radiobutton(window, text="I'm a radio")
radio_two = tk.Radiobutton(window, text="I'm another radio")
button = tk.Button(window, text="I am a very long button", width=50)
button.grid(row=0, column=0, columnspan=2, sticky=tk.N+tk.S+tk.W+tk.E)
radio_one.grid(column=0, row=1, sticky=tk.N+tk.W)
radio_two.grid(column=1, row=1, sticky=tk.N+tk.W)
window.mainloop()
If you would like more information on what parameters the grid geometry manager can use, I suggest you read this tutorial, I have found it to be very helpful in the past.
As a sidenote, please note that you use the variable keyword argument in the declaration of your Radiobuttons incorrectly. You must pass either a tk.StringVar, tk.IntVar or some other comparable object, as described here.
You can use sticky=W inside your .grid for all your buttons to make them align on the left side. And you can also include pady = 20 to make it not go all the way to the left.

Frame as a container (tkinter)

Python 3.4.0.
Could you help me understand what is going on here:
from tkinter import *
root = Tk()
f = Frame(root, borderwidth=2) #
for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]:
Label(f, text=relief, width=10, relief = relief).pack(side=LEFT) #
#f = Frame(root, borderwidth=2, relief = relief)
#Label(f, text=relief, width=10).pack(side=LEFT)
f.pack(side=LEFT, padx=5, pady=5)
root.mainloop()
If I uncomment now commented lines and comment the lines that hafe '#' mark at the end, the result is the same.
First case: the present situation. It is understandable to me. Before the loop we create a frame. Then pack method places each label in the parent widget (which is f). In this case f expands and contains several labels.
Well, the second case: if I switch the comment marks.
A frame f is always new. Label is also always new. A label is always placed on a separate frame. I would suggest that 5 frames would be displayed with a different label in each frame.
Could you help me understand why the result is the same?
Sounds like you want five separate windows, each of which can be moved, closed, etc.
If so, you should use the Toplevel widget instead of Frame.
from tkinter import *
root = Tk()
for relief in [RAISED, SUNKEN, FLAT, RIDGE, GROOVE, SOLID]:
t = Toplevel(root, borderwidth=2, relief = relief)
Label(t, text=relief, width=10).pack(side=LEFT)
root.mainloop()

Tkinter window changing size becuase items in listbox

Hello!
Im developing a GUI to simple python script I made (The GUI developed using SpecTcl).
The script is searching a website and show the search results in a list box.
The code is:
results = search(query) #return a list of results, or False if there are no results
msg = msgMngr()
if results == False:
msg.onWarn("No results", "No search results to " + query) #Warn the user that there are no results
else:
self.list.delete(0, END) #clear listbox
for item in results: #enter all items to the listbox
self.list.insert(END, item)
To demonstrate the problem, i made a simple program which add to the list "hello world!" every time the user click the button: http://i.imgur.com/FuTtrOl.png
but, when there are more items than the list size capacity, its just get bigger: http://i.imgur.com/f9atci5.png
It also happneds horizontally if the item is too long: i.imgur.com/a88DRxy.png
What I want to do is: the window will always stay in his original size, and there will be 2 scrollbars if there are too many items or the item length is too high.
I tried just adding scrollbars but it didnt help.
I also tried forcing the screen size using root.resizable(0,0), and it still got bigger and bigger.
It's my first question here, if i did something wrong/didnt described the problem well just tell me and ill fix :)
Thanks!
What you describe is not the default behavior of a tk listbox widget. Here is an example showing a listbox with scrollbars:
import Tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent, borderwidth=1, relief="sunken")
b = tk.Button(self, text="search", command=self.add_one)
self.lb = tk.Listbox(self, borderwidth=0)
self.lb.pack(fill="both", expand=True)
vsb = tk.Scrollbar(self, orient="vertical", command=self.lb.yview)
hsb = tk.Scrollbar(self, orient="horizontal", command=self.lb.xview)
self.lb.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
b.grid(row=0, column=0, columnspan=2)
vsb.grid(row=1, column=1, sticky="ns")
self.lb.grid(row=1, column=0, sticky="nsew")
hsb.grid(row=2, column=0, sticky="ew")
self.grid_rowconfigure(1, weight=1)
self.grid_columnconfigure(0, weight=1)
def add_one(self):
self.lb.insert("end", "hello world!")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()

Categories