Message Box in Python - python

Is there a UI library to create a message box or input box in python?

Your best bet is the tkMessageBox module, which should work on all systems (as Python will typically come with Tkinter).
If you can restrict yourself to a specific operating system, better choices might be available.

Simple message boxes and input boxes can be created using EasyGui, a small library using Tkinter, which Python comes with.
You can get EasyGui here: http://easygui.sourceforge.net/

I've heard good things about wx python, which is also multi-platform.

from Tkinter
import *
import os
class Dialog(Toplevel):
def __init__(self, parent, title = None):
Toplevel.__init__(self, parent)
self.transient(parent)
if title:
self.title(title)
self.parent = parent
self.result = None
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
self.buttonbox()
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
#
# construction hooks
def body(self, master):
# create dialog body. return widget that should have
# initial focus. this method should be overridden
pass
def buttonbox(self):
# add standard button box. override if you don't want the
# standard buttons
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
w.pack(side=LEFT, padx=5, pady=5)
w = Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side=LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok)
self.bind("<Escape>", self.cancel)
box.pack()
#
# standard button semantics
def ok(self, event=None):
if not self.validate():
self.initial_focus.focus_set() # put focus back
return
self.withdraw()
self.update_idletasks()
self.apply()
self.cancel()
def cancel(self, event=None):
# put focus back to the parent window
self.parent.focus_set()
self.destroy()
#
# command hooks
def validate(self):
return 1 # override
def apply(self):
pass # override

Related

How to avoid destroying data when using tkinter Toplevel parent/child windows?

