I am relatively new to Tkinter and I am trying to create a GUI with three horizontally aligned entry widgets and three corresponding label widgets. I am struggling with how to put the label widgets below the entry widgets without disturbing the alignment of the entry boxes (i.e., pack side = LEFT). Here is an example snapshot of the GUI without the labels below the entry boxes:
Currently my script looks like this, with the label widgets commented out:
#!/usr/bin/python
from sys import exit
from Tkinter import *
from subprocess import Popen, PIPE
from time import sleep
from os.path import exists
import os
import time
import sys
import ttk
#Initialize Tkinter by creating Tk root widget, which is a window with a
title bar. The root widget has to be created before any other widgets.
Root = Tk()
Root.title("GUI")
class Command:
def __init__(self, func, *args, **kw):
self.func = func
self.args = args
self.kw = kw
def __call__(self, *args, **kw):
args = self.args+args
kw.update(self.kw)
self.func(*args, **kw)
#Script definitions#
def quitter():
exit(0)
#Button organization and layout#
Sub0 = Frame(Root)
Sub = Frame(Sub0)
#X mesh node
Label(Sub, text = "Create x mesh nodes").pack(side = TOP, pady = 5)
#x min text box area
v1=StringVar()
#Create entry widge to get user input, in this case a text string for the x
min mesh
Entry(Sub, textvariable=v1).pack(side = LEFT, pady = 5, padx = 5)
#Label(Sub, text = "min").pack(side = BOTTOM, pady = 5, padx = 5)
#x max text box area
v2=StringVar()
Entry(Sub, textvariable=v2).pack(side = LEFT, pady = 5, padx = 5)
#Label(Sub, text = "max").pack(side = BOTTOM, pady = 1)
#x step text box area
v3=StringVar()
Entry(Sub, textvariable=v3).pack(side = LEFT, pady = 5, padx = 5)
#Label(Sub, text = "step increment").pack(side = LEFT, pady = 1)
Sub.pack(side = TOP)
Frame(Sub0,height=1, relief = GROOVE, bg="black").pack(side = TOP, fill =
BOTH, pady= 5)
#GUI Organization#
Sub0.pack(side = TOP, padx = 10)
Button(Root, text = "Quit", command = quitter).pack(side = TOP, pady = 5)
#The window will not appear until we enter the Tkinter event loop. Script
will remain in the event loop until we close the window.
Root.mainloop()
When I uncomment the label widgets I get the following:
Can someone guide me in the right direction on how to make this happen? Or suggest a better way to implement it? Also, is there a way to control the size of the entry widgets? I'd like them to be smaller. Thank you in advance!
You can use the grid geometry manager for this:
from sys import exit
from Tkinter import *
from subprocess import Popen, PIPE
from time import sleep
from os.path import exists
import os, time, sys, ttk
#Initialize Tkinter by creating Tk root widget, which is a window with a
Root = Tk()
Root.title("VIZ TOOL")
class Command:
def __init__(self, func, *args, **kw):
self.func = func
self.args = args
self.kw = kw
def __call__(self, *args, **kw):
args = self.args+args
kw.update(self.kw)
self.func(*args, **kw)
#Script definitions#
def quitter():
exit(0)
#Button organization and layout#
Sub0 = Frame(Root)
Sub = Frame(Sub0)
#X mesh node
Label(Sub, text = "Create x mesh nodes").grid(columnspan=3)
#x min text box area
v1=StringVar()
#Create entry widge to get user input, in this case a text string for the x
Entry(Sub, textvariable=v1).grid(row=1, column=0)
Label(Sub, text = "min").grid(row=2, column=0)
#x max text box area
v2=StringVar()
Entry(Sub, textvariable=v2).grid(row=1, column=1)
Label(Sub, text = "max").grid(row=2, column=1)
#x step text box area
v3=StringVar()
Entry(Sub, textvariable=v3).grid(row=1, column=2)
Label(Sub, text = "step increment").grid(row=2, column=2)
Sub.pack(side = TOP)
Frame(Sub0,height=1, relief = GROOVE, bg="black").pack(side = TOP, fill =
BOTH, pady= 5)
#GUI Organization#
Sub0.pack(side = TOP, padx = 10)
Button(Root, text = "Quit", command = quitter).pack(side = TOP, pady = 5)
#The window will not appear until we enter the Tkinter event loop. Script
Root.mainloop()
For the size of the entries you can do something like this:
Root.option_add("*Entry.Width", 5) #10 is default
Using option add like this will override the size of all entry widgets, you can specify individual size with the width keyword on Entry(....., width = *, ...)
Related
from tkinter import *
import tkinter as tk
import random
f = 0
def test_print():
f = random.randint(0,118)
master.update_idletasks()
# creating Tk window
master = Tk()
master.minsize(600,400)
var = IntVar()
var.set(f)
# cretaing a Fra, e which can expand according
# to the size of the window
pane = Frame(master)
pane.pack(fill = BOTH, expand = True)
# button widgets which can also expand and fill
# in the parent widget entirely
# Button 1
b1 = Button(pane, text = "Click me !",
background = "red", fg = "white", command = test_print)
b1.pack(side = TOP, expand = True, fill = BOTH)
label = tk.Label(pane, textvariable = var)
label.pack(side = BOTTOM, expand = False)
# Execute Tkinter
master.mainloop()
This code runs fine but it doesn't give me a random number when i press the button. I need it to give me a random output so i can get a random element from a list. Does anybody have the answer to this?
Here it is. Now you can see that the label changes:
from tkinter import *
import tkinter as tk
import random
def test_print():
f = random.randint(0, 118)
label.configure(text=str(f))
master.update_idletasks()
# creating Tk window
master = Tk()
master.minsize(600, 400)
# cretaing a Fra, e which can expand according
# to the size of the window
pane = Frame(master)
pane.pack(fill=BOTH, expand=True)
# button widgets which can also expand and fill
# in the parent widget entirely
# Button 1
b1 = Button(pane, text="Click me !",
background="red", fg="white", command=test_print)
b1.pack(side=TOP, expand=True, fill=BOTH)
label = tk.Label(pane)
label.pack(side=BOTTOM, expand=False)
# Execute Tkinter
master.mainloop()
here is the answer
from tkinter import *
import tkinter as tk
import random
maxnumber = 118
f = random.randint(0,maxnumber)
def test_print():
master.update_idletasks()
label.configure(textvariable = var)
# creating Tk window
master = Tk()
master.minsize(600,400)
var = IntVar()
var.set(f)
# cretaing a Fra, e which can expand according
# to the size of the window
pane = Frame(master)
pane.pack(fill = BOTH, expand = True)
# button widgets which can also expand and fill
# in the parent widget entirely
# Button 1
b1 = Button(pane, text = "Click me !",
background = "red", fg = "white", command = test_print)
b1.pack(side = TOP, expand = True, fill = BOTH)
label = tk.Label(pane)
label.pack(side = BOTTOM, expand = False)
# Execute Tkinter
master.mainloop()
I'm creating a GUI in python using tkinter and am having trouble when running it. I have an entry box widget, a radiobutton widget, and a button widget. When I press the button, what I want is the user to type a number into the entry box and select an option from the list of radiobuttons. When the user presses the button, I'd like the values to be retrieved and displayed in the other frame for testing. What I get instead is when the button gets pressed, I get the error 'NoneType' object has no attribute 'get'. The error is referring to the value inside of the entry box: self.tune_entry
The code I have is as follows:
SA_main.py
import os
import tkinter as tk
from tkinter import ttk
from tkinter import font
import SA_gui
def main():
x_vals = [0,1,2,3,4]
y_vals = [0,1,2,3,4]
root = SA_gui.tk.Tk()
UI = SA_gui.Window(root, x_vals, y_vals)
root.mainloop()
if __name__ == "__main__":
main()
SA_gui.py
import os
import tkinter as tk
from tkinter import ttk
from tkinter import font
# Class to define, setup, and build the GUI
class Window:
# Dimensions of the GUI
HEIGHT = 600
WIDTH = 1200
# Colors for main layout
bg_color = "#B0E0E6"
frame_color1 = "#73B1B7"
white_color = "#FFFFFF"
def __init__(self, master, x_vals, y_vals):
# Take in the lists of files for later use
self.x_vals = x_vals
self.y_vals = y_vals
#--------------------------------------------------------------
# Define and create the window
self.master = master
master.title("Signal Analysis")
master.geometry("{}x{}".format(Window.WIDTH, Window.HEIGHT))
# Create and place the background frame
self.bg_frame = tk.Frame(self.master, bg=Window.bg_color, bd=5)
self.bg_frame.place(relwidth=1, relheight=1)
# Create the main title
self.main_title = tk.Label(self.bg_frame, text="Software Defined Radio Signal Analysis",
bg=Window.bg_color, font=("Courier", 14))
self.main_title.pack(side="top")
#--------------------------------------------------------------
# Create and place the frame for tuning
self.tune_frame = tk.Frame(self.bg_frame, bg=Window.frame_color1, bd=4)
self.tune_frame.place(relx=0.05, rely=0.1, relwidth=0.2428, relheight=0.8)
# Create and place the title for the tuning frame
self.tune_title = tk.Label(self.tune_frame, text="Tune", bg=Window.frame_color1, font=
("Courier", 11))
self.tune_title.place(relwidth=1, anchor="nw")
# Create and place the contents of the tuning frame
self.tune_cont = tk.Frame(self.tune_frame, bg=Window.white_color, bd=4)
self.tune_cont.place(relx=0.05, rely=0.05, relwidth=0.9, relheight=0.925)
#Label for frequency entry
self.tune_label = tk.Label(self.tune_cont, text='Enter carrier frequency: (kHz)',
bg=Window.white_color)
self.tune_label.place(relx=0.025, rely=0)
#Entry Box for frequency entry
self.tune_entry = tk.Entry(self.tune_cont)
self.tune_entry.place(relx=0.025, rely=0.075, relwidth=0.95, relheight=0.05)
#Label for divider
self.tune_div = ttk.Separator(self.tune_cont, orient="horizontal")
self.tune_div.place(rely=0.175, relwidth=1)
#Label for display mode
self.disp_label = tk.Label(self.tune_cont, text='Select Display:', bg=Window.white_color)
self.disp_label.place(relx=0.025, rely=0.2)
#Variable for radiobuttons
self.var = tk.IntVar(self.tune_cont).set("1")
#Radio Button for Spectral Analysis
self.SA_select = tk.Radiobutton(self.tune_cont, text="Spectral
Analysis",bg=Window.white_color, padx=20, variable=self.var, value=1)
self.SA_select.place(relx=0.025, rely=0.275)
#Radio Button for Option 2
self.opt2_select = tk.Radiobutton(self.tune_cont, text="Option 2",bg=Window.white_color,
padx=20, variable=self.var, value=2)
self.opt2_select.place(relx=0.025, rely=0.35)
#Radio Button for Option 3
self.opt3_select = tk.Radiobutton(self.tune_cont, text="Option 3",bg=Window.white_color,
padx=20, variable=self.var, value=3)
self.opt3_select.place(relx=0.025, rely=0.425)
#Button for selection
self.tune_button = ttk.Button(self.tune_cont, text="Enter", command=lambda:
self.print_selected(self.var.get(), self.tune_entry.get()))
self.tune_button.place(relx= 0.775, rely=0.9, relwidth=0.2, relheight=0.075)
#-----------------------------------------------------------------
# Create and place the frame for the plot
self.plot_frame = tk.Frame(self.bg_frame, bg=Window.frame_color1, bd=4)
self.plot_frame.place(relx=0.3428, rely=0.1, relwidth=0.6071, relheight=0.8)
# Create and place the title for the plot frame
self.plot_title = tk.Label(self.plot_frame, text="Plot", bg=Window.frame_color1, font=
("Courier", 11))
self.plot_title.place(relwidth=1, anchor="nw")
# Create and place the contents of the plot frame
self.plot_cont = tk.Frame(self.plot_frame, bg=Window.white_color, bd=4)
self.plot_cont.place(relx=0.025, rely=0.05, relwidth=0.95, relheight=0.925)
def print_selected(self, disp, freq):
if disp == 1:
disp_mode = "Spectral Analysis"
elif disp == 2:
disp_mode = "Option 2"
else:
disp_mode = "Option 3"
#Label for this test
self.prnt_label = tk.Label(self.plot_cont, text="Display: " + disp_mode + ", Center Freq: " +
freq, bg=Window.white_color)
self.prnt_label.place(relx=0.025, rely=0.2)
Any help to resolve this issue is greatly appreciated!
Consider this code:
self.var = tk.IntVar(self.tune_cont).set("1")
Anytime you do x=y().z() python assigns the return value of z() to x. Thus, in your code you're assiging the result of .set("1") to self.var. The set method is returning None so self.var is None. Thus, when you later try to call self.var.get() it's the same as doing None.get().
If you want to initialize a variable at the time of creation, there is no need to call set. Also, while it works to pass a string, if you're setting an IntVar you really ought to be setting it to an integer.
self.var = tk.IntVar(value=1)
I have a sequence of pop up windows. I intended to close the window once i have completed the desired task. I am using a "askokcancel" button to get users confirmation whether the activity has completed. The problem is, every time the user presses ok, the focus goes back to the main starting window and rest of the pop up windows goes to the background while staying active. I want to either close the pop up windows or keep the focus to the second last window. Below is my code:
import tkinter as tk
from tkinter import ttk, StringVar, messagebox
from tkinter.filedialog import askopenfilename
from mytest import *
from tkinter import *
class myclass:
def __init__(self, master):
self.master = master
self.frame1 = tk.Frame(self.master)
self.button1 = tk.Button(self.frame1, text = 'select me first', width = 25, command = self.buttonFunc)
self.button1.pack()
self.quitButton = tk.Button(self.frame1, text = 'Quit', width = 25, command = self.close_windows1)
self.quitButton.pack()
self.frame1.pack()
self.master.geometry("200x200+60+60")
def buttonFunc(self):
self.top = tk.Toplevel(self.master)
self.button2 = tk.Button(self.top,text="Select second",command=self.anotherButtonFunc)
self.button2.pack()
self.quitButton = tk.Button(self.top, text = 'Quit', width = 25, command = self.close_windows2)
self.quitButton.pack()
self.master.geometry("200x200+60+60")
def anotherButtonFunc(self):
self.top2 = tk.Toplevel(self.top)
self.newClass = myClassExt(self.top2)
def close_windows1(self):
self.master.destroy()
def close_windows2(self):
self.top.destroy()
class myClassExt():
def __init__(self, top2):
self.top3 = top2
self.frame2 = tk.Frame(self.top3)
self.button3 = tk.Button(self.frame2, text = 'select me third', width = 25, command = self.buttonFunc)
self.button3.pack()
self.quitButton = tk.Button(self.frame2, text = 'Quit', width = 25, command = self.close_windows4)
self.quitButton.pack()
self.frame2.pack()
self.top3.geometry("200x200+60+60")
def buttonFunc(self):
ok = messagebox.askokcancel(message='Press OK to Confirm?')
if not ok:
pass
else:
messagebox.showinfo("Success","Well done")
self.close_windows4()
def close_windows4(self):
self.top3.destroy()
if __name__ == "__main__":
root = tk.Tk()
myclass = myclass(root)
root.mainloop()
From this made up example, i somehow want to either close window number 2 after user presses OK or keep the focus on window 2 rather than window 1. Please guide
There is no way to close a message box, although you can easily make your own. You just have to make a new tkinter window, and set an image, title, and text, then add a close button, and return the tk window. I made a function like this myself, for this very reason. Here is the function:
def mymessage(title, text, spacing = 25, buttonText = "Close", image = None):
tk2 = Tk()
tk2.resizable(0, 0)
tk2.title(title)
if image != None:
image = Label(tk2, image = PhotoImage(file = image))
image.pack()
spacer = Frame(tk2, relief = FLAT, bd = 0, width = 200, height = 25)
spacer.pack()
label = Label(tk2, text = text)
label.pack()
button = Button(tk2, text = buttonText, width = 5, height = 1, command = tk2.destroy)
button.pack()
return tk2
After calling the function, it returns the tk window, for easy destruction.
I am new to python so I was trying to make a GUI, in that I have to place a button in a particular position.
I tried using self.nxt_form.place(x=200,y=100) instead of self.nxt_form.pack().
But the button disappeared and only the frame appeared when it ran. Can you tell me how to place the button in a particular position?
Here is the code:
import tkinter as tk
class Main_form:
def __init__(self, root,title="Simulated MTBF"):
self.root = root
self.frame = tk.Frame(self.root)
"""Button nxt_form which moves to next form"""
self.nxt_form = tk.Button(self.frame, text = 'Next Form', width = 25,command = self.new_window)
self.nxt_form.pack()
self.frame.pack()
"""command to open new window by clicking Button """
def new_window(self):
self.newWindow = tk.Toplevel(self.root)
self.app = Demo2(self.newWindow)
class Demo2:
def __init__(self, root):
self.root = root
self.frame = tk.Frame(self.root)
self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
self.quitButton.pack()
self.frame.pack()
def close_windows(self):
self.root.destroy()
def main():
root = tk.Tk()
app = Main_form(root)
root.mainloop()
if __name__ == '__main__':
main()
when i am using tkinter i used column and row to position objects
self.btn = tk.Button(self, text = "button")
self.btn.grid(row = 1, column = 1)
EDIT - expanded on information in response to comment (below)
I would make an label and change its width and height to make the spacing you need (note im a beginer at python as well so this is probly a bad way but it works)
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.create_GUI()
def create_GUI(self):
frame1 = tk.LabelFrame(self, text="frame1", width=300, height=130, bd=5)
frame1.grid(row=0, column=0, columnspan=3, padx=8)
#the frame is not needed but it is a good thing to use as can group
#parts of your interface together
self.text1 = Entry(frame1)
#note if you were not using frames would just put self here
self.text1.grid(row = 1, column = 0)
self.text2 = Label(frame1, text = "",height = 10)
self.text2.grid(row = 2 , column = 0)
self.text3 = Entry(frame1)
self.text3.grid(row = 3, column = 0)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()
Also note that you can not use pack and grid together what you could do is group your objects in different frames then use grid in one frame and pack in a different frame. I personally prefer to use grid to pack as it gives you more control over your object then pack does
I have a tkinter program:
import urllib.request
from tkinter import *
root = Tk()
root.iconbitmap(default='icon.ico')
root.wm_title('Got Skills\' Skill Tracker')
frame = Frame(width="500",height="500")
frame.pack()
def show():
name = "zezima"
page = urllib.request.urlopen('http://hiscore.runescape.com/index_lite.ws?player=' + name)
page = page.readlines()
skills = []
for line in page:
skills.append([line.decode("utf-8").replace("\n", "").split(",")])
skills = skills[0:25]
for item in skills:
toPrint = item[0][0],"-",item[0][1],"-",item[0][1],"\n"
w = Message(frame, text=toPrint)
w.pack()
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="Commands", menu=filemenu)
filemenu.add_command(label="Show Skills", command=show)
root.mainloop()
When I run the above script, it shows this (which is good):
alt text http://img708.imageshack.us/img708/8821/tkinter1.png
When I click Commands > Show Skills, it turns into this. (Linked because it's tall.) It shows the right thing, but...I can imagine you see the problem.
Two questions:
-How do I add a scrollbar to the frame, and keep the frame a fixed size? (Ideally, keep the size of the first image, add the output of show(), add a scrollbar to the first image of the program.)
-With the following code:
for item in skills:
toPrint = item[0][0],"-",item[0][1],"-",item[0][2],"\n"
w = Message(frame, text=toPrint)
w.pack()
Is that the best way to output what I'm outputting? The list (skills) looks like [[1,2,3],[4,5,6]..], and I want to display 1-2-3 on a line, 4 - 5 - 6 on a line, etc.
But, I don't want that extra line in between them like there is now, and I was wondering if how I did it is the best way to go about doing it.
To add the scroll bars, use tkinter.tix.ScrolledWindow.
To remove extra space drop the extra "\n" and display a string, not a tuple. Here is the complete code:
import urllib.request
from tkinter import *
from tkinter.tix import *
root = Tk()
root.iconbitmap(default='icon.ico')
root.wm_title('Got Skills\' Skill Tracker')
frame = Frame(width="500",height="500")
frame.pack()
swin = ScrolledWindow(frame, width=500, height=500)
swin.pack()
win = swin.window
def show():
name = "zezima"
page = urllib.request.urlopen('http://hiscore.runescape.com/index_lite.ws?player=' + name)
page = page.readlines()
skills = []
for line in page:
skills.append([line.decode("utf-8").replace("\n", "").split(",")])
skills = skills[0:25]
for item in skills:
toPrint = item[0][0],"-",item[0][1],"-",item[0][1]
w = Message(win, text=' '.join(toPrint), width=500)
w.pack()
menu = Menu(root)
root.config(menu=menu)
filemenu = Menu(menu)
menu.add_cascade(label="Commands", menu=filemenu)
filemenu.add_command(label="Show Skills", command=show)
root.mainloop()
Here's a class for scrolling frames. Just pass the window object as traditional tkinter style and use obj.frame as window for new widgets.
class ScrollableFrame:
"""
# How to use class
from tkinter import *
obj = ScrollableFrame(master,height=300 # Total required height of canvas,width=400 # Total width of master)
objframe = obj.frame
# use objframe as the main window to make widget
"""
def __init__ (self,master,width,height,mousescroll=0):
self.mousescroll = mousescroll
self.master = master
self.height = height
self.width = width
self.main_frame = Frame(self.master)
self.main_frame.pack(fill=BOTH,expand=1)
self.scrollbar = Scrollbar(self.main_frame, orient=VERTICAL)
self.scrollbar.pack(side=RIGHT,fill=Y)
self.canvas = Canvas(self.main_frame,yscrollcommand=self.scrollbar.set)
self.canvas.pack(expand=True,fill=BOTH)
self.scrollbar.config(command=self.canvas.yview)
self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion = self.canvas.bbox("all")))
self.frame = Frame(self.canvas,width=self.width,height=self.height)
self.frame.pack(expand=True,fill=BOTH)
self.canvas.create_window((0,0), window=self.frame, anchor="nw")
self.frame.bind("<Enter>", self.entered)
self.frame.bind("<Leave>", self.left)
def _on_mouse_wheel(self,event):
self.canvas.yview_scroll(-1 * int((event.delta / 120)), "units")
def entered(self,event):
if self.mousescroll:
self.canvas.bind_all("<MouseWheel>", self._on_mouse_wheel)
def left(self,event):
if self.mousescroll:
self.canvas.unbind_all("<MouseWheel>")