Related
I am making this PDF tool, and I want the buttons to be disabled until a file or files are successfully imported. This is what the app looks like at the launch:
Right after running the callback for the import files button, the active state looks like this:
I want the colors of the buttons to turn maroon instead of the original grey. They only turn back to maroon once you hover the mouse over them. Any thoughts for how to fix this? Here is the callback for the import button:
def import_callback():
no_files_selected = False
global files
files = []
try:
ocr_button['state'] = DISABLED
merge_button['state'] = DISABLED
status_label.pack_forget()
frame.pack_forget()
files = filedialog.askopenfilenames()
for f in files:
name, extension = os.path.splitext(f)
if extension != '.pdf':
raise
if not files:
no_files_selected = True
raise
if frame.winfo_children():
for label in frame.winfo_children():
label.destroy()
make_import_file_labels(files)
frame.pack()
ocr_button['state'] = ACTIVE
merge_button['state'] = ACTIVE
except:
if no_files_selected:
status_label.config(text='No files selected.', fg='blue')
else:
status_label.config(text='Error: One or more files is not a PDF.', fg='red')
status_label.pack(expand='yes')
import_button = Button(root, text='Import Files', width=scaled(20), bg='#5D1725', bd=0, fg='white', relief='groove',
command=import_callback)
import_button.pack(pady=scaled(50))
I know this was asked quite a while ago, so probably already solved for the user. But since I had the exact same problem and do not see the "simplest" answer here, I thought I would post:
Just change the state from "active" to "normal"
ocr_button['state'] = NORMAL
merge_button['state'] = NORMAL
I hope this helps future users!
As I understand you right you want something like:
...
ocr_button['state'] = DISABLED
ocr_button['background'] = '#*disabled background*'
ocr_button.bind('<Enter>', lambda e:ocr_button.configure(background='#...'))
ocr_button.bind('<Leave>', lambda e:ocr_button.configure(background='#...'))
merge_button['state'] = DISABLED
merge_button['background'] = '#*disabled background*'
merge_button.bind('<Enter>', lambda e:ocr_button.configure(background='#...'))
merge_button.bind('<Leave>', lambda e:ocr_button.configure(background='#...'))
...
...
ocr_button['state'] = ACTIVE
ocr_button['background'] = '#*active background*'
ocr_button.unbind('<Enter>')
ocr_button.unbind('<Leave>')
merge_button['state'] = ACTIVE
merge_button['background'] = '#*active background*'
merge_button.unbind('<Enter>')
merge_button.unbind('<Leave>')
...
If there are any errors, since I wrote it out of my mind or something isnt clear, let me know.
Update
the following code reproduces the behavior as you stated. The reason why this happens is how tkinter designed the standart behavior. You will have a better understanding of it if you consider style of ttk widgets. So I would recommand to dont use the automatically design by state rather write a few lines of code to configure your buttons how you like, add and delete the commands and change the background how you like. If you dont want to write this few lines you would be forced to use ttk.Button and map a behavior you do like
import tkinter as tk
root = tk.Tk()
def func_b1():
print('func of b1 is running')
def disable_b1():
b1.configure(bg='grey', command='')
def activate_b1():
b1.configure(bg='red', command=func_b1)
b1 = tk.Button(root,text='B1', bg='red',command=func_b1)
b2 = tk.Button(root,text='disable', command=disable_b1)
b3 = tk.Button(root,text='activate',command=activate_b1)
b1.pack()
b2.pack()
b3.pack()
root.mainloop()
I've wrote this simple app that I think could help all to reproduce the problem.
Notice that the state of the button when you click is Active.
#!/usr/bin/python3
import sys
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
class Main(ttk.Frame):
def __init__(self, parent, *args, **kwargs):
super().__init__()
self.parent = parent
self.init_ui()
def cols_configure(self, w):
w.columnconfigure(0, weight=0, minsize=100)
w.columnconfigure(1, weight=0)
w.rowconfigure(0, weight=0, minsize=50)
w.rowconfigure(1, weight=0,)
def get_init_ui(self, container):
w = ttk.Frame(container, padding=5)
self.cols_configure(w)
w.grid(row=0, column=0, sticky=tk.N+tk.W+tk.S+tk.E)
return w
def init_ui(self):
w = self.get_init_ui(self.parent)
r = 0
c = 0
b = ttk.LabelFrame(self.parent, text="", relief=tk.GROOVE, padding=5)
self.btn_import = tk.Button(b,
text="Import Files",
underline=1,
command = self.on_import,
bg='#5D1725',
bd=0,
fg='white')
self.btn_import.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
self.parent.bind("<Alt-i>", self.switch)
r +=1
self.btn_ocr = tk.Button(b,
text="OCR FIles",
underline=0,
command = self.on_ocr,
bg='#5D1725',
bd=0,
fg='white')
self.btn_ocr["state"] = tk.DISABLED
self.btn_ocr.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
r +=1
self.btn_merge = tk.Button(b,
text="Merge Files",
underline=0,
command = self.on_merge,
bg='#5D1725',
bd=0,
fg='white')
self.btn_merge["state"] = tk.DISABLED
self.btn_merge.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
r +=1
self.btn_reset = tk.Button(b,
text="Reset",
underline=0,
command = self.switch,
bg='#5D1725',
bd=0,
fg='white')
self.btn_reset.grid(row=r, column=c, sticky=tk.N+tk.W+tk.E,padx=5, pady=5)
b.grid(row=0, column=1, sticky=tk.N+tk.W+tk.S+tk.E)
def on_import(self, evt=None):
self.switch()
#simulate some import
self.after(5000, self.switch())
def switch(self,):
state = self.btn_import["state"]
if state == tk.ACTIVE:
self.btn_import["state"] = tk.DISABLED
self.btn_ocr["state"] = tk.NORMAL
self.btn_merge["state"] = tk.NORMAL
else:
self.btn_import["state"] = tk.NORMAL
self.btn_ocr["state"] = tk.DISABLED
self.btn_merge["state"] = tk.DISABLED
def on_ocr(self, evt=None):
state = self.btn_ocr["state"]
print ("ocr button state is {0}".format(state))
def on_merge(self, evt=None):
state = self.btn_merge["state"]
print ("merge button state is {0}".format(state))
def on_close(self, evt=None):
self.parent.on_exit()
class App(tk.Tk):
"""Main Application start here"""
def __init__(self, *args, **kwargs):
super().__init__()
self.protocol("WM_DELETE_WINDOW", self.on_exit)
self.set_style()
self.set_title(kwargs['title'])
Main(self, *args, **kwargs)
def set_style(self):
self.style = ttk.Style()
#('winnative', 'clam', 'alt', 'default', 'classic', 'vista', 'xpnative')
self.style.theme_use("clam")
def set_title(self, title):
s = "{0}".format('Simple App')
self.title(s)
def on_exit(self):
"""Close all"""
if messagebox.askokcancel(self.title(), "Do you want to quit?", parent=self):
self.destroy()
def main():
args = []
for i in sys.argv:
args.append(i)
kwargs = {"style":"clam", "title":"Simple App",}
app = App(*args, **kwargs)
app.mainloop()
if __name__ == '__main__':
main()
I'm new to python. I'm trying to set up a GUI with a main window and a modal window to receive the database credentials. The main window has to be in the background when the modal window appears and the user should not interact with it. Actually the application should terminate in case the user fails to provide a valid username and password. I'm presenting part of the code here. What I get is the main window (the modal window does not appear at all) and I can't do anything but shut the program down - not directly; only through visual studio.
'''
import tkinter as tk
class login:
def checkDbCredentials(self, user, password):
if (len(user)<4 or len(password)<4):
return 0
return 1
def ok(self):
us = self.user.get()
pw = self.password.get()
if self.checkDbCredentials(us, pw)==0:
tk.messagebox.showinfo("Error", "Username and Password do not match")
sys.exit(0)
self.dic['user']=us
self.dic['pass']=pw
self.win2.destroy()
def cancel(self, event=None):
self.parent.focus_set()
self.destroy()
def widgets(self):
x = self.win2.winfo_screenwidth()
y = self.win2.winfo_screenheight()
xx = int((x-270)/2)
yy = int((y-85)/2)
geo = "270x85+" + str(xx) + "+" + str(yy)
self.win2.geometry(newGeometry=geo)
self.tempLab= tk.Label(self.win2, text="Username:", pady=5)
self.tempLab1 = tk.Label(self.win2, text="Password:")
self.iuser = tk.Entry(self.win2, textvariable = self.user, width=30)
self.ipass = tk.Entry(self.win2, textvariable = self.password, width=30, show="*")
self.tempLab.grid(column=0, row=0)
self.tempLab1.grid(column=0, row=1)
self.iuser.grid(column=1, row=0)
self.ipass.grid(column=1, row=1)
self.bt = tk.Button(self.win2, text="Submit", command=lambda: self.ok())
self.bt.grid(column=0, row=2, columnspan=2, pady=5)
self.win2.bind("<Return>", self.ok)
self.win2.bind("<Escape>", self.cancel)
def __init__(self, dic, parent):
self.win2 = tk.Toplevel(parent)
self.parent=parent
self.dic = dic
self.user = tk.StringVar()
self.password = tk.StringVar()
self.win2.overrideredirect(1)
self.widgets()
self.win2.transient(parent)
self.win2.grab_set()
self.win2.protocol("WM_DELETE_WINDOW", self.cancel)
self.parent.wait_window(self.win2)
And the main class code is the following:
import tkinter as tk
from tkinter import ttk, X, Y, BOTH
from tkinter import messagebox
import sys
import login
class mainWindow:
def connect(bt, fr):
notImplementedYet()
def notImplementedYet():
msg = tk.messagebox
msg.showinfo("Warning", "Not Implemented yet!")
btX = 20
btY = 5
btSunken = '#aec2c2' # sunken button color
btRaised = '#85adad' # normal button color
rw = 0 # starting row for buttons
cl = 0 # starting column
dbCredentials = {"user":"", "pass":""}
win = tk.Tk()
win.title("Title")
win.geometry(newGeometry="1366x700+00+00")
win.iconbitmap(bitmap="bitmap.ico")
fr1 = tk.Frame(win, width=1366, height=50, background='beige')
fr1.grid(column=cl, row=rw, rowspan=5)
fr2 = tk.Frame(win)
fr2.grid(column=0, row=1)
lb2 = tk.Label(fr2, text="frame 2", background=btRaised)
btConnect = tk.Button(fr1, text="Connect", background = btRaised ,command=lambda: connect(btConnect, fr1), width=btX, height=btY)
btConnect.grid(column=0, row=0)
log = login.login(dbCredentials, win)
win.wait_window(log.win2)
print(dbCredentials)
win.mainloop()
win = mainWindow()
The question is why is the modal window not appearing? I've tried placing the 'wait_window' in the other class as well but it's still not working.
After browsing path of image i wanna show image on next window in python using Tk library but image is not showing in next window. please take a look on my code below and give answer Thanks.
import tkinter as tk
from tkinter import filedialog as fd
a=""
str1 = "e"
class Browse(tk.Frame):
""" Creates a frame that contains a button when clicked lets the user to select
a file and put its filepath into an entry.
"""
def __init__(self, master, initialdir='', filetypes=()):
super().__init__(master)
self.filepath = tk.StringVar()
self._initaldir = initialdir
self._filetypes = filetypes
self._create_widgets()
self._display_widgets()
def _create_widgets(self):
self._entry = tk.Entry(self, textvariable=self.filepath, font=("bold", 10))
a=self._entry
self._button = tk.Button(self, text="Browse...",bg="red",fg="white", command=self.browse)
self._classify=tk.Button(self,text="Classify",bg="red",fg="white", command=self.classify)
self._label=tk.Label(self, text="IMAGE CLASSIFICATION USING DEEP LERAINING.", bg="blue", fg="white",height=3, font=("bold", 14))
def _display_widgets(self):
self._label.pack(fill='y')
self._entry.pack(fill='x', expand=True)
self._button.pack(fill='y')
self._classify.pack(fill='y')
def retrieve_input(self):
#str1 = self._entry.get()
#a=a.replace('/','//')
print (str1)
def classify(self):
newwin = tk.Toplevel(root)
newwin.geometry("500x500")
label = tk.Label(newwin, text="Classification", bg="blue", fg="white",height=3, font=("bold", 14))
label.pack()
canvas = tk.Canvas(newwin, height=300, width=300)
canvas.pack()
my_image = tk.PhotoImage(file=a, master=root)
canvas.create_image(150, 150, image=my_image)
newwin.mainloop()
def browse(self):
""" Browses a .png file or all files and then puts it on the entry.
"""
self.filepath.set(fd.askopenfilename(initialdir=self._initaldir,
filetypes=self._filetypes))
if __name__ == '__main__':
root = tk.Tk()
labelfont = ('times', 10, 'bold')
root.geometry("500x500")
filetypes = (
('Portable Network Graphics', '*.png'),
("All files", "*.*")
)
file_browser = Browse(root, initialdir=r"C:\Users",
filetypes=filetypes)
file_browser.pack(fill='y')
root.mainloop()
Your global variable a which stores the path of the image is not getting updated. You need to explicitly do it. Below is the code that works. Have a look at the browse() function.
import tkinter as tk
from tkinter import filedialog as fd
a=""
str1 = "e"
class Browse(tk.Frame):
""" Creates a frame that contains a button when clicked lets the user to select
a file and put its filepath into an entry.
"""
def __init__(self, master, initialdir='', filetypes=()):
super().__init__(master)
self.filepath = tk.StringVar()
self._initaldir = initialdir
self._filetypes = filetypes
self._create_widgets()
self._display_widgets()
def _create_widgets(self):
self._entry = tk.Entry(self, textvariable=self.filepath, font=("bold", 10))
a = self._entry
self._button = tk.Button(self, text="Browse...",bg="red",fg="white", command=self.browse)
self._classify=tk.Button(self,text="Classify",bg="red",fg="white", command=self.classify)
self._label=tk.Label(self, text="IMAGE CLASSIFICATION USING DEEP LERAINING.", bg="blue", fg="white",height=3, font=("bold", 14))
def _display_widgets(self):
self._label.pack(fill='y')
self._entry.pack(fill='x', expand=True)
self._button.pack(fill='y')
self._classify.pack(fill='y')
def retrieve_input(self):
#str1 = self._entry.get()
#a=a.replace('/','//')
print (str1)
def classify(self):
global a
newwin = tk.Toplevel(root)
newwin.geometry("500x500")
label = tk.Label(newwin, text="Classification", bg="blue", fg="white",height=3, font=("bold", 14))
label.pack()
canvas = tk.Canvas(newwin, height=300, width=300)
canvas.pack()
my_image = tk.PhotoImage(file=a, master=root)
canvas.create_image(150, 150, image=my_image)
newwin.mainloop()
def browse(self):
""" Browses a .png file or all files and then puts it on the entry.
"""
global a
a = fd.askopenfilename(initialdir=self._initaldir, filetypes=self._filetypes)
self.filepath.set(a)
if __name__ == '__main__':
root = tk.Tk()
labelfont = ('times', 10, 'bold')
root.geometry("500x500")
filetypes = (
('Portable Network Graphics', '*.png'),
("All files", "*.*")
)
file_browser = Browse(root, initialdir=r"~/Desktop", filetypes=filetypes)
file_browser.pack(fill='y')
root.mainloop()
P.S. Do change your initialdir. I changed it as I am not on Windows.
I am making a Tkinter Python progarm that will have a Login page and once you are logged in it will show a Menu page for the user to interact with.
My code that includes the Quiz class, StartPage class, Menu class, difficulty class, and the Login page is as follows:
import tkinter as tk
from tkinter import *
import tkinter.messagebox as tm
class Quiz (tk.Tk):
def __init__ (self, *args , **kwargs):
tk.Tk.__init__(self, *args , ** kwargs)
container = tk.Frame (self)
container.pack (side = "top" , fill = "both" , expand = True)
container.grid_rowconfigure (0,weight = 1)
container.grid_columnconfigure (0,weight = 1)
self.frames = {}
for F in (StartPage, Menu, Difficulty):
frame = F(container, self)
self.frames[F] = frame
frame.grid (row = 0, column = 0 , sticky = "nsew")
self.show_frame(StartPage)
def show_frame(self,cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text = "Login")
label.pack(pady = 10 , padx = 10)
Username = tk.Entry(self)
Username.pack()
Password = tk.Entry (self, show = "*")
Password.pack()
button1 = tk.Button(self, text = "Login", command = lambda: Login(Username,Password,parent,controller,self))
button1.pack()
class Menu(tk.Frame):
def __init__ (self, parent, controller) :
tk.Frame.__init__(self, parent)
label = tk.Label(self, text = "Menu")
button1 = tk.Button(self, text = "Histoy", command = lambda: controller.show_frame(Difficulty))
button1.pack()
button2 = tk.Button(self, text = "Maths", command = lambda: controller.show_frame(Difficulty))
button2.pack()
button3 = tk.Button(self, text = "Music",
command = lambda: controller.show_frame(Difficulty))
button3.pack()
class Difficulty(tk.Frame):
def __init__ (self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text = "Difficulty")
Easy = tk.Button(self, text = "Easy", command = lambda: controller.show_frame(Difficulty))
Easy.pack()
Medium = tk.Button(self, text = "Medium",command = lambda: controller.show_frame(Difficulty))
Medium.pack()
Hard = tk.Button(self, text = "Hard", command = lambda: controller.show_frame(Difficulty))
Hard.pack()
backtomenu = tk.Button(self, text = "Back to Menu", command = lambda: controller.show_frame(Menu))
backtomenu.pack()
def Login(Username,Password,parent,controller,self):
Usernames = []
count = 0
Username = Username.get()
Password = Password.get()
try:
with open ("Usernames&Passwords.txt" , "r", encoding = "UTF-8" ) as file:
for each in file:
Usernames.append(each.strip("\n"))
except IOError as error:
print (error)
if Usernames[count] == Username :
if Usernames[count + 1] == Password:
Menu( parent, controller)
print ("Hi")
else:
tm.showinfo("Username or Password is Incorrect")
else:
tm.showinfo("Username or Password is Incorrect")
app = Quiz()
app.geometry ("500x300")
app.mainloop()
When I run the code there is not an error message shown but it doesn't run the Menu class so it does not go to the next Tkinter Frame to continue on with the program. Can someone help point me in the right direction of why the Main class is not running. Thanks in advance.
You have to destroy all other widgets before the next is shown.
Insert self.destroy() before Menu(parent, controller).
The same thing has to be done by the difficulty.
Edit: As #Bryan Oakley pointed out, this is the wrong solution. Instead change Menu(parent, controller) to controller.show_frame(Menu)
The code picture needs to fit the screen size perfectly. I saw a bunch of tutorials but nothing seems to work.I tried adding a canvas but it covers half the screen.All my buttons go under the image itself not over it. It's getting on my nerves .
here's my code :
import tkinter as tk
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
w = Label(root, text="Send and receive files easily")
w.config(font=('times', 32))
w.pack()
def create_window():
window = tk.Toplevel(root)
window.geometry("400x400")
tower= PhotoImage(file="D:/icons/tower.png")
towlab=Button(root,image=tower, command=create_window)
towlab.pack()
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Bifrost v1.0")
self.pack(fill=BOTH, expand=1)
self.img1 = PhotoImage(file="D:/icons/download.png")
self.img2 = PhotoImage(file="D:/icons/upload.png")
sendButton = Button(self, image=self.img2)
sendButton.place(x=305, y=15)
receiveButton = Button(self, image=self.img1)
receiveButton.place(x=355, y=15)
menu = Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
top = Toplevel()
msg = Message(top, text="This is a project developed by Aditi,Sagar and
Suyash as the final year project.",
font=('', '15'))
msg.pack()
top.geometry('200x200')
button = Button(top, text="Okay", command=top.destroy)
button.pack()
top.mainloop()
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()
Overlaying elements is tricky. I think this might be approximately what you're looking for. At least it's a start...
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
class Window:
def __init__(self, master=None):
tower = PIL.Image.open("Images/island.png")
master.update()
win_width = int(master.winfo_width())
win_height = int(master.winfo_height())
# Resize the image to the constraints of the root window.
tower = tower.resize((win_width, win_height))
tower_tk = ImageTk.PhotoImage(tower)
# Create a label to hold the background image.
canvas = Canvas(master, width=win_width, height=win_height)
canvas.place(x=0, y=0, anchor='nw')
canvas.create_image(0, 0, image=tower_tk, anchor='nw')
canvas.image = tower_tk
frame = Frame(master)
frame.place(x=win_width, y=win_height, anchor='se')
master.update()
w = Label(master, text="Send and receive files easily", anchor='w')
w.config(font=('times', 32))
w.place(x=0, y=0, anchor='nw')
master.title("Bifrost v1.0")
self.img1 = PhotoImage(file="Images/logo.png")
self.img2 = PhotoImage(file="Images/magnifier.png")
frame.grid_columnconfigure(0, weight=1)
sendButton = Button(frame, image=self.img2)
sendButton.grid(row=0, column=1)
sendButton.image = self.img2
receiveButton = Button(frame, image=self.img1)
receiveButton.grid(row=0, column=2)
receiveButton.image = self.img1
menu = Menu(master)
master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
message = "This is a project developed by Aditi,Sagar and"
message += "Suyash as the final year project."
messagebox.showinfo("Delete Theme", message)
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()