issue with tkinter messagebox - python

I'm using several tkinter messageboxes in my code. But ive noticed a problem with the showinfo messageboxes I've used in my code. Basically, I want a function to be called when the ok on the messagebox is pressed. Also, the user can choose not to proceed by just closing the messagebox. But, it looks like when I press the x icon to close the messagebox, the function is still called. Here is a minimum reproducible code to explain what i mean.
from tkinter import *
from tkinter import messagebox
root = Tk()
def func() :
Label(root,text="This is the text").pack()
msg = messagebox.showinfo("Loaded","Your saved state has been loaded")
if msg == "ok" :
func()
root.mainloop()
My question is, What should i do so that the function is not called when the x icon is pressed?

There are different types of messagebox, the one your using here is not what you actually should be using for your case. What you want is something called askyesno, or something that is prefixed by 'ask' because your code depend upon the users action. So you want to 'ask' the user, like:
from tkinter import *
from tkinter import messagebox
root = Tk()
def func() :
Label(root,text="This is the text").pack(oadx=10,pady=10)
msg = messagebox.askyesno("Loaded","Your saved state has been loaded")
if msg: #same as if msg == True:
func()
root.mainloop()
Here, askyesno like other 'ask' prefixed functions will return True or 1 if you click on the 'Yes' button, else it will return False or 0.
Also just something I realized now, showinfo, like other 'show' prefixed messagebox function, returns 'ok' either you press the button or close the window.
Some more 'ask' prefixed messageboxes ~ askokcancel, askquestion, askretrycancel, askyesnocancel. Take a look here

Related

Activate and close Tkinter Input GUI from another module

