I'm trying to use messagebox.showinfo to show a message when my counter reach 4.
import tkinter
from tkinter import *
global cptBalle
global cptPrise
cptBalle = 0
cptPrise = 0
cptRetrait = 0
cptManche = 1
ptsVisiteur = 0
ptsReceveur = 0
coupSurVisiteur = 0
coupSurReceveur = 0
erreurVisiteur = 0
erreurReceveur = 0
equipeAuBaton = "visiteur"
def balle():
global cptBalle
global cptPrise
cptBalle += 1
if cptBalle == 4:
messagebox.showinfo(title="Balle", message="Testtest")
cptBalle = 0
cptPrise = 0
def prise():
pass
def fausse_balle():
pass
def retrait():
pass
def balle_passee():
pass
def mauvais_lancer():
pass
def sacrifice():
pass
def simple():
pass
def double():
pass
def triple():
pass
def circuit():
pass
def atteint():
pass
def erreur():
pass
def creer_bouton():
btnBalle = Button(app, text="Balle", command=balle)
btnBalle.grid(row=1, column=0)
btnPrise = Button(app, text="Prise", command=prise)
btnPrise.grid(row=2, column=0)
btnFausse_balle = Button(app, text="Fausse balle", command=fausse_balle)
btnFausse_balle.grid(row=3, column=0)
btnRetrait = Button(app, text="Retrait", command=retrait)
btnRetrait.grid(row=4, column=0)
btnBalle_passee = Button(app, text="Balle passee", command=balle_passee)
btnBalle_passee.grid(row=5, column=0)
btnMauvais_lancer = Button(app, text="Mauvais lancer", command=mauvais_lancer)
btnMauvais_lancer.grid(row=6, column=0)
btnSacrifice = Button(app, text="Sacrifice", command=sacrifice)
btnSacrifice.grid(row=7, column=0)
btnSimple = Button(app, text="Simple", command=simple)
btnSimple.grid(row=8, column=0)
btnDouble = Button(app, text="Double", command=double)
btnDouble.grid(row=9, column=0)
btnTriple = Button(app, text="Triple", command=triple)
btnTriple.grid(row=10, column=0)
btnCircuit = Button(app, text="Circuit", command=circuit)
btnCircuit.grid(row=11, column=0)
btnAtteint = Button(app, text="Atteint", command=atteint)
btnAtteint.grid(row=12, column=0)
btnErreur = Button(app, text="Erreur", command=erreur)
btnErreur.grid(row=13, column=0)
root = tkinter.Tk()
root.title("Baseball!")
root.geometry("750x350")
app = Frame(root)
app.grid()
creer_bouton()
root.mainloop()
The first button "btnBalle" call the function "Balle()".
It works when I run it in Python IDLE but when I use PyCharm, it doesn't.
Obviously that's not your whole program, but… let's assume your real program is calling Test() multiple times, but isn't actually starting the Tk runloop anywhere, or even creating a top-level Tk object. So, any Tkinter windows you try to display will never show up. (Actually, on some platforms, like OS X, it will show up—but it shouldn't, and if it doesn't on your platform, that's not a bug.)
Why does it work in IDLE? Because IDLE itself is written in Tkinter, and the tricks it uses to allow you to use the interactive interpreter while you've got a GUI program running also allow you to get away with this. That's not something you should rely on.
I ran into the same problem when attempting to use the messagebox class.
The basis of the code was:
import tkinter as tk
tk.messagebox.showinfo( --- )
I resolved the issue by adding:
from tkinter import messagebox
and then calling:
messagebox.showinfo( --- )
Hope this helps.
Related
I have a large code where a button press is supposed to run a code that will take roughly 15 seconds to complete. Within this time I want to display a label that says "Processing, please wait" or something of that sort. However in python, the whole GUI created using tkinter will freeze and unfreeze once the procedure is over. How do I get around to doing this? I created a smaller code so that I can explain easier.
from tkinter import *
from threading import Thread
import os
import sys
import time
master = Tk()
master.geometry("500x500")
master.resizable(False,False)
def tryout():
sign2.config(text = "AAA")
for x in range(5):
print(x)
time.sleep(1)
sign2.config(text = "BBB")
for x in range(5):
print(x)
time.sleep(1)
sign2.config(text = "CCC")
def close_window():
master.destroy()
sys.exit()
sign1 = Label(master, text = "VNA GUI").grid(pady=10, padx=10)
sign2 = Label(master, text = "Choose option to continue")
sign2.grid(pady=10, padx=10, ipadx=50)
Button(master, text='Exit', command=close_window).grid(pady=10, padx=20)
butTest = Button(master, text='test', command=tryout)
butTest.grid(pady=10, padx=20)
master.mainloop( )
So in this code I expect to see 'AAA' on the label first, followed by 'BBB' at the middle of the count from 0 to 4, and then 'CCC' at the end of the final count from 0 to 4. What happens here is the GUI freezes at the beginning, the count carries on and I just see 'CCC'. How do I get around this?
There are only a few changes necessary to do that with threading.
First create a function start_tryout:
def start_tryout():
Thread(target=tryout, daemon=True).start() # deamon=True is important so that you can close the program correctly
Then create the button with the new command:
butTest = Button(master, text='test', command=start_tryout)
Then it should no longer freeze the gui and you should be able to see the label change.
You can try threading. I've made changes below to the code and tested it here, and it worked.
from tkinter import *
from threading import Thread
import os
import sys
import time
import threading # NEW
master = Tk()
master.geometry("500x500")
master.resizable(False,False)
def tryout():
sign2.config(text = "AAA")
for x in range(5):
print(x)
time.sleep(1)
sign2.config(text = "BBB")
for x in range(5):
print(x)
time.sleep(1)
sign2.config(text = "CCC")
def close_window():
master.destroy()
sys.exit()
def thread(): # NEW
threading.Thread(target=tryout).start() # NEW
sign1 = Label(master, text = "VNA GUI").grid(pady=10, padx=10)
sign2 = Label(master, text = "Choose option to continue")
sign2.grid(pady=10, padx=10, ipadx=50)
Button(master, text='Exit', command=close_window).grid(pady=10, padx=20)
butTest = Button(master, text='test', command=thread) # Changed
butTest.grid(pady=10, padx=20)
master.mainloop( )
My question is about Python 2.7 tkinter. The difficulty lies in getting all the buttons in one window, right now it opens 2 windows, one window with the size I defined, and one with all the button without a defined size.
from Tkinter import *
master = Tk()
class Calculator:
def __init__(self,master):
self.var = IntVar()
frame = Frame(master)
frame.grid()
f2 = Frame(master,width=500,height=500)
f2.grid(row=0,column=1)
def callback():
print("Hello World")
b = Button(master, text="Calc", command=callback)
b.grid()
e = Entry(master, width=10)
e.grid()
e.focus_set()
b1 = Button(master, text = "Ok", width=10, command = callback)
b1.grid(row=20, column=30)
top = Tk()
app = Calculator(top)
mainloop()
Tkinter requires exactly one instance of Tk() to start the tkinter app and one instance of mainloop() to manage the update loop.
If you call on Tk() more than once you will run into the issue of having multiple windows and things not working as you want.
If you do happen to need a 2nd or more windows then you will need to use Toplevel() to create them.
If you delete:
top = Tk()
and change:
app = Calculator(top)
to:
app = Calculator(master)
You will have everything in one window as intended.
So, I'm working on Tkinter and my goal is to when the user presses a button it opens a new window that he can insert data on database and then it populates a table again so it shows the new data inserted. The new window opens fine and data is indeed inserted, but the list is not updated and I don't know why.
Button code:
self.inserir = Button(self.container2, text="Inserir", command=lambda:self.help(tm.FazTela(bd),self.populate()))
Function code that gets the functions as a list and run them:
def help(*functions):
def func(*args, **kwargs):
return_value = None
for function in functions:
return_value = function(*args, **kwargs)
return return_value
return func
If I call the populate function before the function that generates the window it runs nicely but that's not what I want, I want to update after the user has input data.
I don't know if it helps, but here's the code of the window that opens once the button is pressed:
from Tkinter import *
from database import database as db
from database import tratamentos as tr
import tkMessageBox
class TelaMenor():
def __init__(self):
self.root = None
self.OPTIONS = []
self.cor1 = '#D32F2F'
def CloseWindow(self):
self.root.destroy()
self.root = None
def SendToTR(self,nome,valor,tipo,bd):
try:
tr.ProdutosRecieve(nome,valor,tipo,bd)
except:
tkMessageBox.showerror("Erro encontrado", "Digite valores validos!")
finally:
self.CloseWindow()
def FazTela(self,bd):
if(self.root!=None):
self.CloseWindow()
self.FazTela()
else:
self.root=Tk()
# opcoes do droplist
self.OPTIONS = [
"Tipo de produto",
"Doce",
"Salgado",
"Massa",
"Bebida",
"Outro"
]
#fim
# criacao e posicao dos widgets
info = Frame(self.root)
info.grid(sticky=N+S+W+E)
salto1 = Label(info, text=" ")
salto1.grid(row=0, column=0)
nome1 = Label(info, text="Nome:")
nome1['font']=['bold']
nome1.grid(row=1, column=1, sticky=W)
nome2 = Entry(info)
nome2["width"]=40
nome2.grid(row=2, column=1)
salto2 = Label(info, text="")
salto2.grid(row=3, column=0)
valor1 = Label(info, text="Valor:")
valor1['font']=['bold']
valor1.grid(row=4, column=1, sticky=W)
valor2 = Entry(info)
valor2["width"]=40
valor2.grid(row=5, column=1)
salto3 = Label(info, text="")
salto3.grid(row=6, column=0)
variable = StringVar(info)
variable.set(self.OPTIONS[0])
droplist = apply(OptionMenu, (info, variable) + tuple(self.OPTIONS))
droplist.grid(row=7, column=1)
salto4 = Label(info, text="")
salto4.grid(row=8, column=0)
pronto = Button(info, text="Pronto", bg=self.cor1, bd=3,command=lambda: self.SendToTR(nome2.get(),valor2.get(),variable.get(),bd))
pronto['font']=['bold']
pronto['fg']='white'
pronto.grid(row=9, column=1)
salto5 = Label(info, text="")
salto5.grid(row=10, column=1)
espaco1 = Label(info, text=" ")
espaco1.grid(row=10, column=2)
#fim
# barra de "status"
status = Label(info, text="Estado: Normal", bg="white", bd=1, relief=SUNKEN, anchor=W)
status.grid(row= 11, column=0, sticky=S+W+E, columnspan=3)
#fim
# formatacao da janela
self.root.title('Cadastro do Produto')
#root.iconbitmap(r'c:\Python27\DLLs\icon.ico')
self.root.resizable(width=False, height=False)
self.root.geometry('298x276')
self.root.protocol("WM_DELETE_WINDOW",lambda: self.CloseWindow())
self.root.mainloop()
#fim
Sorry, there are some words in portuguese.
This is a good illustration of why you shouldn't use lambda unless absolutely necessary: it makes debugging difficult. I recommend removing the use of lambda, and instead tie the button to a normal function. Doing so will make it easier to insert debugging code.
In this case, your function is running this code:
self.help(tm.FazTela(bd),self.populate())
This is the same as doing this:
a = tm.FazTela(bd)
b = self.populate()
self.help(a,b)
You also have the problem that you are creating more than one root window. In tkinter you must always have exactly one root window. Instead of creating a second instance of Tk, you need to create an instance of Toplevel.
If you want to execute code after the window has been destroyed you can use the function wait_window which will not return until the given window has closed.
I got example code were there are two windows and in the second one there's a tick box that doesn't change value when it is ticked. How can I fix this? I tried returning the value of the tickbox however that failed as well.
from tkinter import *
root = Tk()
def open_custom_gui():
custom_gui()
b = Button(root,command=open_custom_gui)
b.grid(row=1,column=0)
def custom_gui():
def getinfo():
print(var1.get())
custom= Tk()
var1 = IntVar()
tickbox_1 = Checkbutton(custom,text='TEST',variable=var1,)
tickbox_1.grid(row=0,column=0)
b = Button(custom,command=getinfo)
b.grid(row=1,column=0)
custom.mainloop()
root.mainloop()
The problem has something to do with calling Tk() twice. You can fix that by explicitly creating a second Toplevel window.
from tkinter import *
root = Tk()
def open_custom_gui():
custom_gui()
b = Button(root, command=open_custom_gui)
b.grid(row=1, column=0)
def custom_gui():
def getinfo():
print(var1.get())
custom = Toplevel() # CHANGE THIS (don't call Tk() again)
var1 = IntVar()
tickbox_1 = Checkbutton(custom, text='TEST', variable=var1)
tickbox_1.grid(row=0, column=0)
b = Button(custom, command=getinfo)
b.grid(row=1, column=0)
custom.mainloop()
root.mainloop()
Alternatively you can also fix it by specifying the second Tk instance when you create the IntVar tkinter variable:
def custom_gui():
def getinfo():
print(var1.get())
custom = Tk()
var1 = IntVar(master=custom) # ADD a "master" keyword argument
tickbox_1 = Checkbutton(custom, text='TEST', variable=var1)
tickbox_1.grid(row=0, column=0)
b = Button(custom, command=getinfo)
b.grid(row=1, column=0)
custom.mainloop()
However I would suggest using the first approach because the documentation says the following (about adding the argument to the IntVar constructor):
The constructor argument is only relevant if you’re running Tkinter with
multiple Tk instances (which you shouldn’t do, unless you really know what
you’re doing).
Take a look at the example code below. There is a main window, which calls the function fun2 to display the value of variable a (as a label w/ text). At the same time, a menu item on the main window launches a secondary window (function fun1) with two buttons. I am trying to find a way to change the value of a through these buttons.
If I do not include the global variable a = 0 (line 6), I get a "global name 'a' is not defined" error. If I do include it (as in this example), the window buttons don't have any effect on the variable (it remains a = 0). I've tried using the command global a in fun1, with no effect. I've also experimented using the same command also in fun2 but I still can't get it to work.
Any ideas? What am I doing wrong?
import Tkinter
import random
import time
from Tkinter import *
a = 0
def fun1():
win2 = Toplevel()
win2.geometry("300x300")
def var_yes():
a = 1
win2.after(500, lambda: win2.destroy())
def var_no():
a = 0
win2.after(500, lambda: win2.destroy())
button1 = Tkinter.Button(win2, text ="1", command = var_yes).pack()
button2 = Tkinter.Button(win2, text ="2", command = var_no).pack()
def fun2():
value = 0
if a == 1:
value = a
granresult = "{}".format(value)
lbl.configure(text = str(granresult))
def gui_stuff(window):
global lbl
window.configure(background="#000000")
window.geometry("700x500")
lbl = Tkinter.Label(window, height=5, anchor = "c", text="Label", bg="#000000", fg="#ffffff", font=("Helvetica", 22))
lbl.pack()
fun2()
window = Tkinter.Tk()
menubar = Menu(window)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Program", menu=filemenu)
filemenu.add_command(label="test", command=fun1)
window.config(menu=menubar)
gui_stuff(window)
window.update()
winx1 = window.winfo_rootx()
winy1 = window.winfo_rooty()
winh1 = window.winfo_height()
window.mainloop()
The global statement must be used in the function that assigns to the variable. It does not carry over into sub-functions, which is why it didn't have an effect in fun1. You have to add it to both var_yes and var_no.
What you are doing wrong is thinking that global variables are a good idea. Then not understanding how to use them. In python you create a global by assignment in the module level scope. You have done that by creating a value and calling it a
In each function which needs to write `a' you need to declare as global. See the code
import Tkinter
import random
import time
from Tkinter import *
a = 0
def fun1():
win2 = Toplevel()
win2.geometry("300x300")
def var_yes():
global a
a = 1
win2.after(500, lambda: win2.destroy())
def var_no()
global a
a = 0
win2.after(500, lambda: win2.destroy())
button1 = Tkinter.Button(win2, text ="1", command = var_yes).pack()
button2 = Tkinter.Button(win2, text ="2", command = var_no).pack()
def fun2():
global a
value = 0
if a == 1:
value = a
granresult = "{}".format(value)
lbl.configure(text = str(granresult))
def gui_stuff(window):
# the next line refers to a global which doesn't exist
global lbl
window.configure(background="#000000")
window.geometry("700x500")
lbl = Tkinter.Label(window, height=5, anchor = "c", text="Label", bg="#000000", fg="#ffffff", font=("Helvetica", 22))
lbl.pack()
fun2()
window = Tkinter.Tk()
menubar = Menu(window)
filemenu = Menu(menubar, tearoff=0)
menubar.add_cascade(label="Program", menu=filemenu)
filemenu.add_command(label="test", command=fun1)
window.config(menu=menubar)
gui_stuff(window)
window.update()
winx1 = window.winfo_rootx()
winy1 = window.winfo_rooty()
winh1 = window.winfo_height()
window.mainloop()