is there anyway to create a confirmation popup like this - python

I am trying to make a popup that can return a true or false to where it was called from when a button is pressed
```python
import kivy
def confirmation_popup(title_text):
btn1 = kivy.uix.button.Button(text="Yes")
btn2 = kivy.uix.button.Button(text="no")
btn1.bind(on_release=return True)#to the function itself
btn2.bind(on_release=return False)
Boxed_layout= kivy.uix.boxlayout.BoxLayout(orientation = "horizontal")
Boxed_layout.add_widget(btn1)
Boxed_layout.add_widget(btn2)
pop = kivy.uix.popup.Popup(title=title_text,content=Boxed_layout)
pop.open()
if confirmation_popup("are you sure you want to delete your user"):
#delete user from database```

Rather than trying to get a return from the Popup, you should just let the Popup call a method that does the confirmed action. If you define your confirmation_popup like this:
def confirmation_popup(title_text, doit):
btn1 = Button(text="Yes")
btn2 = Button(text="no")
Boxed_layout= BoxLayout(orientation = "horizontal")
Boxed_layout.add_widget(btn1)
Boxed_layout.add_widget(btn2)
pop = Popup(title=title_text,content=Boxed_layout)
btn1.bind(on_release=partial(doit, pop)) # bind to whatever action is being confiirmed
btn2.bind(on_release=pop.dismiss)
pop.open()
# a method that does the action being confirmed
def doit(popup, button):
popup.dismiss()
print('do whatever action is confirmed')
Then you can use it by:
confirmation_popup('This is a Test', doit)

Related

How to have script wait until user interacts in Tkinter?

