tkinter puts WAY too much space between checkbuttons - python

I can't figure out how to get tkinter to put checkbuttons and radiobuttons closer together. Even specifying pady=0 anyplace it seems valid has no effect. The vertical distance between the buttons is unnaturally large, ugly, and just wastes space. In order to make a set of buttons appear as a group separate from other controls requires that I add extra space elsewhere, which just gets out of control.
Here's a working example I extracted:
from Tkinter import *
def rbtest(frame):
group = LabelFrame( frame, text="Target", padx=0, pady=0)
btnVal = StringVar(frame,' ')
for b in ( "option1", "another option", "Someth Else", "go away"):
rb=Radiobutton( group, text=b, value=b, variable=btnVal)
rb.pack( anchor=W, pady=2)
boardname = StringVar()
Label( group, text="Name").pack( anchor=W)
Entry( group, text=boardname).pack()
group.pack( side=LEFT, fill=Y, padx=0, pady=0)
tk = Tk()
rbtest(tk)
tk.mainloop()
[Well, I can't post an image showing what it produces because I don't have enough reputation, so sorry about that... I tried.]
Edit: I'm using Python 2.6.6 and Windows 7.
Considering how closely together it packs other elements, I'm surprised this is normal behavior, but all the examples I've found on the web look similar...

I ran your code on a Mac and on a windows box, and in both cases it looked about right to me. If you want them literally as close as possible, set the borderwidth to zero and the pady option to zero.
To eek out another two pixels between each button, set the highlightthickness to zero, though that affects the user experience when they are using keyboard traversal.

It looks pretty normal to me:
If it really needs to be made super-compact, there are ways of doing so, but I suspect your system is rendering the window differently.

Related

My second StringVar fails to show text, shows blank

I was writing a pixel editor in Tkinter, to practice Tkinter and GUI programming. And I was thinking to add a "bottom frame" to show informations like the current tool, the canvas size, etc. But for some reason, the second defined StringVar doesn't seems to work, while the first one works just fine. By this, I mean the code runs just fine but the second StringVar doesn't show anything.
Here is the code, for the bottom frame so far:
# Bottom frame
ttk.Style().configure('Interface.TFrame', background='#dbdbdb')
bottomframe = ttk.Frame(root, style='Interface.TFrame')
bottomframe.grid(column=0, row=2, sticky=(N, S, W, E), pady=4)
# An indicator that shows the current selected tool.
toolname = StringVar()
toolname.set('paint tool')
tool_label = ttk.Label(bottomframe, textvariable=toolname, width=11, background='#dbdbdb', anchor='center')
tool_label.grid(column=0, row=0, sticky=(W, E), padx=2)
# A thin separator.
ttk.Separator(bottomframe, orient=VERTICAL).grid(column=1, row=0, sticky=(N, S, W, E))
# An indicator that shows the canvas size.
cvsize = StringVar()
cvsize.set('50x50 px')
cv_size_label = ttk.Label(bottomframe, textvariable=cvsize, width=11, background='#dbdbdb', anchor='center')
cv_size_label.grid(column=2, row=0, sticky=W, padx=2)
So, why it's not working? The first and the second indicator look nearly same (except the bind operation) and the second one still fails. I also tried removing the first, but it also failed.
I have no idea how can I fix it. I think, I am either missing something and using the StringVar wrong, or there is something in my code that causes this behavior.
So, how can I fix it? And also, why it's happening?
EDIT: Removed the function definiton part. It wasn't really part of the question.
So, I finally understood the reason behind this behavior, thanks to #BryanOakley. Python was removing those unusued variables to free up memory. Because even though they are used in tkinter window, it doesn't really matter for Python, since the mainloop() is what organizing the window. So, it is necessary to save a reference of the variable somewhere, to prevent Python from removing it. And the easiest way of doing this, is saving the variable with self. Which won't get removed even after the class definiton ends.

Creating GUI with multiple function buttons

I am trying to create a GUI as shown in the attached picture
I wrote the following code which does the job but not the way I need it to.
try:
import Tkinter as tk
import tkMessageBox as mb
except ImportError:
import tkinter as tk
import tkinter.messagebox as mb
root = tk.Tk()
root.geometry("500x300")
tk.Label(root, text="Python First GUI Template", bg="goldenrod", font="bold").pack()
tk.Label(root, text="").pack()
def addFn():
a = int(input('enter first number'))
b = int(input('enter second number'))
mb.showinfo('showinfo', a+b)
def subtractFn():
a = int(input('enter first number'))
b = int(input('enter second number'))
mb.showinfo('showinfo', a - b)
tk.Button(root, text="Add Function", bg="SkyBlue1", command=addFn).pack()
tk.Label(root, text="").pack()
tk.Button(root, text="Subtract Function", bg="SkyBlue1", command=subtractFn).pack()
root.mainloop()
So, I have the following problems:
(1) I am not able to create the design as I want in the attached picture in terms of relative color and relative location of "add" and "subtract" buttons.
(2) When I hit the buttons to activate "add" or "subtract" functions, the inputs are required on the console. I need a pop up with input box and drop down for two numbers I want to add. I am looking for following format for "add" function.
(3) I want to add a "quit" button to close the console when I am done
I'm new to this myself, and unfortunately can't answer most of your questions, but regarding the quit button, I'm thinking you can write a function that calls quit(), just like you would type in order to exit the Python interactive interpreter. Then you link that function to a button just as you did for the first two buttons. This is the same idea with a lambda expression:
from tkinter import *
root =Tk()
root.geometry("500x300")
Button(root,text="QUIT",bg='Red',command=lambda:(quit())).pack(side=BOTTOM)
root.mainloop()
This here is a TKinter frame that gives you a red quit button at the bottom whose sole reason for existence is to quit the frame it's in.
Regarding the layout, I think the pack method requires you to indicate where pack should prefer to put the widget, but doesn't give you much absolute control. Wouldn't grid method allow for better alignment?
Why do your input boxes have to pop out? Why can't they be embedded into the app frame? I would think that would eliminate some difficulty with the issue, no?
Sorry this isn't the most helpful answer ever... but I hope it gives you something to work with until someone more knowledgeable happens by. Cheers.
There are a couple of ways you could do this, the simplest being using .grid() instead of .pack():
from tkinter import *
root = Tk()
title = Label(root, text="Python First GUI Template")
add = Button(root, text="Add")
subtract = Button(root, text="Subtract")
_quit = Button(root, text="Quit")
title.grid(row=0, column=1, padx=5, pady=5)
add.grid(row=1, column=0, padx=5, pady=5)
subtract.grid(row=1, column=2, padx=5, pady=5)
_quit.grid(row=2, column=3, padx=5, pady=5)
root.mainloop()
.grid() allows you to place widgets on the window in a grid fashion, imagine there are cells which you are placing each widget into, whereas .pack() by default will place items stacked on top of eachother unless certain attributes are given values.
You could also use .place() which allows you to place the widgets based on coordinates but this requires a lot more effort make responsive to window size changes or adding new widgets and the like.
On a side note, Stack Overflow is not a free programming resource, we will not write programs for you based on a list of demands. There are plenty of freelance programmers who are happy to do that in exchange for money. I would recommend in future that rather than asking a question about an incredibly well documented library with over 17000 questions on Stack Overflow, a large number of which are about the difference in the three geometry managers you instead find a tutorial or ask a colleague, schoolmate, teacher or friend for help.

