I need a tkinter button to open only one Toplevel
but I tried using a counter that changes to 2 when one Toplevel is made and a if loop so it checks if the counter is 1, (it will make a Toplevel window if its 1)
but when I run the program I can make many windows by clicking the button multiple times
I think the solution of using a counter doesn't work
def menu_window(self): # this is in a class
self.frame4 = tk.Frame(self.master, padx=30, pady=30)
self.frame4.grid()
Counter = 1 ### COUNTER
button2 = tk.Button(self.frame4, text="Review your Quiz", command=lambda: PreviewQuiz(self.master, self.frame4,
Counter))
button2.grid(row=3, column=2, padx=40, pady=15, ipadx=28)
button3 = tk.Button(self.frame4, text=" Start your Quiz ")
button3.grid(row=4, column=2, padx=40, pady=5, ipadx=30)
class PreviewQuiz:
def __init__(self, master, frame4, Counter):
if Counter == 1: # CHECK IF COUNTER IS 1
self.master = master
self.review_q = tk.Toplevel(self.master)
self.frame5 = tk.Frame(self.master, padx=50, pady=20)
self.frame5.grid()
self.Counter = 2 # SET COUNTER TO 2
Just disable the button when the user clicks on it and enable it only when the top-level is closed.
Here is an example taken from the code you provided in your newest post:
import tkinter as tk
class Run:
def __init__(self, master):
self.master = master
self.button = tk.Button(master, text="TopLevel", command=self.make_new)
self.button.pack()
def make_new(self):
self.button['state'] = 'disabled'
new = tk.Toplevel(self.master)
lbl = tk.Label(new, text='only one topLevel')
lbl.pack()
new.protocol("WM_DELETE_WINDOW", lambda : self.button.configure(state='normal') or new.destroy()) # or make a method to change the state
master1 = tk.Tk()
i = Run(master1)
master1.mainloop()
Your code does not run, which makes it difficult to debug. There are however a few things:
When you assingn a value to counter in menu_window() you end the value with a ".", which makes it a float, not an integer.
You call PreviewQuiz with the counter argument, but when you update the counter you do it to an instance variable of PreviewQuiz, not of menu_window() class so next time you call PreviewQuiz you will still use 1.0.
Related
I am quite new with Tkinter and am trying to create a new window using this script while keeping the current window but i am get the error
_init_() missing 1 required positional argument: 'parent'. I am not really sure what the reason is but I am assuming that the command function for my button isn't working the way I want it.
The script currently looks something like this:
from tkinter import simpledialog
from tkinter import *
class Additional(simpledialog.Dialog):
def body(self, master):
#input fields
Label(master, text="Picture 3 Path:").grid(row=1)
#input fields for tags
#add as needed
self.e1 = Entry(master)
self.e1.grid(row=1, column=1, ipadx=150)
return self.e1 # initial focus
def apply(self):
first = self.e1.get()
self.ttag1 = (first)
class Initial(simpledialog.Dialog):
def body(self, master):
#input fields for username and passwords
Label(master, text="Usernames:").grid(row=1),
self.e1 = Entry(master)
self.b1 = Button(master, text = "Add More", bg= 'grey', command= Additional)
self.b1.grid(row=6, column=2, ipadx=75)
self.e1.grid(row=1, column=1, columnspan=2, ipadx=50)
return self.e1 # initial focus
def apply(self):
first = self.e1.get()
self.tag1 = (first)
root = tk.Tk()
root.withdraw()
d = Initial(root)
toor = tk.Tk()
toor.withdraw()
I have tried changing it up but it seems that it's not working right. Any ideas?
When calling the Additional class through the button command, you are not specifying what the parent root should be, and therefore the class fails to initiate. You can solve this by passing the master using a lambda
self.b1 = Button(master, text="Add More", bg='grey', command=lambda: Additional(master))
I am trying to write a script that will ask a word in English and then show its meaning. I am able to ask the question but the answer window doesn't show up. Code I wrote so far as below. In second window, it starts like a new page. How can I modify it? Now, it shows the label but buttons doesn't seem.
from tkinter import *
class Application(Frame):
def __init__(self, master):
"""Initialize the Frame"""
Frame.__init__(self, master)
self.grid()
self.button_clicks = 0 # count the number of button clicks
self.create_widgets()
def root_close(self):
global root
root.destroy()
self.button_clicky()
def create_widgets(self):
"""Button displays number of clicks"""
if clicker % 2 == 0:
self.soru = Label(self, text="Kelime: " + kelime)
self.soru.grid(row=0, column=0, columnspan=2, sticky=W)
self.btn_submit = Button(self, text="Submit", command=self.root_close)
self.btn_submit.grid(row=3, column=1, sticky=W)
else:
self.cevap = Label(self, text="Kelimenin türkçe anlamları:\n" + anlam)
self.cevap.grid(row=0, column=0, columnspan=2, sticky=W)
self.btn_okay = Button(self, text="Bildim", command=self.dogru)
self.btn_submit.grid(row=3, column=0, sticky=W)
self.btn_okay = Button(self, text="Bilemedim", command=self.yanlis)
self.btn_submit.grid(row=3, column=2, sticky=W)
def button_clicky(self):
global clicker
clicker += 1
def dogru(self):
#will do stuff
self.root_close()
def yanlis(self):
self.root_close()
clicker = 0
kelime = "apple"
anlam = "elma"
root = Tk()
root.title("Ask word")
root.geometry("200x85")
app = Application(root)
root.mainloop()
So what I get from your question is that you have the first window with the Kelime question, and you want to open up another window with the else clause in your create_widgets() function once you click the submit button. The problem here is that when you are running root_close(), you're essentially terminating the whole program (the program runs because the root is on a loop created by root.mainLoop()). If you want to open one window when you close the other, check out Closing current window when opening another window
.
I am new to python and tkinter and I have decided that I will make a stopwatch.
I have gooled alot and find many useful information, but I still haven't found how to display value of a function in tkinter. Here is my current code:
import time
from tkinter import*
import os
root = Tk()
def clock(event):
second = 0
minute = 0
hour = 0
while True:
time.sleep(0.99)
second +=1
print(hour,":",minute,":",second)
return
def stop(event):
time.sleep(1500)
def clear(event):
os.system('cls')
button1 = Button(root, text="Start")
button2 = Button(root, text="Stop")
button3 = Button(root, text="Clear")
button1.bind("<Button-1>", clock)
button2.bind("<Button-1>", stop)
button3.bind("<Button-1>", clear)
button1.grid(row=2, column=0, columnspan=2)
button2.grid(row=2, column=2, columnspan=2)
button3.grid(row=2, column=4, columnspan=2)
root.mainloop()
I am aware that the code isn't perefect yet(especially the functions stop and clear).
You might consider using callback functions (i.e. call to your function when something happens — when clicking a button for example):
Quoting portions of Tkinter Callbacks:
In Tkinter, a callback is Python code that is called by Tk when
something happens. For example, the Button widget provides a command
callback which is called when the user clicks the button. You also use
callbacks with event bindings.
You can use any callable Python object as a callback. This includes
ordinary functions, bound methods, lambda expressions, and callable
objects. This document discusses each of these alternatives briefly.
...
To use a function object as a callback, pass it directly to Tkinter.
from Tkinter import *
def callback():
print "clicked!"
b = Button(text="click me", command=callback)
b.pack()
mainloop()
It's unclear from your sample code which function's value you want to display.
Regardless, a good way to do accomplish something like that in tkinter is by creating instances of its StringVar Variable class and then specifying them as the textvariable option of another widget. After this is done, any changes to the value of the StringVar instance will automatically update the associated widget's text.
The code below illustrates this:
import os
import time
import tkinter as tk
class TimerApp(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master=None)
self.grid()
self.create_widgets()
self.elapsed = 0
self.refresh_timer()
self.after_id = None # used to determine and control if timer is running
def create_widgets(self):
self.timer = tk.StringVar()
self.timer.set('')
self.timer_label = tk.Label(self, textvariable=self.timer)
self.timer_label.grid(row=1, column=2)
self.button1 = tk.Button(self, text="Start", command=self.start_clock)
self.button1.grid(row=2, column=0, columnspan=2)
self.button2 = tk.Button(self, text="Stop", command=self.stop_clock)
self.button2.grid(row=2, column=2, columnspan=2)
self.button3 = tk.Button(self, text="Clear", command=self.clear_clock)
self.button3.grid(row=2, column=4, columnspan=2)
def start_clock(self):
self.start_time = time.time()
self.after_id = self.after(1000, self.update_clock)
def stop_clock(self):
if self.after_id:
self.after_cancel(self.after_id)
self.after_id = None
def clear_clock(self):
was_running = True if self.after_id else False
self.stop_clock()
self.elapsed = 0
self.refresh_timer()
if was_running:
self.start_clock()
def update_clock(self):
if self.after_id:
now = time.time()
delta_time = round(now - self.start_time)
self.start_time = now
self.elapsed += delta_time
self.refresh_timer()
self.after_id = self.after(1000, self.update_clock) # keep updating
def refresh_timer(self):
hours, remainder = divmod(self.elapsed, 3600)
minutes, seconds = divmod(remainder, 60)
self.timer.set('{:02d}:{:02d}:{:02d}'.format(hours, minutes, seconds))
app = TimerApp()
app.master.title('Timer')
app.mainloop()
What I want to get: change of checkbox state changes the state of the Entry widget from 'disabled' into 'normal'. (checkbox off = Entry disabled, checkbox on = Entry normal).
My problem is that I don't know how to access and update the state of entry.
My code:
from tkinter import *
from tkinter import ttk
class App(Frame):
def __init__(self, master):
ttk.Frame.__init__(self, master, padding='20')
self.grid()
self.create_checkbox()
self.create_entry()
def create_checkbox(self):
self.limit = BooleanVar()
Checkbutton(self,
text='Limit length',
variable= self.limit,
command= self.state_update,
).grid(row=1, column=1, sticky=W)
def create_entry(self):
self.entry_low = StringVar()
Entry(self,
width=6,
textvariable=self.entry_low,
state='disabled',
).grid(row=1, column=2, sticky=W)
def state_update(self):
self.entry_low.config(state="normal") #THIS OBVIOUSLY DOES NOT WORK
root = Tk()
root.title("Lottery")
app = App(root)
root.mainloop()
I'm beginner, so I'd be especially grateful for simple solutions.
Save a reference to the entry widget, then call the configure method. To make things easy, give your checkbutton the values for the states. That isn't strictly necessary, you can use a boolean and then translate that to the appropriate state.
def create_checkbox(self):
self.limit = StringVar(value="normal")
checkbutton = Checkbutton(..., onvalue="normal", offvalue="disabled", ...)
checkbutton.grid(...)
def create_entry(self):
self.entry_low = StringVar()
self.entry = Entry(self,
width=6,
textvariable=self.entry_low,
state='disabled',
)
self.entry.grid(row=1, column=2, sticky=W)
def state_update(self):
self.entry.config(state="normal") #THIS OBVIOUSLY DOES NOT WORK
Note: you need to call grid in a second step. grid(...) (as well as place) returns None. If you do x=Entry(...).grid(...), x will always be None.
I'm looking for a way to create elements dynamically in Tkinter. For example, say the user enters 5, I'd like a loop to create 5 radio buttons and entries next to them.
Here's a simple example to get you started:
import Tkinter as tk
class ButtonBlock(object):
def __init__(self, master):
self.master = master
self.button = []
self.button_val = tk.IntVar()
entry = tk.Entry()
entry.grid(row=0, column=0)
entry.bind('<Return>', self.onEnter)
def onEnter(self, event):
entry = event.widget
num = int(entry.get())
for button in self.button:
button.destroy()
for i in range(1, num+1):
self.button.append(tk.Radiobutton(
self.master, text=str(i), variable=self.button_val, value=i,
command=self.onSelect))
self.button[-1].grid(sticky='WENS', row=i, column=0, padx=1, pady=1)
def onSelect(self):
print(self.button_val.get())
if __name__ == '__main__':
root = tk.Tk()
ButtonBlock(root)
root.mainloop()
There's nothing special about widgets. You create them in a loop the same way you would create any other object:
for i in range(5):
r = tk.Radiobutton(...)
r.pack(...) # or .grid(...)
# if you need to reference these buttons later,
# save them in a list
self.buttons.append(r)