I'm learning Python on my own and now I'm trying to learn some GUI with Tkinter. If anyone can help, I'm having trouble having the program show a greeting message and then offering options that should be picked by clicking a button. Actually, I think I've sorted out how to build it, but there's a key piece missing: I don't know how to have the program wait until the user has interacted by clicking one of the buttons.
Let's say, for instance, I create a file with a 'Window' Class (for the interface) and some functions along (Window.py):
import time
from tkinter import *
# Here I'll set each one of the the buttons' commands.
# I've referenced it before to avoid triggering a reference problem, but when I tried, I actually broke the code in three parts and used imports to link all of them.
# For simplicity's sake, however, I'll present everything in a single file in this question.
Choice = ''
def Choose1():
Choice = 1
def Choose2():
Choice = 2
def Choose3():
Choice = 3
# Here I create the object 'Window':
class Window:
def __init__(self):
self.Window = Tk()
self.Window.title = 'Interact'
self.Window.minsize = (500, 300)
# Here I'll add a label to display the messages that I want to show the user:
self.Text = Label(self.Window, text = '')
self.Text.pack()
# Aqui uma série de botões:
self.B1 = Button(self.Window, text = 'Option 1', command = Choose1)
self.B1.pack()
self.B2 = Button(self.Window, text = 'Option 2', command = Choose2)
self.B2.pack()
self.B3 = Button(self.Window, text = 'Option 3', command = Choose3)
self.B3.pack()
# Here I'll create an instance of the 'Window' object:
Example = Window()
# Here I'll create a function so that certain messages will be displayed to the user:
def Say(X):
Example.Text.configure(text = X)
Example.Text.update()
time.sleep(3) # Please ignore this. I inserted this delay so there's time for the user to read the message. I actualy have a better way to do it, but to keep it simple, let's leave it like this.
# Finally, the main part of the program:
Say('Welcome!')
Say('Which option would you like to choose?')
WaitInput() # I haven't figured out how this function would work, and that's my issue. I'd like the program to wait for the option to be chosen and only then print the following message:
Say('You've chosen option {}!'.format(Choose))
Text.mainloop()
Can anybody by any chance tell me how can I create this 'WaitInput()' function, or if something of the sort already exists in Python?
Appreciate it!
In all GUIs (in all languages) you use button to wait for input and execute some function when there are input data.
In tkinter you have to use lambda to assing function with arguments to button
self.b1 = tk.Button(self.window, text='Option 1', command=lambda:self.choose('1'))
I used after() to change text with delay and also to add buttons with delay - I used callback in say_later() to execute it with delay.
import time
import tkinter as tk
# --- classes ---
class Window:
def __init__(self):
self.window = tk.Tk()
self.window.title = 'Interact'
self.window.geometry('500x300')
#self.window.minsize = (500, 300)
self.text = tk.Label(self.window, text='')
self.text.pack()
def add_buttons(self):
self.b1 = tk.Button(self.window, text='Option 1', command=lambda:self.choose('1'))
self.b1.pack()
self.b2 = tk.Button(self.window, text='Option 2', command=lambda:self.choose('2'))
self.b2.pack()
self.b3 = tk.Button(self.window, text='Option 3', command=lambda:self.choose('3'))
self.b3.pack()
def say(self, message, callback=None):
self.text.configure(text=message)
if callback:
callback()
def say_later(self, delay, message, callback=None):
self.window.after(delay, lambda:self.say(message, callback))
def choose(self, value):
self.say("You've chosen option {}!".format(value))
# --- functions ---
# empty
# --- main ---
example = Window()
example.say('Welcome!')
example.say_later(3000, 'Which option would you like to choose?', example.add_buttons)
example.window.mainloop()

How can I return the result of a user selection via a tkinter dialog?

I'm trying to write a function that creates a tkinter dialog which presents the user with a series of selection options and requires them to select one. My issue I have is that when I press the button to close the dialog my program just hangs and doesn't proceed to the next step. I get no error message to help me debug.
Please see my code here:
import tkinter as tk
class Option():
"""
Dumnmy class for user option
"""
def __init__(self, display_name, item_name):
self.DisplayName = display_name
self.ItemName = item_name
def user_selection(options):
"""
Tkinter popup to make the user choose from a list of options
Doesn't work - crashes on exit
"""
tk_root = tk.Tk()
selection = tk.StringVar()
selection.set("1") # initial value
for option in options:
radio = tk.Radiobutton(tk_root, text=option.DisplayName, value=option.ItemName, var=selection)
radio.pack()
button = tk.Button(tk_root, text='OK', command=tk_root.destroy)
button.pack()
tk_root.mainloop()
user_choice = selection.get()
return user_choice
avaliable_options = [Option('Apple', 'apple_url'), Option('Banana', 'banana_url')]
selection = user_selection(avaliable_options)
print(selection)
I've exhausted my Google-foo on this one, can anyone advise what I've done wrong?
I have chacked your code and the problem is easy: you have to put the mainloop at the end of program, because when the compiler read these function, it doesn't compile the next code. But you can make a similar effect if you use a update function to the root.
So the code changed is the following:
import tkinter as tk
class Option():
"""
Dumnmy class for user option
"""
def __init__(self, display_name, item_name):
self.DisplayName = display_name
self.ItemName = item_name
def user_selection(options):
"""
Tkinter popup to make the user choose from a list of options
Doesn't work - crashes on exit
"""
tk_root = tk.Tk()
selection = tk.StringVar()
selection.set("1") # initial value
for option in options:
radio = tk.Radiobutton(tk_root, text=option.DisplayName, value=option.ItemName, var=selection)
radio.pack()
button = tk.Button(tk_root, text='OK', command=tk_root.destroy)
button.pack()
tk_root.update()
user_choice = selection.get()
return user_choice
avaliable_options = [Option('Apple', 'apple_url'), Option('Banana', 'banana_url')]
selection = user_selection(avaliable_options)
print(selection)
tk_root.mainloop()

'Back' Button not functioning in Python with Kivy

I am attempting to have a functioning back button to take user back to the main screen, seen below as 'Social', but cannot seem to make it function. I have tried multiple solutions that I've found on this site and some others, but haven't seemed to fix the issue yet.
I have tried multiple solutions that I've found on this site and some others, but haven't seemed to fix the issue yet. I am trying to avoid a Kivy file currently, but have accepted that at some point I'm going to have to make one.
#Main Screen
class Social(GridLayout):
title = "Welcome To PedaShield"
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.cols = 3
#FB 'Icon'
self.facebook = Button(text="Facebook")
self.facebook.bind(on_press=self.fb_signin)
self.add_widget(self.facebook)
#Button for Facebook Screen
def fb_signin(self, instance):
datastop.screen_manager.current = "FBSignin"
#Create FB sign-in screen w/ options
class FBSignin(GridLayout):
def __init__(self,**kwargs):
super().__init__(**kwargs)
self.cols = 4
if os.path.isfile("fbprev_details.txt"):
with open("fbprev_details.txt", "r") as f:
d = f.read().split(",")
prev_username = d[0]
prev_password = d[1]
else:
prev_username = ""
prev_password = ""
#row 1
self.add_widget(Label())
self.add_widget(Label(text="Username: "))
self.username = TextInput(text=prev_username, multiline=False)
self.add_widget(self.username)
self.add_widget(Label())
#row 2
self.add_widget(Label())
self.add_widget(Label(text="Password: "))
self.password = TextInput(text=prev_password, multiline=False)
self.add_widget(self.password)
self.add_widget(Label())
#row 3 include checkbox for saving signin
self.add_widget(Label())
self.signin = Button(text="Sign In")
self.signin.bind(on_press=self.signin_button)
self.add_widget(self.signin)
self.goback = Button(text="Back")
self.signin.bind(on_press=self.go_back)
self.add_widget(self.goback)
self.add_widget(Label())
#sign-in button
def signin_button(self, instance):
username = self.username.text
password = self.password.text
print("Signing in as {username}")
with open("fbprev_details.txt","w") as f:
f.write(f"{username},{password}")
#Back button
def go_back(self, instance):
print('Here')
datastop.screen_manager.current = "Social"
class PedaShield(App):
title = "PedaShield"
def build(self):
self.screen_manager = ScreenManager()
#Main screen with Social Media Options
self.Social = Social()
screen = Screen(name='Social')
screen.add_widget(self.Social)
self.screen_manager.add_widget(screen)
#Facebook sign in/option page
self.fb_signin = FBSignin()
screen = Screen(name="FBSignin")
screen.add_widget(self.fb_signin)
self.screen_manager.add_widget(screen)
return self.screen_manager
if __name__ == "__main__":
datastop = PedaShield()
datastop.run()
I don't have anything to trace, just nothing happens when the 'back' button it pressed.
You assigned function go_back to button self.signin
self.signin.bind(on_press=self.go_back)
but it has to be self.goback
self.goback.bind(on_press=self.go_back)
In old code when you click button "Sign In" then you can see two strings
Here
Signing in as {username}
First text is from function go_back. And this should give you clue where is the problem

How to change Tkinter label text on button press

I have this code, and its meant to change the text of the Instruction label when the item button is pressed. It doesn't for some reason, and I'm not entirely sure why. I've tried creating another button in the press() function with the same names and parameters except a different text.
import tkinter
import Theme
import Info
Tk = tkinter.Tk()
message = 'Not pressed.'
#Sets window Options
Tk.wm_title(Info.Title)
Tk.resizable(width='FALSE', height='FALSE')
Tk.wm_geometry("%dx%d%+d%+d" % (720, 480, 0, 0))
#Method run by item button
def press():
message = 'Button Pressed'
Tk.update()
#item button
item = tkinter.Button(Tk, command=press).pack()
#label
Instruction = tkinter.Label(Tk, text=message, bg=Theme.GUI_hl2, font='size, 20').pack()
#Background
Tk.configure(background=Theme.GUI_bg)
Tk.mainloop()
Doing:
message = 'Button Pressed'
will not affect the label widget. All it will do is reassign the global variable message to a new value.
To change the label text, you can use its .config() method (also named .configure()):
def press():
Instruction.config(text='Button Pressed')
In addition, you will need to call the pack method on a separate line when creating the label:
Instruction = tkinter.Label(Tk, text=message, font='size, 20')
Instruction.pack()
Otherwise, Instruction will be assigned to None because that is the method's return value.
You can make message a StringVar to make callback.
message = tkinter.StringVar()
message.set('Not pressed.')
You need to set message to be a textvariable for Instruction:
Instruction = tkinter.Label(Tk, textvariable=message, font='size, 20').pack()
and then
def press():
message.set('Button Pressed')

Correct way to implement a custom popup tkinter dialog box

I just started learning how to create a custom pop up dialog box; and as it turns out, the tkinter messagebox is really easy to use, but it also does not do too much. Here is my attempt to create a dialog box that will take input and then store that in the username.
My question is what is the recommended style to implement this? As Bryan Oakley suggested in this comment.
I would advise against using a global variable. Instead of having the dialog destroy itself, have it destroy only the actual widget but leave the object alive. Then, call something like inputDialog.get_string() and then del inputDialog from your main logic.
Maybe using the global variable to return my string is not the best idea, but why? And what is the suggested way? I get confused because I don't know how to trigger the getstring once the window is destroyed, and... the line about destroying the actual widget, I am not sure if he is referring to TopLevel.
The reason I ask is because I want the pop up box to be destroyed after I press the submit button; because after all, I want it to resume back to the main program, update something, etc. What should the button method send do in this case? Because the idea in this particular example is to allow the user to do it over and over, if he desires.
import tkinter as tk
class MyDialog:
def __init__(self, parent):
top = self.top = tk.Toplevel(parent)
self.myLabel = tk.Label(top, text='Enter your username below')
self.myLabel.pack()
self.myEntryBox = tk.Entry(top)
self.myEntryBox.pack()
self.mySubmitButton = tk.Button(top, text='Submit', command=self.send)
self.mySubmitButton.pack()
def send(self):
global username
username = self.myEntryBox.get()
self.top.destroy()
def onClick():
inputDialog = MyDialog(root)
root.wait_window(inputDialog.top)
print('Username: ', username)
username = 'Empty'
root = tk.Tk()
mainLabel = tk.Label(root, text='Example for pop up input box')
mainLabel.pack()
mainButton = tk.Button(root, text='Click me', command=onClick)
mainButton.pack()
root.mainloop()
Using the global statement is unnecessary in the two scenarios that come to mind.
you want to code a dialog box that can be imported to use with a main GUI
you want to code a dialog box that can be imported to use without a main GUI
code a dialog box that can be imported to use with a main GUI
Avoiding the global statement can be accomplished by passing a dictionary & key when you create an instance of a dialog box. The dictionary & key can then be associated with the button's command, by using lambda. That creates an anonymous function that will execute your function call (with args) when the button is pressed.
You can avoid the need to pass the parent every time you create an instance of the dialog box by binding the parent to a class attribute (root in this example).
You can save the following as mbox.py in your_python_folder\Lib\site-packages or in the same folder as your main GUI's file.
import tkinter
class Mbox(object):
root = None
def __init__(self, msg, dict_key=None):
"""
msg = <str> the message to be displayed
dict_key = <sequence> (dictionary, key) to associate with user input
(providing a sequence for dict_key creates an entry for user input)
"""
tki = tkinter
self.top = tki.Toplevel(Mbox.root)
frm = tki.Frame(self.top, borderwidth=4, relief='ridge')
frm.pack(fill='both', expand=True)
label = tki.Label(frm, text=msg)
label.pack(padx=4, pady=4)
caller_wants_an_entry = dict_key is not None
if caller_wants_an_entry:
self.entry = tki.Entry(frm)
self.entry.pack(pady=4)
b_submit = tki.Button(frm, text='Submit')
b_submit['command'] = lambda: self.entry_to_dict(dict_key)
b_submit.pack()
b_cancel = tki.Button(frm, text='Cancel')
b_cancel['command'] = self.top.destroy
b_cancel.pack(padx=4, pady=4)
def entry_to_dict(self, dict_key):
data = self.entry.get()
if data:
d, key = dict_key
d[key] = data
self.top.destroy()
You can see examples that subclass TopLevel and tkSimpleDialog (tkinter.simpledialog in py3) at effbot.
It's worth noting that ttk widgets are interchangeable with the tkinter widgets in this example.
To accurately center the dialog box read → this.
Example of use:
import tkinter
import mbox
root = tkinter.Tk()
Mbox = mbox.Mbox
Mbox.root = root
D = {'user':'Bob'}
b_login = tkinter.Button(root, text='Log in')
b_login['command'] = lambda: Mbox('Name?', (D, 'user'))
b_login.pack()
b_loggedin = tkinter.Button(root, text='Current User')
b_loggedin['command'] = lambda: Mbox(D['user'])
b_loggedin.pack()
root.mainloop()
code a dialog box that can be imported to use without a main GUI
Create a module containing a dialog box class (MessageBox here). Also, include a function that creates an instance of that class, and finally returns the value of the button pressed (or data from an Entry widget).
Here is a complete module that you can customize with the help of these references: NMTech & Effbot.
Save the following code as mbox.py in your_python_folder\Lib\site-packages
import tkinter
class MessageBox(object):
def __init__(self, msg, b1, b2, frame, t, entry):
root = self.root = tkinter.Tk()
root.title('Message')
self.msg = str(msg)
# ctrl+c to copy self.msg
root.bind('<Control-c>', func=self.to_clip)
# remove the outer frame if frame=False
if not frame: root.overrideredirect(True)
# default values for the buttons to return
self.b1_return = True
self.b2_return = False
# if b1 or b2 is a tuple unpack into the button text & return value
if isinstance(b1, tuple): b1, self.b1_return = b1
if isinstance(b2, tuple): b2, self.b2_return = b2
# main frame
frm_1 = tkinter.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
# the message
message = tkinter.Label(frm_1, text=self.msg)
message.pack(padx=8, pady=8)
# if entry=True create and set focus
if entry:
self.entry = tkinter.Entry(frm_1)
self.entry.pack()
self.entry.focus_set()
# button frame
frm_2 = tkinter.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
# buttons
btn_1 = tkinter.Button(frm_2, width=8, text=b1)
btn_1['command'] = self.b1_action
btn_1.pack(side='left')
if not entry: btn_1.focus_set()
btn_2 = tkinter.Button(frm_2, width=8, text=b2)
btn_2['command'] = self.b2_action
btn_2.pack(side='left')
# the enter button will trigger the focused button's action
btn_1.bind('<KeyPress-Return>', func=self.b1_action)
btn_2.bind('<KeyPress-Return>', func=self.b2_action)
# roughly center the box on screen
# for accuracy see: https://stackoverflow.com/a/10018670/1217270
root.update_idletasks()
xp = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
yp = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
geom = (root.winfo_width(), root.winfo_height(), xp, yp)
root.geometry('{0}x{1}+{2}+{3}'.format(*geom))
# call self.close_mod when the close button is pressed
root.protocol("WM_DELETE_WINDOW", self.close_mod)
# a trick to activate the window (on windows 7)
root.deiconify()
# if t is specified: call time_out after t seconds
if t: root.after(int(t*1000), func=self.time_out)
def b1_action(self, event=None):
try: x = self.entry.get()
except AttributeError:
self.returning = self.b1_return
self.root.quit()
else:
if x:
self.returning = x
self.root.quit()
def b2_action(self, event=None):
self.returning = self.b2_return
self.root.quit()
# remove this function and the call to protocol
# then the close button will act normally
def close_mod(self):
pass
def time_out(self):
try: x = self.entry.get()
except AttributeError: self.returning = None
else: self.returning = x
finally: self.root.quit()
def to_clip(self, event=None):
self.root.clipboard_clear()
self.root.clipboard_append(self.msg)
and:
def mbox(msg, b1='OK', b2='Cancel', frame=True, t=False, entry=False):
"""Create an instance of MessageBox, and get data back from the user.
msg = string to be displayed
b1 = text for left button, or a tuple (<text for button>, <to return on press>)
b2 = text for right button, or a tuple (<text for button>, <to return on press>)
frame = include a standard outerframe: True or False
t = time in seconds (int or float) until the msgbox automatically closes
entry = include an entry widget that will have its contents returned: True or False
"""
msgbox = MessageBox(msg, b1, b2, frame, t, entry)
msgbox.root.mainloop()
# the function pauses here until the mainloop is quit
msgbox.root.destroy()
return msgbox.returning
After mbox creates an instance of MessageBox it starts the mainloop,
which effectively stops the function there until the mainloop is exited via root.quit().
The mbox function can then access msgbox.returning, and return its value.
Example:
user = {}
mbox('starting in 1 second...', t=1)
user['name'] = mbox('name?', entry=True)
if user['name']:
user['sex'] = mbox('male or female?', ('male', 'm'), ('female', 'f'))
mbox(user, frame=False)
Since the object inputDialog is not destroyed, I was able to access the object attribute. I added the return string as an attribute:
import tkinter as tk
class MyDialog:
def __init__(self, parent):
top = self.top = tk.Toplevel(parent)
self.myLabel = tk.Label(top, text='Enter your username below')
self.myLabel.pack()
self.myEntryBox = tk.Entry(top)
self.myEntryBox.pack()
self.mySubmitButton = tk.Button(top, text='Submit', command=self.send)
self.mySubmitButton.pack()
def send(self):
self.username = self.myEntryBox.get()
self.top.destroy()
def onClick():
inputDialog = MyDialog(root)
root.wait_window(inputDialog.top)
print('Username: ', inputDialog.username)
root = tk.Tk()
mainLabel = tk.Label(root, text='Example for pop up input box')
mainLabel.pack()
mainButton = tk.Button(root, text='Click me', command=onClick)
mainButton.pack()
root.mainloop()
Instead of using messagebox, you can use simpledialog. It is also part of tkinter. It is like a template instead of completely defining your own class. The simpledialog solves the problem of having to add the 'Ok' and 'Cancel' buttons yourself. I myself have ran into this problem and java2s has a good example on how to use simple dialog to make custom dialogs. This is their example for a two text field and two label dialog box. It is Python 2 though so you need to change it. Hope this helps :)
from Tkinter import *
import tkSimpleDialog
class MyDialog(tkSimpleDialog.Dialog):
def body(self, master):
Label(master, text="First:").grid(row=0)
Label(master, text="Second:").grid(row=1)
self.e1 = Entry(master)
self.e2 = Entry(master)
self.e1.grid(row=0, column=1)
self.e2.grid(row=1, column=1)
return self.e1 # initial focus
def apply(self):
first = self.e1.get()
second = self.e2.get()
print first, second
root = Tk()
d = MyDialog(root)
print d.result
Source: http://www.java2s.com/Code/Python/GUI-Tk/Asimpledialogwithtwolabelsandtwotextfields.htm
I used Honest Abe's 2nd part of the code titled:
code a dialog box that can be imported to use without a main GUI
as template and made some modifications. I needed a combobox instead of entry, so I also implemented it. If you need something else, it should be fairly easy to modify.
Following are the changes
Acts as a child
Modal to the parent
Centered on top of the parent
Not resizable
Combobox instead of entry
Click cross (X) to close the dialog
Removed
frame, timer, clipboard
Save the following as mbox.py in your_python_folder\Lib\site-packages or in the same folder as your main GUI's file.
import tkinter
import tkinter.ttk as ttk
class MessageBox(object):
def __init__(self, msg, b1, b2, parent, cbo, cboList):
root = self.root = tkinter.Toplevel(parent)
root.title('Choose')
root.geometry('100x100')
root.resizable(False, False)
root.grab_set() # modal
self.msg = str(msg)
self.b1_return = True
self.b2_return = False
# if b1 or b2 is a tuple unpack into the button text & return value
if isinstance(b1, tuple): b1, self.b1_return = b1
if isinstance(b2, tuple): b2, self.b2_return = b2
# main frame
frm_1 = tkinter.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
# the message
message = tkinter.Label(frm_1, text=self.msg)
if cbo: message.pack(padx=8, pady=8)
else: message.pack(padx=8, pady=20)
# if entry=True create and set focus
if cbo:
self.cbo = ttk.Combobox(frm_1, state="readonly", justify="center", values= cboList)
self.cbo.pack()
self.cbo.focus_set()
self.cbo.current(0)
# button frame
frm_2 = tkinter.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
# buttons
btn_1 = tkinter.Button(frm_2, width=8, text=b1)
btn_1['command'] = self.b1_action
if cbo: btn_1.pack(side='left', padx=5)
else: btn_1.pack(side='left', padx=10)
if not cbo: btn_1.focus_set()
btn_2 = tkinter.Button(frm_2, width=8, text=b2)
btn_2['command'] = self.b2_action
if cbo: btn_2.pack(side='left', padx=5)
else: btn_2.pack(side='left', padx=10)
# the enter button will trigger the focused button's action
btn_1.bind('<KeyPress-Return>', func=self.b1_action)
btn_2.bind('<KeyPress-Return>', func=self.b2_action)
# roughly center the box on screen
# for accuracy see: https://stackoverflow.com/a/10018670/1217270
root.update_idletasks()
root.geometry("210x110+%d+%d" % (parent.winfo_rootx()+7,
parent.winfo_rooty()+70))
root.protocol("WM_DELETE_WINDOW", self.close_mod)
# a trick to activate the window (on windows 7)
root.deiconify()
def b1_action(self, event=None):
try: x = self.cbo.get()
except AttributeError:
self.returning = self.b1_return
self.root.quit()
else:
if x:
self.returning = x
self.root.quit()
def b2_action(self, event=None):
self.returning = self.b2_return
self.root.quit()
def close_mod(self):
# top right corner cross click: return value ;`x`;
# we need to send it a value, otherwise there will be an exception when closing parent window
self.returning = ";`x`;"
self.root.quit()
It should be quick and easy to use. Here's an example:
from mbox import MessageBox
from tkinter import *
root = Tk()
def mbox(msg, b1, b2, parent, cbo=False, cboList=[]):
msgbox = MessageBox(msg, b1, b2, parent, cbo, cboList)
msgbox.root.mainloop()
msgbox.root.destroy()
return msgbox.returning
prompt = {}
# it will only show 2 buttons & 1 label if (cbo and cboList) aren't provided
# click on 'x' will return ;`x`;
prompt['answer'] = mbox('Do you want to go?', ('Go', 'go'), ('Cancel', 'cancel'), root)
ans = prompt['answer']
print(ans)
if ans == 'go':
# do stuff
pass
else:
# do stuff
pass
allowedItems = ['phone','laptop','battery']
prompt['answer'] = mbox('Select product to take', ('Take', 'take'), ('Cancel', 'cancel'), root, cbo=True, cboList=allowedItems)
ans = prompt['answer']
print(ans)
if (ans == 'phone'):
# do stuff
pass
elif (ans == 'laptop'):
# do stuff
pass
else:
# do stuff
pass
import tkinter
import tkinter.ttk as ttk
class MessageBox(object):
def __init__(self, msg, b1, b2, parent, cbo, cboList):
root = self.root = tkinter.Toplevel(parent)
root.title('Choose')
root.geometry('100x100')
root.resizable(False, False)
root.grab_set() # modal
self.msg = str(msg)
self.b1_return = True
self.b2_return = False
# if b1 or b2 is a tuple unpack into the button text & return value
if isinstance(b1, tuple): b1, self.b1_return = b1
if isinstance(b2, tuple): b2, self.b2_return = b2
# main frame
frm_1 = tkinter.Frame(root)
frm_1.pack(ipadx=2, ipady=2)
# the message
message = tkinter.Label(frm_1, text=self.msg)
if cbo: message.pack(padx=8, pady=8)
else: message.pack(padx=8, pady=20)
# if entry=True create and set focus
if cbo:
self.cbo = ttk.Combobox(frm_1, state="readonly", justify="center", values= cboList)
self.cbo.pack()
self.cbo.focus_set()
self.cbo.current(0)
# button frame
frm_2 = tkinter.Frame(frm_1)
frm_2.pack(padx=4, pady=4)
# buttons
btn_1 = tkinter.Button(frm_2, width=8, text=b1)
btn_1['command'] = self.b1_action
if cbo: btn_1.pack(side='left', padx=5)
else: btn_1.pack(side='left', padx=10)
if not cbo: btn_1.focus_set()
btn_2 = tkinter.Button(frm_2, width=8, text=b2)
btn_2['command'] = self.b2_action
if cbo: btn_2.pack(side='left', padx=5)
else: btn_2.pack(side='left', padx=10)
# the enter button will trigger the focused button's action
btn_1.bind('<KeyPress-Return>', func=self.b1_action)
btn_2.bind('<KeyPress-Return>', func=self.b2_action)
# roughly center the box on screen
# for accuracy see: https://stackoverflow.com/a/10018670/1217270
root.update_idletasks()
root.geometry("210x110+%d+%d" % (parent.winfo_rootx()+7,
parent.winfo_rooty()+70))
root.protocol("WM_DELETE_WINDOW", self.close_mod)
# a trick to activate the window (on windows 7)
root.deiconify()
def b1_action(self, event=None):
try: x = self.cbo.get()
except AttributeError:
self.returning = self.b1_return
self.root.quit()
else:
if x:
self.returning = x
self.root.quit()
def b2_action(self, event=None):
self.returning = self.b2_return
self.root.quit()
def close_mod(self):
# top right corner cross click: return value ;`x`;
# we need to send it a value, otherwise there will be an exception when closing parent window
self.returning = ";`x`;"
self.root.quit()
Tkinter simpledialog maybe useful for this problem.
Example usage
import tkinter as tk
name = tk.simpledialog.askstring("Title", "Message")
SOURCE:
https://python-course.eu/tkinter/dialogs-in-tkinter.php
There are different approaches available in tkiner
Waits
Buttontext
Body
class_
icon
baseclass
unresponsive root
MessageBox
True
False
False
False
True
False
True
Dialog
True
True
True
True
True
False
True
SimpleDialog
False
True
False
True
False
True
False
DialogClass
True
False
True
False
True
True
True
waits: waits for dialog to be destroyed.
buttontext: custom naming of Buttons
Body: intended to be costumized
class_: XSystem's may benefit from it.
icon: Custom icon
baseclass: intended as baseclass
All examples was initially wrote by Fredrik Lundh (R.I.P.) and can be found in the standard library
Dialog
import tkinter as tk
from tkinter.dialog import Dialog
def test():
d = Dialog(None, {'title': 'File Modified',
'text':
'File "Python.h" has been modified'
' since the last time it was saved.'
' Do you want to save it before'
' exiting the application.',
'bitmap': 'questhead',
'default': 0,
'strings': ('Save File',
'Discard Changes',
'Return to Editor')})
print(d.num)
root = tk.Tk()
tk.Button(root, text='Test', command=test).pack()
root.mainloop()
SimpleDialog
import tkinter as tk
from tkinter import simpledialog
class MessageBox(simpledialog.SimpleDialog):
def __init__(self, master,**kwargs):
simpledialog.SimpleDialog.__init__(self,master,**kwargs)
def done(self,num):
print(num)
self.num = num
self.root.destroy()
def test():
'SimpleDialog does not wait or return a result'
'You can retrieve the value by overwriting done or by MessageBox.num'
MessageBox(
root,title='Cancel',text='Im telling you!',class_=None,
buttons=['Got it!','Nah'], default=None, cancel=None)
root = tk.Tk()
tk.Button(root, text='Test', command=test).pack()
root.mainloop()
DialogClass
class MessageBox(simpledialog.Dialog):
def __init__(self, master,**kwargs):
simpledialog.Dialog.__init__(self,master,**kwargs)
def body(self, master):
'''create dialog body.
return widget that should have initial focus.
This method should be overridden, and is called
by the __init__ method.
'''
pass
def validate(self):
'''validate the data
This method is called automatically to validate the data before the
dialog is destroyed. By default, it always validates OK.
'''
return 1 # override
def apply(self):
'''process the data
This method is called automatically to process the data, *after*
the dialog is destroyed. By default, it does nothing.
'''
pass # override

Categories

Resources