Tkinter Radiobutton "indicatoron" value doesn't effect anything

Using Tkinter in Python 3.5, trying to create a series of radiobuttons without indicators (ie. regular push buttons). I set "indicatoron" to 0 but it still appears with indicators. I tried changing the value to 99999, 0.25, -1, and it always appears with indicators (except when I tried to set it to a string, then it told me it was expecting a boolean). What am I doing wrong?
Code snippet:
import tkinter as tk
term=tk.IntVar()
b1=tk.Radiobutton(root, text="1", variable=term, value=1, indicatoron=0).pack()
b2=tk.Radiobutton(root, text="2", variable=term, value=2, indicatoron=0).pack()
b3=tk.Radiobutton(root, text="3", variable=term, value=3, indicatoron=0).pack()
b4=tk.Radiobutton(root, text="4", variable=term, value=4, indicatoron=0).pack()
It appears to not work on OSX. In essence this flag does not work for radiobuttons or checkbuttons, and has not for many years.
This is the reason given by the TK team ...
it is mapped to a specific Cocoa button style (NSSwitchButton) that does not allow us to turn off the checkmark
The full official response (back in 2012), in regards to the checkbutton is ...
wordtech added on 2012-11-07 22:02:38:
As discussed in the Tkinter mailing list:
"After looking at the code that implements the checkbutton, it appears that, internally, it is mapped to a specific Cocoa button style (NSSwitchButton) that does not allow us to turn off the checkmark. I suppose we'll have to add this to the list of Tk configuration flags that are ignored in certain contexts when Mac-native widgets are used (background, relief, etc.). "
This is the less useful responce to the problem logged against the radiobutton ... It works for me
It is unclear why some people on OSX seem to have this working.

Python Tkinter message box with multiple text

http://i.imgur.com/0dLxzzc.png
How can I make the text on the right hand side(stored in variable msg2) to start from the top, ie same horizontal level as message on left hand side(msg)
Here is my code
from Tkinter import *
top = Tk()
msg = """I very soon decided that until I had done something towards naming and describing the most important groups in my collection, and had worked out some of the more interesting problems of variation and geographical distribution (of which I had had glimpses while collecting them), I would not attempt to publish my travels.GoodBye!!"""
w= Message(top,text=msg)
msg2="""I feel bound to give them full satisfaction on this point"""
v= Message(top,text=msg2)
w.grid(row=0,column=0)
v.grid(column=1,row=0)
top.mainloop()
Use sticky option (See grid documentation):
w.grid(row=0, column=0, sticky=N)
v.grid(row=0, column=1, sticky=N)

Stretching frames using grid layout in Python Tkinter

I'm trying to get stretching to work using Python 2.6.7 with Tkinter. I'd expect the below code to stretch the first button to the width of the second, but both buttons are only as wide as they need to be to fit their text.
#!/usr/bin/python
from Tkinter import *
win = Frame()
win.grid(sticky=N+S+E+W)
inner_a = Frame(win)
inner_a.grid(row=0, column=0, sticky=N+E+W)
inner_b = Frame(win)
inner_b.grid(row=1, column=0, sticky=S+E+W)
Button(inner_a, text='1').grid(row=0, column=0, sticky=E+W)
Button(inner_b, text='Some long text').grid(row=0, column=0, sticky=E+W)
win.mainloop()
By my understanding, the single column in win will expand to the width of the largest thing it contains, ie the width of inner_b, and then the width of inner_a, and thence of the first button, will be that of the second button.
Actually, what happens is the below; the first button is only wide enough to contain "1", not as wide as the second button.
What do I need to do to get the first button to expand the size of the second?
If you want widgets to line up in a grid, the first thing to do is make sure they have the same parent. This isn't strictly necessary if all the widgets are the same size or you are only using one column.
Another thing you need to do is give your column a weight. What is happening in your code is that the widget is expanding to fill the column, but the column isn't expanding to fill the master. If you give it a weight of 1 it will. You ned to do something like inner_a.columnconfigure(1, weight=1), and then do likewise for inner_b.

Categories

Resources