How do I pass data between parent and child windows and preserve data/unique IDs?
If I use the destroy() method for closing a child window, associated values are destroyed too, even when the dictionary that I send values to was initiated with the parent. Clicking on the Get child1config button after destroying the child window gives the error:
_tkinter.TclError: invalid command name ".!child1.!entry"
So, I don't destroy. Is it recommended to withdraw and deiconify many child windows?
How do I refer to the child window (and associated values) from parent window? Am I doing it correctly?
import tkinter as tk
class parent(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.dic={}
self.dic["var"]=['default']
self.title("Parent")
self.button1=tk.Button(self,text="open child1", command = self.open_child1, width=20)
self.button1.grid(row=0,column=0, padx=5, pady=5)
self.button2=tk.Button(self,text="Get child1 config", command = self.get_child1_value, width=20)
self.button2.grid(row=0,column=1, padx=5, pady=5)
self.label1 = tk.Label(self, text="", width=10)
self.label1.grid(row=0,column=2, sticky='ew')
self.child1_from_parent=child1(self)
self.child1_from_parent.withdraw()
def open_child1(self):
self.child1_from_parent.deiconify()
def get_child1_value(self):
self.label1.config(text=(self.dic["var"][0]+' \n'+self.child1_from_parent.child1_entry.get()))
class child1(tk.Toplevel):
def __init__(self,master):
tk.Toplevel.__init__(self, master)
self.frame = tk.Frame(self)
self.title("Child")
self.label1 = tk.Label(self, text="Config 1", width=10)
self.label1.grid(row=0,column=0)
self.child1_entry = tk.Entry(self, width=10)
self.child1_entry.grid(row=0, column=1, padx=5, pady=5)
self.child1_entry.insert ( tk.END, self.master.dic['var'][0])
self.child1_entry.bind('<Return>', self.update_value)
self.button4=tk.Button(self,text="Close", command = self.close_child1, width=20)
self.button4.grid(row=0,column=2, padx=5, pady=5)
self.button5=tk.Button(self,text="destroy", command = self.destroy_child1, width=20)
self.button5.grid(row=0,column=3, padx=5, pady=5)
def update_value(self, event):
self.master.dic["var"][0]=self.master.child1_from_parent.child1_entry.get()
def close_child1(self):
self.withdraw()
def destroy_child1(self):
self.destroy()
def main():
parent().mainloop()
if __name__ == '__main__':
main()
My program will grow, so I am looking for expandability. Classes 'seems' like a good idea. I have a parent tkinter window running with live data, and I will open/navigate to different child windows to perform different functions while the main window is running, accessible, and receiving data from child windows.
The code you have can be changed fairly easily to fix the problem. Tkinter supports something called "Variable Classes" — see The Variable Classes (BooleanVar, DoubleVar, IntVar, StringVar) — which are very handy for storing and passing around data within tkinter apps. In particular, Entry widgets support storing their contents in one (see Entry widget options) simply by passing one to it via the textvariable= keyword argument when its created. Once that's done, the widgets current (or last) value can be retrieved at any time whether the Entry still exists or not.
Below is a modified version of your code with the modifications needed to create and use one to pass information that's put into the widget in the child window back to its parent. I've indicated the most important changes with # ALL CAPS COMMENTS. Also note that I have also reformatted your code so it follows the PEP 8 - Style Guide for Python Code recommendations and is more readable. I strongly suggest you read and follow these guidelines.
import tkinter as tk
class Parent(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.dic = {}
self.dic['var'] = ['default']
self.dic['child1_value'] = tk.StringVar(value='') # ADDED.
self.title("Parent")
self.button1 = tk.Button(self, text="open Child1",
command=self.open_child1, width=20)
self.button1.grid(row=0, column=0, padx=5, pady=5)
self.button2 = tk.Button(self, text="Get Child1 config",
command=self.get_child1_value, width=20)
self.button2.grid(row=0, column=1, padx=5, pady=5)
self.label1 = tk.Label(self, text="", width=10)
self.label1.grid(row=0, column=2, sticky='ew')
self.Child1_from_parent = Child1(self)
self.Child1_from_parent.withdraw()
def open_child1(self):
self.Child1_from_parent.deiconify()
def get_child1_value(self):
self.label1.config(text=self.dic['var'][0] + '\n' +
self.dic['child1_value'].get()) # CHANGED.
class Child1(tk.Toplevel):
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.frame = tk.Frame(self)
self.title("Child")
self.label1 = tk.Label(self, text="Config 1", width=10)
self.label1.grid(row=0, column=0)
# ADDED `textvariable=` keyword argument.
self.child1_entry = tk.Entry(self, width=10,
textvariable=master.dic['child1_value'])
self.child1_entry.grid(row=0, column=1, padx=5, pady=5)
self.child1_entry.insert(tk.END, self.master.dic['var'][0])
self.child1_entry.bind('<Return>', self.update_value)
self.button4=tk.Button(self, text="Close", command=self.close_child1, width=20)
self.button4.grid(row=0, column=2, padx=5, pady=5)
self.button5=tk.Button(self, text="destroy", command=self.destroy_child1,
width=20)
self.button5.grid(row=0, column=3, padx=5, pady=5)
def update_value(self, event):
self.master.dic['var'][0] = self.master.Child1_from_parent.child1_entry.get()
def close_child1(self):
self.withdraw()
def destroy_child1(self):
self.destroy()
def main():
Parent().mainloop()
if __name__ == '__main__':
main()
If I understand your question correctly then this code may help.
It is a minimal demonstration of a one parent many children implementation.
All data and micro changes to each child are maintained after closing child.
Keyboard short-cuts give access to all children and parent
Parent is accessible while child is active.
Real exit is via gate keeper dialog from messagebox.
Creating children is easy and open ended.
import tkinter as tk
from tkinter.messagebox import askyesno
def flexx(m, r = 0, c = 0, rw = 1, cw = 1):
if r != None:
m.rowconfigure(r, weight = rw)
if c != None:
m.columnconfigure(c, weight = cw)
class child(tk.Toplevel):
def __init__(self, master, title, key):
super().__init__(master)
self.transient(master)
self.title(title)
flexx(self)
self.protocol('WM_DELETE_WINDOW', self.toggle)
self.bind('<Escape>', self.toggle)
self.bind(key, self.toggle)
def toggle(self, event = None):
'''toggle child on|off'''
if self.winfo_viewable():
self.withdraw()
else:
self.deiconify()
self.focus_force()
class parent(tk.Tk):
def __init__(self, title, icon = None):
super().__init__()
self.title(title)
flexx(self)
self.protocol('WM_DELETE_WINDOW', self.closer)
self.bind('<Escape>', self.closer)
if icon:
self.iconbitmap(default = icon)
self.withdraw()
def maker(self, title, key, geom):
anon = child(self, title, key)
# Connect parent and child
self.bind(key, anon.toggle)
anon.geometry(geom)
return anon
def closer(self, event = None):
if askyesno(
title = 'Confirm', message = 'Really',
detail = 'Close Program?', default = 'no'):
self.destroy()
if __name__ == '__main__':
the = parent('The Parent', icon = None) # icon = '.\\Icons\\Py-006.ico')
w,h,x,y = 500, 500, 100, 50
the.geometry(f'{w}x{h}+{x}+{y}')
the.boy = the.maker('harri', '<Control-h>', f'200x200+{x+w+5}+{y}')
the.girl = the.maker('suzie', '<Control-s>', f'200x200+{x+w+5}+{y+235}')
# make all other children
# inter-connect all children
the.girl.bind('<Control-h>', the.boy.toggle)
the.boy.bind('<Control-s>', the.girl.toggle)
the.deiconify()
the.mainloop( )

Login and show menu items by if

I'm trying to create a login with a tkinter Entry.
Compare the input with the password and if it is correct you are supposed to get access to more stuff in the menu bar.
If I understand correctly I need to update the window in order for the menu to update, but I cant figure out how.
And the variable "moberg" don't seems to update to True. Might be that one is global(?) and the other one belongs to a class. But I cant figure out how to make that work either.
Here is a sample of what I've done so far.
from tkinter import *
moberg="no"
class PCMsyntax(Frame):
def update():
print("updated") #only for visual, remove later
app.mainloop.after(1, update)
def __init__(self, master):
super().__init__(master)
self.pack(fill=BOTH, expand=True)
self.initUI()
def initUI(self):
menubar = Menu(self.master)
self.master.config(menu=menubar)
syntaxMenu = Menu(menubar, tearoff=False)
submenu = Menu(syntaxMenu)
syntaxMenu.add_cascade(label='Arithmetic Exp', underline=0, command='')
syntaxMenu.add_cascade(label='Assign & Compare', underline=0, command='')
syntaxMenu.add_separator()
syntaxMenu.add_cascade(label='Math', menu=submenu, underline=0)
submenu.add_command(label="abs()", command='')
if moberg == True:
syntaxMenu.add_cascade(label='No public access', menu=submenu, underline=0)
submenu.add_command(label="onlyForLabTech()")
menubar.add_cascade(label="Syntax", underline=0, menu=syntaxMenu)
menubar.add_cascade(label="Login", underline=0, command=self.onLogin)
def onLogin(self):
self.newWindow = Toplevel(self.master)
self.app = Password(self.newWindow)
class Password():
def __init__(self, master):
self.master = master
self.frame = Frame(self.master)
self.pwd = Entry(self.master, width=30, bg="whitesmoke", foreground="whitesmoke")
self.pwd.pack()
self.verifyButton = Button(self.frame, text = 'Verify', width = 25, command = self.verify_password)
self.verifyButton.pack()
self.frame.pack()
def verify_password(self):
user_entry = self.pwd.get()
if str(user_entry) == "test":
moberg=True
print(moberg) #only for visual, remove later
PCMsyntax.update
self.master.destroy()
else:
moberg=False
print(moberg) #only for visual, remove later
self.master.destroy()
def main():
root = Tk()
root.geometry("560x600")
app = PCMsyntax(master=root)
app.mainloop()
if __name__ == '__main__':
main()
You could achieve something like what you're looking for with the below:
from tkinter import *
class App:
def __init__(self, root):
self.root = root
self.public = Frame(self.root, borderwidth=1, relief="solid") #public, visible frame
self.hidden = Frame(self.root, borderwidth=1, relief="solid") #hidden, private frame
self.label1 = Label(self.public, text="This text and everything over here is public.") #this is inside the public frame and so is visible
self.entry1 = Entry(self.public) #so is this
self.label2 = Label(self.hidden, text="This text and everything over here is hidden and only appears after login.") #this one is in the hidden frame and so is private before login
self.button1 = Button(self.public, text="Login", command=self.command) #this is in the public frame
self.public.pack(side="left", expand=True, fill="both") #we pack the public frame on the left of the window
self.label1.pack() #then we pack all the widgets for both frames here and below
self.entry1.pack()
self.label2.pack()
self.button1.pack()
def command(self): #whenever the login button is pressed this is called
if self.button1.cget("text") == "Login" and self.entry1.get() == "password": #we check if the button is in login state or not and if the password is correct
self.hidden.pack(side="right", expand=True, fill="both") #if it is we pack the hidden frame which makes it and it's contents visible
self.button1.configure({"text": "Logout"}) #we then set the button to a logout state
elif self.button1.cget("text") == "Logout": #if the button is in logout state
self.hidden.pack_forget() #we pack_forget the frame, which removes it and it's contents from view
self.button1.configure({"text": "Login"}) #and then we set the button to login state
root = Tk()
App(root)
root.mainloop()
This is fairly self explanatory and where it isn't I've explained what's happening.
This is just one way of many of achieving what it is you're looking for.
I'd also like to point out that login systems are complicated and if you're looking to use this for anything serious or as a package to sell then the way I have done this is not secure.
I'd recommend looking at other ways people handle sensitive information in tkinter.

Having some trouble clearing a textbox - tkinter - Python

I've read a few threads all over the internet regarding clearing a text box on tkinter. Basically everyone says it's simple:
text.delete("1.0", END)
However, perhaps it has something to do with the way I structured it, or the way I'm calling it, but for some reason, this does not work for me. It simply does nothing.
I've tried re-positioning the def, and re-writing the text.delete("1.0", END) in a number of ways, most of which lead me to other errors, but I cannot seem to get this to work.
Ultimately, what I'm trying to accomplish is that when I click a button, the text box will clear, before populating with new information.
Below is my code.
from tkinter import *
from PIL import Image, ImageTk
import functions
class MainWindow(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self):
self.parent.title("pyTicket")
# TOOLBAR ####################################################
toolbar = Frame(self.parent, bd=1, relief=RAISED)
self.img = Image.open("Icons\startupcheck.png")
eimg = ImageTk.PhotoImage(self.img)
startupButton = Button(toolbar, text="Re-Check ", image=eimg, compound="left", relief=RAISED, command=self.StartUpChecker)
startupButton.image = eimg
startupButton.pack(side=RIGHT, padx=2, pady=2)
toolbar.pack(side=TOP, fill=X)
self.parent.config(menu=menubar)
self.pack(anchor=N, side=TOP, fill=X, expand=False)
# TOOLBAR ####################################################
# TEXTBOX ####################################################
self.textbox = Text(self, wrap="word", height=5)
self.textbox.pack(side="bottom", fill="both", expand=True)
self.textbox.tag_configure("TextBox", foreground="#b22222")
self.pack(anchor=S, side=BOTTOM, fill=BOTH, expand=True)
# TEXTBOX ####################################################
# Functions ###################################################
def StartUpChecker(self):
self.clear_text()
functions.StartUpChecker()
def clear_text(self):
self.textbox.delete("1.0", END)
class TextRedirector(object):
def __init__(self, widget, tag="stdout"):
self.widget = widget
self.tag = tag
def write(self, str):
self.widget.configure(state="normal")
self.widget.insert("end", str, (self.tag,))
self.widget.configure(state="disabled")
def main():
root = Tk()
#Width X Height
root.geometry("500x300+300+300")
root.update()
root.minsize(400,200)
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
You don't appear to actually use the TextRedirector class in the code you posted, but if you're using it in your actual code, note that its .write() method leaves the textbox in a disabled state - which prevents ALL modifications, even those resulting from code instead of direct user action. Your .clear_text() method needs to temporarily enable the textbox so that you can modify it, exactly as .write() does.

Tkinter: How to distinguishing between long and short button click

i am trying to achieve this behaviour: When user clicks the button for a shorter time the program runs the first method, which lets say adds one. However, when user keeps the button pressed for a longer time the program runs the second method, which opens a dialog window. The only solution which came to my mind was using time thread.
The problem is that the program is acting really strangely.Sometimes (not always that's also weird) when the dialog pops up my computer kind of freezez(not exactly, the processes are running). I am able to move with my mouse but I am not able to click or write anything with my keyboard.
Here is a code:
from Tkinter import *
import threading
import os
class Dialog(Toplevel):
def __init__(self, parent, title = None):
Toplevel.__init__(self, parent)
self.transient(parent)
if title:
self.title(title)
self.parent = parent
self.result = None
body = Frame(self)
self.initial_focus = self.body(body)
body.pack(padx=5, pady=5)
#self.buttonbox()
self.grab_set()
if not self.initial_focus:
self.initial_focus = self
self.protocol("WM_DELETE_WINDOW", self.cancel)
self.geometry("+%d+%d" % (parent.winfo_rootx()+50,
parent.winfo_rooty()+50))
self.initial_focus.focus_set()
self.wait_window(self)
#
# construction hooks
def body(self, master):
# create dialog body. return widget that should have
# initial focus. this method should be overridden
pass
def buttonbox(self):
# add standard button box. override if you don't want the
# standard buttons
box = Frame(self)
w = Button(box, text="OK", width=10, command=self.ok, default=ACTIVE)
w.pack(side=LEFT, padx=5, pady=5)
w = Button(box, text="Cancel", width=10, command=self.cancel)
w.pack(side=LEFT, padx=5, pady=5)
self.bind("<Return>", self.ok)
self.bind("<Escape>", self.cancel)
box.pack()
#
# standard button semantics
def ok(self, event=None):
if not self.validate():
self.initial_focus.focus_set() # put focus back
return
self.withdraw()
self.update_idletasks()
self.apply()
self.cancel()
def cancel(self, event=None):
# put focus back to the parent window
self.parent.focus_set()
self.destroy()
#
# command hooks
def validate(self):
return 1 # override
def apply(self):
pass # override
class MyDialog(Dialog):
def body(self, master):
master.grid_columnconfigure(0, weight=1)
self.e1 = Entry(master)
self.e1.grid(column=0,row=0,columnspan = 4)
self.buttons = {}
self.buttons['previous'] = Button(master,text =u'/')
self.buttons['previous'].grid(column=0,row =1,columnspan = 2)
self.buttons['next'] = Button(master,text =u'*')
self.buttons['next'].grid(column=2,row =1,columnspan = 2)
self.buttons['minus'] = Button(master,text =u'-')
self.buttons['minus'].grid(column=3,row =2)
self.buttons['plus'] = Button(master,text =u'+')
self.buttons['plus'].grid(column=3,row =3)
self.buttons['enter'] = Button(master,text =u'Enter')
self.buttons['enter'].grid(column=3,row =4,rowspan = 2)
self.buttons['zero'] = Button(master,text =u'0')
self.buttons['zero'].grid(column=0,row =5)
self.buttons['del'] = Button(master,text =u'←')
self.buttons['del'].grid(column=1,row =5)
rows = range(4,1,-1)
columns = range(0,3)
i = 1
for row in rows:
for column in columns:
Button(master,text = i).grid(row= row,column = column)
i+=1
return self.e1 # initial focus
def leftClick():
print 'add one'
def longerClick(): #if the timer ends this will run
d = MyDialog(master) #create dialog
print 'longerClick'
def handleButtonPress(event):
global t
t = threading.Timer(0.8,longerClick) #setTimer
t.start()
print t
def handleButtonRelease(event): #here is a problem probably
global t
t.cancel()
leftClick()
master = Tk()
t = None
master.geometry('{}x{}'.format(300, 300))
button = Button(master, text = 'Stlac')
button.pack()
button.bind('<ButtonPress-1>',handleButtonPress)
button.bind('<ButtonRelease-1>',handleButtonRelease)
mainloop()
So when button is pressed I setup timer. When user releases the button before timer ends, the timer is canceled.When not, longerClick method runs.
If you know where the problem is I would really aprecciate your help. Also if you know a better way how to detect longer button press that would also help me. I have read that it is possible in PYQT although I have to use Tkinter.

Blocking Input Dialog Box

How can I get a blocking modal input dialog box in standard Python?
I need the user to input a value before the code can proceed.
Here is some not-working test code, but the idea is that I should be able to call MyDialog from anywhere in the script, so this is just a simplified example.
import tkinter
class MyDialog:
def __init__(self, prompt):
self.top = tkinter.Toplevel()
tkinter.Label(self.top, text=prompt).pack()
self.e = tkinter.Entry(self.top)
self.e.pack(padx=5)
tkinter.Button(self.top, text="OK", command=self.ok).pack(pady=5)
def ok(self):
self.top.destroy()
return self.e.get()
root = tkinter.Tk()
userName = MyDialog('Enter your name')
tkinter.Label(root, text="Hello {}".format(userName)).pack()
root.mainloop()
The dialog should not only disable the master window, but block whatever code called it. And it should be able to pass the value back to the calling code.
The solution requires two critical pieces. First, use grab_set to block all events in the other window (or, more correctly, send all events to the dialog window). Second, use wait_window to prevent the method from returning until the dialog has been destroyed.
That being said, you shouldn't be using it like in your example. You need to have the mainloop running before you create the window. It might work OK on some platforms, but in general you shouldn't expect your GUI to behave properly until mainloop is running.
Here's a simple example:
import Tkinter as tk
class MyDialog(object):
def __init__(self, parent, prompt):
self.toplevel = tk.Toplevel(parent)
self.var = tk.StringVar()
label = tk.Label(self.toplevel, text=prompt)
entry = tk.Entry(self.toplevel, width=40, textvariable=self.var)
button = tk.Button(self.toplevel, text="OK", command=self.toplevel.destroy)
label.pack(side="top", fill="x")
entry.pack(side="top", fill="x")
button.pack(side="bottom", anchor="e", padx=4, pady=4)
def show(self):
self.toplevel.grab_set()
self.toplevel.wait_window()
value = self.var.get()
return value
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.button = tk.Button(self, text="Click me!", command=self.on_click)
self.label = tk.Label(self, text="", width=40)
self.label.pack(side="top", fill="x")
self.button.pack(padx=20, pady=20)
def on_click(self):
result = MyDialog(self, "Enter your name:").show()
self.label.configure(text="your result: '%s'" % result)
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()

Categories

Resources