I have repeatedly tried, and failed, to understand where and how I should be defining the textvariable "die" in the following code. The commented lines are where I've tried assigning values, but a variety of Value or Name errors keep occurring, which leads me to believe that I don't know how to properly initialize its value.
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
#die = StringVar() # 1
def roll (int):
try:
die.set(randrange(1,int))
except ValueError:
pass
class Application(ttk.Frame):
#die = StringVar() # 2
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
#self.die = StringVar() # 3
self.createWidgets()
def createWidgets(self):
#self.die = StringVar() # 4
self.d_twoButton = ttk.Button(self, text='d2', command=roll(2)).grid()
self.d_threeButton = ttk.Button(self, text='d3', command=roll(3)).grid()
self.d_fourButton = ttk.Button(self, text='d4', command=roll(4)).grid()
self.d_sixButton = ttk.Button(self, text='d6', command=roll(6)).grid()
self.d_eightButton = ttk.Button(self, text='d8', command=roll(8)).grid()
self.d_tenButton = ttk.Button(self, text='d10', command=roll(10)).grid()
self.d_twelveButton = ttk.Button(self, text='d12', command=roll(12)).grid()
self.d_twentyButton = ttk.Button(self, text='d20', command=roll(20)).grid()
self.d_onehundredButton = ttk.Button(self, text='d100', command=roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=die)
self.resultLabel.grid()
app = Application()
app.master.title('Die Roller')
#app.die = StringVar() # 5
app.mainloop()
(I had tried to add the tags for textvariable and stringval for easier identification, but I am as of yet unable. If anyone is able to add such tags to this post, please feel free to do so.)
Spot #3 is probably the best place. You'll need to make a few additional modifications, though.
You'll have to explicitly refer to the app object in roll, to access its die attribute. Alternatively, roll should be a method of the Application class; see second code block.
command parameters must be wrapped in a lambda, if you're supplying arguments to the function you want it to call.
optional: remove all the self.d_someNumberButton = assignment bits, since they're all None and you don't use them anywhere anyway. (Hint: my_thing = Button() makes my_thing into a Button. my_thing = Button().grid() makes my_thing into None.)
Implementation with the fewest possible modifications to your original code:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
#die = StringVar() # 1
def roll (int):
try:
app.die.set(randrange(1,int))
except ValueError:
pass
class Application(ttk.Frame):
#die = StringVar() # 2
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar() # 3
self.createWidgets()
def createWidgets(self):
#self.die = StringVar() # 4
self.d_twoButton = ttk.Button(self, text='d2', command=lambda: roll(2)).grid()
self.d_threeButton = ttk.Button(self, text='d3', command=lambda: roll(3)).grid()
self.d_fourButton = ttk.Button(self, text='d4', command=lambda: roll(4)).grid()
self.d_sixButton = ttk.Button(self, text='d6', command=lambda: roll(6)).grid()
self.d_eightButton = ttk.Button(self, text='d8', command=lambda: roll(8)).grid()
self.d_tenButton = ttk.Button(self, text='d10', command=lambda: roll(10)).grid()
self.d_twelveButton = ttk.Button(self, text='d12', command=lambda: roll(12)).grid()
self.d_twentyButton = ttk.Button(self, text='d20', command=lambda: roll(20)).grid()
self.d_onehundredButton = ttk.Button(self, text='d100', command=lambda: roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
app = Application()
app.master.title('Die Roller')
#app.die = StringVar() # 5
app.mainloop()
Result:
Here, I just clicked the "d100" button, and it successfully displayed a number in the expected range.
Alternative implementation, using roll as a class method:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
class Application(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar()
self.createWidgets()
def createWidgets(self):
ttk.Button(self, text='d2', command=lambda: self.roll(2)).grid()
ttk.Button(self, text='d3', command=lambda: self.roll(3)).grid()
ttk.Button(self, text='d4', command=lambda: self.roll(4)).grid()
ttk.Button(self, text='d6', command=lambda: self.roll(6)).grid()
ttk.Button(self, text='d8', command=lambda: self.roll(8)).grid()
ttk.Button(self, text='d10', command=lambda: self.roll(10)).grid()
ttk.Button(self, text='d12', command=lambda: self.roll(12)).grid()
ttk.Button(self, text='d20', command=lambda: self.roll(20)).grid()
ttk.Button(self, text='d100', command=lambda: self.roll(100)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
def roll(self, max_value):
app.die.set(randrange(1,max_value))
app = Application()
app.master.title('Die Roller')
app.mainloop()
Alternative alternative implementation that uses a for loop to create the buttons:
from random import *
from tkinter import *
from tkinter import ttk
import tkinter as tk
class Application(ttk.Frame):
def __init__(self, master=None):
ttk.Frame.__init__(self, master)
self.grid()
self.die = StringVar()
self.createWidgets()
def createWidgets(self):
for num_sides in [2, 3, 4, 6, 8, 10, 12, 20, 100]:
ttk.Button(self, text="d{}".format(num_sides), command=lambda value=num_sides: self.roll(value)).grid()
self.resultLabel = ttk.Label(self, textvariable=self.die)
self.resultLabel.grid()
def roll(self, max_value):
app.die.set(randrange(1,max_value))
app = Application()
app.master.title('Die Roller')
app.mainloop()
Related
just started working with tkinter and i wanted to change the style of the frame but it won't. Can't figure it out so i'm asking you guys.
from tkinter import *
from tkinter import ttk
from tkinter import font
import currencyapi
class Currency():
def __init__(self, parent):
# App settings
parent.title("CoinyAPP")
icon = PhotoImage(file="icon.png")
parent.iconphoto(False, icon)
parent.eval("tk::PlaceWindow . center")
# Font settings
highlightFont = font.Font(
family='Helvetica', name='appHighlightFont', size=12, weight='bold')
# Widgets
self.frame1 = ttk.Frame(
parent, style="Frame1.TFrame").grid(row=0, column=0)
ttk.Label(self.frame1, text="Pick a base currency.", font=highlightFont).grid(
row=0, column=0, padx=48, pady=20)
ttk.Label(self.frame1, text="Pick currency to convert into.", font=highlightFont).grid(
row=0, column=2, padx=18, pady=20)
self.amount = StringVar()
currencyAmount = ttk.Entry(self.frame1, textvariable=self.amount)
currencyAmount.grid(row=1, column=1, padx=40)
self.baseCurrency = StringVar()
base = ttk.Combobox(self.frame1, textvariable=self.baseCurrency, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
base.grid(row=1, column=0)
base.current(46)
self.convertInto = StringVar()
convert = ttk.Combobox(self.frame1, textvariable=self.convertInto, justify='center',
values=list(currencyapi.currencyData['rates'].keys()))
convert.grid(row=1, column=2)
convert.current(0)
ttk.Button(self.frame1, command=self.currency_convertion,
text='Convert!').grid(row=2, column=1, padx=40, pady=15)
self.result = StringVar()
ttk.Label(self.frame1, font=highlightFont,
textvariable=self.result).grid(row=3, column=1, pady=5)
def currency_convertion(self, *args):
self.conv = currencyapi.currencyData['rates'].get(
self.convertInto.get())
self.amountNumber = self.amount.get()
self.base = currencyapi.currencyData['rates'].get(
self.baseCurrency.get())
Ans = (float(self.conv) * float(self.amountNumber)) / float(self.base)
self.result.set("%.2f" % Ans)
root = Tk()
s = ttk.Style()
s.configure("Frame1.TFrame", background='yellow',
foreground='blue')
Currency(root)
root.mainloop()
It's probably not very well written, sorry for that! Started programming few weeks ago.
Tried to put it into Currency class and outside, both didn't work.
It's possible that the problem is here:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame").grid(row=0, column=0)
The geometry manager methods (pack, grid, place) return None, so self.frame1 is evaluating to None
To fix this, declare your frame and then put it on the grid separately:
self.frame1 = ttk.Frame(parent, style="Frame1.TFrame")
self.frame1.grid(row=0, column=0)
That said, I put together a quick boilerplate app to test this and it seemed to work without issues...
"""Tkinter Boilerplate App Example"""
import tkinter as tk
from tkinter import ttk
class App(tk.Tk):
def __init__(self):
super.__init__()
self.geometry('200x200')
self.title('Stylish')
self.frame = ttk.Frame(self, style='Frame1.TFrame')
self.frame.pack(expand=True, fill=tk.BOTH) # fill available space
self.style = ttk.Style()
# note: 'foreground' doesn't appear to have any effect on a Frame
self.style.configure('Frame1.TFrame', background='pink', foreground='red')
if __name__ == '__main__':
app = App()
app.mainloop()
I want to create a label and update it with the int-value, which is updated by pressing the buttons, also in the label. I'm still new to Python and would like some help :)
import tkinter as tk
class Main(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.integer = tk.IntVar()
self.integer.set(0)
tk.Button(self, text='Quit', command=self.destroy).pack()
tk.Button(self, text='+', command=self.plus_one).pack()
tk.Button(self, text='-', command=self.take_one).pack()
self.entry0 = tk.Entry(self, textvariable=str(self.integer), justify="center", width=4)
self.entry0.pack()
def plus_one(self):
x = self.integer.get() + 1
self.integer.set(x)
def take_one(self):
x = self.integer.get() - 1
self.integer.set(x)
app = Main()
app.mainloop()
You would do this the same way you did with the Entry widget:
import tkinter as tk
class Main(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.integer = tk.IntVar()
self.integer.set(0)
tk.Button(self, text='Quit', command=self.destroy).pack()
tk.Button(self, text='+', command=self.plus_one).pack()
tk.Button(self, text='-', command=self.take_one).pack()
self.entry0 = tk.Entry(self, textvariable=str(self.integer), justify="center", width=4)
self.entry0.pack()
self.label0 = tk.Label(self, textvariable=str(self.integer))
self.label0.pack()
def plus_one(self):
x = self.integer.get() + 1
self.integer.set(x)
def take_one(self):
x = self.integer.get() - 1
self.integer.set(x)
app = Main()
app.mainloop()
As per your comments, if you are interested in having the binding at button press instead of button release, this has been already addressed here.
so i am doing some learning with modules. i am decent with tkinter after using it for 5 months or so. i can get this to work if i put my functions inside my main file. i am separating them into separate modules so i can learn how to work with modules better. so this question is more for knowledge.
I am going to have 3 files total, my main loop (example_gui.py) , my pythonic functions (example_funcs.py) , my GUI functions (more_example_funcs.py)... you can see that my issue is with using "get_text()" inside more_example_funcs.py its obvious why it doesnt work in this case. the variable is not defined inside this .py file. how would i make this work? I was told it is better way to code by having the functions inside another file(modules).
With a full scale app using Tkinter , i am going to have bunch of functions connected to entries an such that are going to be defined in the example_gui.py it would be much easier if i could put the functions for those inside more_example_funcs.py just like my example below
example_funcs.py
from Tkinter import *
import Tkinter as tk
def center(toplevel):
toplevel.update_idletasks()
w = toplevel.winfo_screenwidth()
h = toplevel.winfo_screenheight()
size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x'))
x = w/2 - size[0]/2
y = h/2 - size[1]/2
toplevel.geometry("%dx%d+%d+%d" % (size + (x, y)))
def popupmsg(msg):
popup = tk.Toplevel()
popup.title("Information Dialog")
label = Label(popup, text = msg)
label.pack(side="top", pady=10)
button = Button(popup, text = "OK", command = popup.destroy)
button.pack()
popup.grab_set()
center(popup)
popup.mainloop()
more_example_funcs.py
from Tkinter import *
import Tkinter as tk
def get_text():
print entry_one_var.get()
example_gui.py
from Tkinter import *
import Tkinter as tk
import example_funcs as EF
import more_example_funcs as MEF
class start(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
tk.Tk.title(self, "app name")
menubar = tk.Menu(container)
tk.Tk.config(self, menu=menubar)
fileMenu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="File", menu=fileMenu)
fileMenu.add_command(label="Exit", command=quit)
for F in (Page_one, Page_two, Page_three):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(Page_one)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class Page_one(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
self.controller = controller
Frame.__init__(self, parent, *args, **kwargs)
self.labels_one()
self.buttons_one()
self.entries_one()
def labels_one(self):
label1 = Label(self, text="Welcome to page one")
label1.grid()
def buttons_one(self):
button_one = Button(self, text="go to page two", command=lambda:self.controller.show_frame(Page_two))
window_one_button = Button(self, text="open popup window", command=lambda:EF.popupmsg("New window 1"))
text_one_button = Button(self, text="print entered text", command=MEF.get_text)
button_one.grid()
window_one_button.grid()
text_one_button.grid()
def entries_one(self):
entry_one_var=StringVar()
entry_one = Entry(self, textvariable= entry_one_var)
entry_one.grid()
class Page_two(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
self.controller = controller
Frame.__init__(self, parent, *args, **kwargs)
self.labels_two()
self.buttons_two()
def labels_two(self):
label2 = Label(self, text="Welcome to page two")
label2.grid()
def buttons_two(self):
button_two = Button(self, text="go to page three", command=lambda:self.controller.show_frame(Page_three))
window_two_button = Button(self, text="open popup window", command=lambda:EF.popupmsg("New window 2"))
button_two.grid()
window_two_button.grid()
class Page_three(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
self.controller = controller
Frame.__init__(self, parent, *args, **kwargs)
self.labels_three()
self.buttons_three()
def labels_three(self):
label3 = Label(self, text="Welcome to page three")
label3.grid()
def buttons_three(self):
button_three = Button(self, text="go to page one", command=lambda:self.controller.show_frame(Page_one))
window_three_button = Button(self, text="open popup window", command=lambda:EF.popupmsg("New window 3"))
button_three.grid()
window_three_button.grid()
app = start()
EF.center(app)
app.mainloop()
Make your get_text function take arguments so you can call it on any variable later.
more_example_funcs.py
from Tkinter import *
import Tkinter as tk
def get_text(var):
print var.get()
Also, make entry_one_var in Page_one a class variable using the self keyword (self.entry_one_var) since you'll need it in more than one method, then pass self.entry_one_var as an argument when you call get_text.
This is how the Page_one class will look like:
class Page_one(tk.Frame):
def __init__(self, parent, controller, *args, **kwargs):
self.controller = controller
Frame.__init__(self, parent, *args, **kwargs)
self.labels_one()
self.buttons_one()
self.entries_one()
def labels_one(self):
label1 = Label(self, text="Welcome to page one")
label1.grid()
def buttons_one(self):
button_one = Button(self, text="go to page two", command=lambda:self.controller.show_frame(Page_two))
window_one_button = Button(self, text="open popup window", command=lambda:EF.popupmsg("New window 1"))
text_one_button = Button(self, text="print entered text", command=lambda: MEF.get_text(self.entry_one_var))##
button_one.grid()
window_one_button.grid()
text_one_button.grid()
def entries_one(self):
self.entry_one_var=StringVar() #make entry_one_var class instance variable
entry_one = Entry(self, textvariable= self.entry_one_var) ##
entry_one.grid()
I hope it helps.
I would like to update a label once I press one of the buttons.
Here is my code - I added a label (caled label1), now I have two issues:
It presents some gibberish
How do I update the label with text right when the user is pressing the Browse button?
from tkinter import *
import threading
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.var = IntVar()
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
quitButton = Button(self, text="Exit", command=self.client_exit)
startButton = Button(self, text="Browse", command=self.start_Button)
label1 = Label(self, text=self.lable_1)
quitButton.grid(row=0, column=0)
startButton.grid(row=0, column=2)
label1.grid(row=1, column=0)
def client_exit(self):
exit()
def lable_1(self):
print('starting')
def start_Button(self):
def f():
print('Program is starting')
t = threading.Thread(target=f)
t.start()
root = Tk()
root.geometry("250x50")
app = Window(root)
root.title("My Program")
root.mainloop()
Use self.label['text'] to change text
(Minimal?) Working example:
import tkinter as tk
class Window(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
# tk.Frame.__init__ creates self.master so you don't have to
#self.master = master
self.init_window()
def init_window(self):
self.pack(fill=tk.BOTH, expand=1)
quit_button = tk.Button(self, text="Exit", command=root.destroy)
start_button = tk.Button(self, text="Browse", command=self.on_click)
self.label = tk.Label(self, text="Hello")
quit_button.grid(row=0, column=0)
start_button.grid(row=0, column=1)
self.label.grid(row=1, column=0, columnspan=2)
def on_click(self):
self.label['text'] = "Starting..."
root = tk.Tk()
app = Window(root)
root.mainloop()
I am having trouble figuring out how to run more than one application in a Tkinter instance. I am planning to have one main window that will call other applications to run.
I also want to have the login button set the username and password strings, and then close its own window.
I have already tried using Toplevel windows, but this limits my ability to format buttons. For example I cant use frames... Any help on the direction I need to take is greatly appreciated.
I am spinning my wheels trying to figure this out, I have looked at many different code samples and I keep getting contradictory ways to do the same thing. I am using python 3.
import tkinter as tk
import os
import json
from tkinter import Toplevel
cert = ""
username = ""
password = ""
base_url = ''
url = ''
splash_page = ''
class BuildApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.lUSER = tk.Label(self, text="Username: ").pack(side="left")
self.eUSER = tk.Entry(self)
self.eUSER.pack(side="left")
self.lPASS = tk.Label(self, text="Password: ").pack(side="left")
self.ePASS = tk.Entry(self)
self.ePASS.pack(side="left")
#ive tried command= lambda: self.setCredentials(self.eUSER.get(),self.ePASS.get())
# command = self.setCredentials(self.eUSER.get(),self.ePASS.get())
# But none if it works....
self.LOGIN = tk.Button(self, text = "Login", fg="green" )
self.LOGIN.pack(side="left")
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=self.destroy)
self.QUIT.pack(side="left")
self.mainloop()
def setCredentials(self,u,p):
username = u
password = p
print(username)
print(password)
self.destroy()
class SearchApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
print("create somethng")
class MainApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
#Build Data
self.bBuild = tk.Button(self, text="Build Data", command=self.build)
self.bBuild.pack(side="top")
#Search Data
self.bSearch = tk.Button(self, text="Search",command=self.search)
self.bSearch["text"] = "Search"
self.bSearch["command"] = self.search
self.bSearch.pack(side="top")
#quit
self.QUIT = tk.Button(self, text="QUIT", fg="red", command= root.destroy)
self.QUIT.pack(side="bottom")
def build(self):
print("Building")
root2 = tk.Tk()
buildApp = BuildApplication(master=root2)
buildApp.mainloop()
def search(self):
print("Search")
root3 = tk.Tk()
app2 = SearchApplication(master=root3)
app2.mainloop()
root = tk.Tk()
app = MainApplication(master=root)
app.master.title("fdsafds")
app.mainloop()
I modified your code:
import tkinter as tk
import os
import json
from tkinter import Toplevel
cert = ""
username = ""
password = ""
base_url = ''
url = ''
splash_page = ''
class BuildApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.lUSER = tk.Label(self, text="Username: ")
self.lUSER.pack(side="left")
self.eUSER = tk.Entry(self)
self.eUSER.pack(side="left")
self.lPASS = tk.Label(self, text="Password: ")
self.lPASS.pack(side="left")
self.ePASS = tk.Entry(self, show="*")
self.ePASS.pack(side="left")
#ive tried command= lambda: self.setCredentials(self.eUSER.get(),self.ePASS.get())
# command = self.setCredentials(self.eUSER.get(),self.ePASS.get())
# But none if it works....
self.LOGIN = tk.Button(self, text = "Login", fg="green", command=self.setCredentials )
self.LOGIN.pack(side="left")
self.QUIT = tk.Button(self, text="QUIT", fg="red", command=self.master.destroy)
self.QUIT.pack(side="left")
#self.mainloop()
def setCredentials(self):
username = self.eUSER.get()
password = self.ePASS.get()
print("username", username)
print("password", password)
self.master.destroy()
class SearchApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
print()
self.some_abel = tk.Label(self, text="create somethng")
self.some_abel.pack(side="left")
self.quitb = tk.Button(self, text = "quit", fg="green", command=self.master.destroy )
self.quitb.pack(side="left")
class MainApplication(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
#Build Data
self.bBuild = tk.Button(self, text="Build Data", command=self.build)
self.bBuild.pack(side="top")
#Search Data
self.bSearch = tk.Button(self, text="Search",command=self.search)
self.bSearch["text"] = "Search"
self.bSearch["command"] = self.search
self.bSearch.pack(side="top")
#quit
self.QUIT = tk.Button(self, text="QUIT", fg="red", command= self.master.destroy)
self.QUIT.pack(side="bottom")
def build(self):
print("Building")
root2 = tk.Toplevel()
buildApp = BuildApplication(master=root2)
def search(self):
print("Search")
root3 = tk.Toplevel()
app2 = SearchApplication(master=root3)
root = tk.Tk()
app = MainApplication(master=root)
app.master.title("fdsafds")
app.mainloop()
The main change includes using toplevel windows in build and search methods instead of Tk() ones. You should not have multiple Tk().mainloops() in one program. Its better to use toplevel windows for new windows.
I also changed setCredentials method so that it actually works and prints out username and password and destroys its window upon pressing Login. Also I added few widgets to SearchApplication to show how to make it work.
Other problem was this line (and other lines similar to this one):
self.lUSER = tk.Label(self, text="Username: ").pack(side="left")
It does not make direct trouble in this particular code, but as a result of this line, self.lUSER is None. The reason is that pack (and grid) returns None. This might be not an issue now, but later it can save you lots of headache wondering why you cant change the label self.lUSER if you wanted to.
Below is gif showing how it works. Hope it helps.