I'm new to coding, so I apologize if I'm making a really dumb mistake.
I have one module (INPUT_GUI.py) that opens a window where my user can input information, then hit a submit button.
I have another module (Error_Check.py) that I want to use to look over the inputs for errors. If there is an error, it throws up a message box "You dun goofed bud" which they can close and correct their input error (INPUT_GUI frame hasn't closed yet). The Error_Check.py should run each time the submit button is clicked.
I want to call both of these modules from Input_Master.py, which I want to close the INPUT_GUI frame if there were no errors.
Right now, when I run the Input_Master, I don't get anything. I've got a print command in there to show me the values it grabs from the Input GUI, but I just see a 0.
What am I doing wrong?
GUI_INPUT.py:
from tkinter import *
from tkinter import ttk
Input_Table = 0
def retrieve(): #returns the input values as a dictionary
global Input_Table
Input_Table={1:[inputA1.get(),inputB1.get()],2:[inputA2.get(),inputB2.get()]....}
return(Input_Table)
def Close_Input():
root.destroy()
def Input_Table_Gen():
root=Tk()
frame1=Frame(root)
frame1.pack(fill=x)
frame2=Frame(root)
frame2.pack(fill=x)
#...
frame11=Frame(root)
frame11.pack(fill=x)
inputA1=Entry(frame1,width=20)
inputA1.pack(side=LEFT,padx=5,pady=5)
inputB1=Entry(frame1,width=20)
inputB1.pack(side=LEFT,padx=5,pady=5)
#...
inputA10=Entry(frame1,width=20)
inputA10.pack(side=LEFT,padx=5,pady=5)
inputB10=Entry(frame1,width=20)
inputB10.pack(side=LEFT,padx=5,pady=5)
Submit_Button = Button(frame11,text="Submit",command=retrieve)
Submit_Button.pack()
root.mainloop()
Error_Check.py:
From GUI_INPUT import retrieve
x = {}
def Input_Errors(x)
#checks for errors, returns True if errors are found, and False if no errors are found
Input_Master.py:
import GUI_INPUT
from Error_Check import Input_Errors
GUI_INPUT.Input_Table_Gen
Error_Output = Error_Check.Input_Errors(Input_Table)
if Error_Output = True:
messagebox.showinfo("ERROR","You dun goofed, try again plz")
else:
GUI_INPUT.Close_Input

I am tying to use an event, but it doesnt register because the curser is still in the entry field (tkinter)

I have an entry field in my window and I want to type someting in the entry field,
press enter, and something happends, but it doesnt work because the curser is still in the entry field when I press enter after I typed someting
here is the code ive been using oversimpified (the for this question non important parts left out)
from tkinter import *
def some_func():
#other code I want to happen when I press enter
root = Tk()
entry_one_root = Entry(root).place(x=0, y=0)
root.mainloop()
Is there a way to fix that?
thx for your help
Is this what you're looking for ?
import tkinter as tk
root = tk.Tk()
entry = tk.Entry(tk.root)
def some_func():
...
# Bind enter key on entry to some_func
entry.bind("<Enter>", lambda event: some_func())
root.mainloop()

closing tkinter window together with messagebox error window

In my script I sometimes call my ErrorWindow class to show an error message. This creates an empty tkinter window and a messagebox error window. I either only want the messagebox window, or I want the tkinter window to close automatically when I close the error window.
I've tried two pieces of code:
class ErrorWindow:
def __init__(self,error_message):
self.error_window = tk.Tk()
messagebox.showerror("ERROR",error_message,command=self.close)
self.error_window.protocol("WM_DELETE_WINDOW", self.close)
self.error_window.mainloop()
def close(self):
self.error_window.destroy()
.
class ErrorWindow:
def __init__(self,error_message):
messagebox.showerror("ERROR",error_message) #automatically creates a tk window too
But even with the second one, the tkinter window remains after I close the messagebox.
How can I program the class so that I only have to press a button (either Ok or the X in the top right of a window) once to close all windows (whether that is one or two)?
You need to withdraw the main window:
class ErrorWindow:
def __init__(self,error_message):
if not tk._default_root: # check for existing Tk instance
error_window = tk.Tk()
error_window.withdraw()
messagebox.showerror("ERROR",error_message)
This has no business as a class. You should remake this a simple function.
You did not specify whether there is just one place or multiple places where you might want want an error message. If the latter, you can create and withdraw a tk window just once. I believe a wrapper function rather than class should be sufficient for your purposes.
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
# consider placing root to control where messagebox appears
root.withdraw()
def showerror(message):
messagebox.showerror('XYZ ERROR', message, parent=root)
To avoid possible problems, I always use an explicit master or parent for everything and never depend on _default_root.
The small function below will do the job. By setting the type you can choose for: info, warning or error message box, the default is 'Info'. You can set also the timeout, the default is 2.5 seconds.
def showMessage(message, type='info', timeout=2500):
import tkinter as tk
from tkinter import messagebox as msgb
root = tk.Tk()
root.withdraw()
try:
root.after(timeout, root.destroy)
if type == 'info':
msgb.showinfo('Info', message, master=root)
elif type == 'warning':
msgb.showwarning('Warning', message, master=root)
elif type == 'error':
msgb.showerror('Error', message, master=root)
except:
pass
Call the function as follow:
For message type 'Info' and timeout of 2.5 seconds:
showMessage('Your message')
Or by your own settings for type message 'Error' and timeout 4 seconds:
showMessage('Your message', type='error', timeout=4000)

python button combination to open a tkinter message box

im new topython 2.7 and want to know if it is possible to open a tkinter messagebox with a button combination on keyboard (Ctrl+alt+'something')
that pops up like an windows error message
import win32api
import time
import math
import Tkinter
import tkMessageBox
top = Tkinter.Tk()
def Message():
tkMessageBox.showinfo("Window", "Text")
for i in range(9000):
x = int(600+math.sin(math.pi*i/100)*500)
y = int(500+math.cos(i)*100)
win32api.SetCursorPos((x,y))
time.sleep(.01)
Yes, you can bind to control and alt characters. Bindings are fairly well documented. Here's one good source of information:
http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
As an example, to bind to ctrl-alt-x you would do this:
top.bind("<Control-Alt-x>", Message)
You can bind to a sequence of events by specifying the whole sequence. For example, if you wanted to implement a cheat code you could do something like this:
label.bind("<c><h><e><a><t>", Message)
For letters, "a" is the same as "<a>", so you can also do this:
label.bind("cheat", Message)
Here is a complete working example:
import Tkinter as tk
import tkMessageBox
def Message(event=None):
tkMessageBox.showinfo("Window", "Text")
def Cheat(event=None):
tkMessageBox.showinfo("Window", "Cheat Enabled!")
root = tk.Tk()
label = tk.Label(root, text="Press control-alt-m to see the messagebox\ntype 'cheat' to enable cheat.")
label.pack(fill="both", expand=True, padx=10, pady=100)
label.bind("<Control-Alt-x>", Message)
label.bind("<c><h><e><a><t>", Cheat)
label.focus_set()
root.mainloop()
If you want something like: Press button A, then press button B then open a Message box it is possible.
Do something like:
from Tkinter import *
import tkMessageBox
def change():
global switch
switch=True
def new_window():
if switch:
tkMessageBox.showinfo("Random name", "Correct combination")
else:
print "Not the correct order"
root = Tk()
switch = False
root.bind("<A>", change)
root.bind("<B>",new_window)
root.mainloop()
If you want more buttons then use an integer and increase it while using switches for the correct button order.
Note that you can bind key combinations as well with root.bind("<Shift-E>") for example
Edit: Now a and b keyboard button insted of tkinter buttons

Tkinter Listbox

I want to execute function with one click on listbox. This is my idea:
from Tkinter import *
import Tkinter
def immediately():
print Lb1.curselection()
top = Tk()
Lb1 = Listbox(top)
Lb1.insert(1, "Python")
Lb1.insert(2, "Perl")
Lb1.insert(3, "C")
Lb1.insert(4, "PHP")
Lb1.insert(5, "JSP")
Lb1.insert(6, "Ruby")
Lb1.pack()
Lb1.bind('<Button-1>', lambda event :immediately() )
top.mainloop()
But this function print before execute selecting...You will see what is the problrm when you run this code.
You can bind to the <<ListboxSelect>> event as described in this post: Getting a callback when a Tkinter Listbox selection is changed?
TKinter is somewhat strange in that the information does not seemed to be contained within the event that is sent to the handler. Also note, there is no need to create a lambda that simply invokes your function immediately, the function object can be passed in as shown:
from Tkinter import *
import Tkinter
def immediately(e):
print Lb1.curselection()
top = Tk()
Lb1 = Listbox(top)
Lb1.insert(1, "Python")
Lb1.insert(2, "Perl")
Lb1.insert(3, "C")
Lb1.insert(4, "PHP")
Lb1.insert(5, "JSP")
Lb1.insert(6, "Ruby")
Lb1.pack()
Lb1.bind('<<ListboxSelect>>', immediately)
top.mainloop()

Categories