How to delete popup window in tkinter? - python

I have a sequence of pop up windows. I intended to close the window once i have completed the desired task. I am using a "askokcancel" button to get users confirmation whether the activity has completed. The problem is, every time the user presses ok, the focus goes back to the main starting window and rest of the pop up windows goes to the background while staying active. I want to either close the pop up windows or keep the focus to the second last window. Below is my code:
import tkinter as tk
from tkinter import ttk, StringVar, messagebox
from tkinter.filedialog import askopenfilename
from mytest import *
from tkinter import *
class myclass:
def __init__(self, master):
self.master = master
self.frame1 = tk.Frame(self.master)
self.button1 = tk.Button(self.frame1, text = 'select me first', width = 25, command = self.buttonFunc)
self.button1.pack()
self.quitButton = tk.Button(self.frame1, text = 'Quit', width = 25, command = self.close_windows1)
self.quitButton.pack()
self.frame1.pack()
self.master.geometry("200x200+60+60")
def buttonFunc(self):
self.top = tk.Toplevel(self.master)
self.button2 = tk.Button(self.top,text="Select second",command=self.anotherButtonFunc)
self.button2.pack()
self.quitButton = tk.Button(self.top, text = 'Quit', width = 25, command = self.close_windows2)
self.quitButton.pack()
self.master.geometry("200x200+60+60")
def anotherButtonFunc(self):
self.top2 = tk.Toplevel(self.top)
self.newClass = myClassExt(self.top2)
def close_windows1(self):
self.master.destroy()
def close_windows2(self):
self.top.destroy()
class myClassExt():
def __init__(self, top2):
self.top3 = top2
self.frame2 = tk.Frame(self.top3)
self.button3 = tk.Button(self.frame2, text = 'select me third', width = 25, command = self.buttonFunc)
self.button3.pack()
self.quitButton = tk.Button(self.frame2, text = 'Quit', width = 25, command = self.close_windows4)
self.quitButton.pack()
self.frame2.pack()
self.top3.geometry("200x200+60+60")
def buttonFunc(self):
ok = messagebox.askokcancel(message='Press OK to Confirm?')
if not ok:
pass
else:
messagebox.showinfo("Success","Well done")
self.close_windows4()
def close_windows4(self):
self.top3.destroy()
if __name__ == "__main__":
root = tk.Tk()
myclass = myclass(root)
root.mainloop()
From this made up example, i somehow want to either close window number 2 after user presses OK or keep the focus on window 2 rather than window 1. Please guide

There is no way to close a message box, although you can easily make your own. You just have to make a new tkinter window, and set an image, title, and text, then add a close button, and return the tk window. I made a function like this myself, for this very reason. Here is the function:
def mymessage(title, text, spacing = 25, buttonText = "Close", image = None):
tk2 = Tk()
tk2.resizable(0, 0)
tk2.title(title)
if image != None:
image = Label(tk2, image = PhotoImage(file = image))
image.pack()
spacer = Frame(tk2, relief = FLAT, bd = 0, width = 200, height = 25)
spacer.pack()
label = Label(tk2, text = text)
label.pack()
button = Button(tk2, text = buttonText, width = 5, height = 1, command = tk2.destroy)
button.pack()
return tk2
After calling the function, it returns the tk window, for easy destruction.

Related

Tktinter Menu with functionality in separate file

It's my first time trying tkinter.
I'm trying to make a menu with the command section in another file.
However it seems to run the command immediately as I open the program and doesn't wait till I click the menu button.
following is the code for my main:
import data
import loginPage
import menuFunc
from tkinter import *
import tkinter as tk
class main(Tk):
def __init__(self):
super().__init__()
self.geometry("1000x700") #size of the window
self.resizable(False,False) #dont let the user resize (might mess up layout of GUI)
def Menu(self):
myMenu = Menu(self)
self.config(menu=myMenu)
#Create a menu items
optionMenu= Menu(myMenu)
myMenu.add_cascade(label="Options", menu=optionMenu)
optionMenu.add_command(label="Exit", command = self.destroy)
addMenu= Menu(myMenu)
myMenu.add_cascade(label="Add", menu=addMenu)
addMenu.add_command(label="New Book", command = menuFunc.addBook(self))
addMenu.add_command(label="New customer", command = menuFunc.addCustomer(self))
addMenu.add_command(label="New employee", command = menuFunc.addEmployee(self))
def Label(self):
self.backGroundImage = PhotoImage(file = "Background.png") #photoimage for background
self.backGroundImageLabel = Label(self, image = self.backGroundImage) #import the image as a label
self.backGroundImageLabel.place(x=0, y=0) #placement
# self.canvas = Canvas(self, width=550,height = 400) #show a canvas in front of background
#self.canvas.place(x=75, y=70)
if __name__=="__main__":
Main = main()
Main.Label()
Main.Menu()
#Login.Entry()
#Login.Button()
Main.mainloop()
This is my code in the other file menuFunc.py
from tkinter import *
import tkinter as tk
global addBookFrame
def addBook(window):
addBookFrame = Frame(window, bg = "red")
addBookFrame.pack(fill="both",expand = 1)
def addCustomer(window):
addCustomerFrame = Frame(window, bg = "blue")
addCustomerFrame.pack(fill="both",expand = 1)
def addEmployee(window):
addEmployeeFrame = Frame(window, bg = "yellow")
addEmployeeFrame.pack(fill="both",expand = 1)
def hideFrames(frame):
for widget in frame.winfo_children():
widget.destroy()
I get the following result:
enter image description here
How can I make it so that the function only runs when I press the appropriate menu button?
Put:
command = menuFunc.addBook
command = menuFunc.addCustomer
command = menuFunc.addEmployee
In place of:
command = menuFunc.addBook(self)
command = menuFunc.addCustomer(self)
command = menuFunc.addEmployee(self)

Prevent Tkinter window to pop up once is called only once

I have a small test Tkinter window with Labels and Entries in a file called "customer.py"
I created another file "button_test.py" with a super simple tkinter window with only one button to call "customer.py"
The button calls 'customer.py" with no problem but If I click the button again over andover. Keeps popping up the same window. I could probably add some conditions over there maybe but I would like to know if there is a better way to prevent that. I see it also happens with the "Tk TopLevel"
I thank you for your help and time Comrades.
customer.py
from tkinter import *
class OFFLINE():
def __init__(self,window):
self.win = window
self.win.title("Emails")
frame = LabelFrame(self.win, text = 'CUSTOMER INFORMATION')
frame.grid(column = 0, row = 0, )
Label(frame, text = "Case Number").grid(column = 0, row = 1)
self.Case_box = Entry(frame).grid(column = 1, row = 1)
Label(frame, text = "Customer Name").grid(column = 0, row = 2)
self.name_box = Entry(frame).grid(column = 1, row = 2)
Label(frame, text = "Phone number").grid(column = 0, row = 3)
self.phone_box = Entry(frame).grid(column = 1, row = 3)
Label(frame, text = "Email").grid(column = 0, row =4)
self.email_box = Entry(frame).grid(column =1, row = 4)
def main():
root = Tk()
application = OFFLINE(root)
root.mainloop()
if __name__ == '__main__':
main()
button_test.py
import customer
from tkinter import *
offline = customer
window = Tk()
button = Button(window, text = "Click Me", command =offline.main)
button.pack()
window.mainloop()
You can disable button
button['state'] = 'disabled'
and later enable it
button['state'] = 'normal'
Or you can use .grab_set() to make modal window and first window will not get key/mouse events.
Minimal working code
from tkinter import *
def set_disabled():
button1['state'] = 'disabled'
def set_normal():
button1['state'] = 'normal'
window = Tk()
button1 = Button(window, text = "Click Me", command=set_disabled)
button1.pack()
button2 = Button(window, text = "Next Me", command=set_normal)
button2.pack()
window.mainloop()
EDIT:
Example with second window.
It shows how to do it with Toplevel() instead od second Tk() and without second `mainloop()
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def close_window():
top_window.destroy()
button_open['state'] = 'normal'
def open_window():
global top_window # to keep value in external variable
global button_close # to keep value in external variable
button_open['state'] = 'disabled'
top_window = tk.Toplevel(window)
label = tk.Label(top_window, text="New Window")
label.pack()
button_close = tk.Button(top_window, text = "Close", command=close_window)
button_close.pack()
# --- main ---
window = tk.Tk()
button_open = tk.Button(window, text="Open", command=open_window)
button_open.pack()
window.mainloop()
EDIT:
Example with grab_set() to make window modal
import tkinter as tk # PEP8: `import *` is not preferred
# --- functions ---
def open_window():
top_window = tk.Toplevel(window)
top_window.grab_set()
label = tk.Label(top_window, text="New Window")
label.pack()
button_close = tk.Button(top_window, text = "Close", command=top_window.destroy)
button_close.pack()
# --- main ---
window = tk.Tk()
button_open = tk.Button(window, text="Open", command=open_window)
button_open.pack()
window.mainloop()
PEP 8 -- Style Guid for Python Code
You can simulate singleton feature using class as below:
customer.py
from tkinter import *
__all__ = ['main']
class OFFLINE():
...
class _SingletonWin(Toplevel):
_instance = None
def __init__(self, master=None, *args, **kw):
super().__init__(master, *args, **kw)
self.form = OFFLINE(self)
self.protocol("WM_DELETE_WINDOW", self.on_destroy)
#classmethod
def on_destroy(cls):
if cls._instance:
cls._instance.destroy()
cls._instance = None
#classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
return cls._instance
def main():
return _SingletonWin.get_instance()
Then whenever main() is called, only one instance of the toplevel will be shown.

Tkinter Canvas: Itemconfig failed update color

I've to change the color of the rectangle created with the Canvas item.
I've looked at other questions but I didn't find an answer to my problem.
I am recording a microphone using a USB Sound card. Once the record is started I want to put a RED light and, once it is finished, back it to green.
Here's the code:
main.py:
import tkinter as tk
from GUI import Demo1
def main():
root = tk.Tk()
app = Demo1(root)
root.mainloop()
if __name__ == '__main__':
main()
GUI.py:
class Demo1:
def __init__(self, master):
#Set geometry and title
self.master = master
self.master.title("DAQ - Sound Pressure Level")
self.master.geometry("480x320")
# Canvas zone
self.canvas = tk.Canvas(self.master,width=40,height=20,background='white')
self.canvas.grid(row=0,column=3)
self.frame = Frame(self.master)
self.frame.grid(row=0,column=3)
self.rect1 = self.canvas.create_rectangle(0,0,40,20, fill="green")
#canvas.bind(func=changecolor(canvas))
#set buttons
self.quitbutton = tk.Button(self.master, text = 'Quit', width = 10, command = self.close_windows)
self.quitbutton.grid(column=1,row=0)
self.startbutton = tk.Button(self.master, text = 'Start', width = 10, command = lambda: self.startacquisition())
self.startbutton.grid(column=0,row=0)
#self.zerobutton = tk.Button(self.master,text = 'Zero', width = 10, command = lambda: self.zerocalibration())
#self.zerobutton.grid(column=2,row=0)
#self.livebutton = tk.Button(self.master,text="Live/Stop", command=lambda: self.gui_handler, bg="red", fg="white")
#self.livebutton.grid(column=2,row=0)
def startacquisition(self):
chunk = 8192 # Record in chunks
print("Changing rect color to red")
self.canvas.itemconfig(self.rect1,fill='red')
p = pyaudio.PyAudio() # Create an interface to PortAudio
[....recording stuff...]
[...preparing plot...]
plt.show()
self.canvas.itemconfig(self.rect1,fill='green')
So when I press the START button it calls startacquisition(self) function. What happend is that the color doesn't upgrade until I close all the plot.
Why?
Thanks for your help.

This my small python program .when button clicks new window opening. how it is possible to in one window only

This is small Python button program. My problem was when I am clicking button always opening new window. I want one window execution.
from tkinter import *
import sys
def pressed():
root = Tk()
root.title('My Window2')
root.geometry('200x200')
button = Button(root,text = 'press2',command = pressed2)
button.pack(pady = 20, padx = 20)
def close():
quit()
def pressed1():
print('second window')
def pressed2():
root = Tk()
root.title('My Window3')
root.geometry('200x200')
button = Button(root,text = 'press3',command = pressed1)
button.pack(pady = 20, padx = 20)
button = Button(root,text = 'back',command = pressed)
button.pack(pady = 20, padx = 20)
root = Tk()
root.title('My Window')
root.geometry('200x200')
button = Button(root,text = 'press',command = pressed)
button2 = Button(root,text = 'Exit',command = close)
button.pack(pady = 20, padx = 20)
button2.pack(pady = 20, padx = 20)
mainloop()
I have not used Tkinter, but here is what looks like is happening.
1. on my win 7 python 2.6 it is Tkinter, not tkinter
2. when you use root = Tk() it is creating a new window; if you remove the root = Tk() from pressed() and pressed2() it uses the original window over again.
It's not clear what you want, but if you are trying to modify the text, and command associated with the button then you just need to configure those attributes.
Something like this should work. It can be modified to add new buttons instead of reusing the same button. I made the class inherit from Frame, but you could also choose to inherit from Tk. (Note: This is Python 3 code)
import tkinter
class ButtonPressWindow(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
master.title('My Window')
master.geometry('200x200')
self.button1 = tkinter.Button(self, text='press', command=self.pressed)
self.button2 = tkinter.Button(self, text='Exit', command=self.close)
self.button1.pack(pady=20, padx=20)
self.button2.pack(pady=20, padx=20)
def pressed(self):
self.master.title('My Window2')
self.master.geometry('200x200')
self.button1.configure(text='press2', command=self.pressed2)
def pressed2(self):
self.master.wm_title('My Window3')
self.master.geometry('200x200')
self.button1.configure(text='press3', command=self.pressed3)
def pressed3(self):
print("Second window")
def close(self):
quit()
root = tkinter.Tk()
btnWindow = ButtonPressWindow(root)
btnWindow.pack(fill='both', expand=True)
root.mainloop()

Need help placing buttons on a PhotoImage .gif

Here is my program as of yet:
from tkinter import *
from collections import deque
class App():
def __init__(self, *images):
self.root = Tk()
self.root.title("Skin")
self.image_dict = {image: PhotoImage(file=image) for image in images}
self.image_queue = deque(images)
b = Button(self.root, text="Click here to see the diagram!", command=self.change_image)
b.pack(fill=X)
self.label = Label(self.root, image=self.image_dict["1.gif"])
self.label.image = self.image_dict["1.gif"]
self.label.pack()
def change_image(self):
self.image_queue.rotate(-1)
next_image = self.image_queue[0]
self.label.configure(image=self.image_dict[next_image])
self.label.image = self.image_dict[next_image]
if __name__ == "__main__":
app = App('1.gif', '2.gif')
app.root.mainloop()
What this does is when you run the scipt, a window comes up diplaying "1.gif", and a button. When you click the button, "1.gif" changes to "2.gif". "1.gif" is a blank diagram, "2.gif" is a diagram with labels showing what each part of the diagram is.
Now for the next stage of my program, I need some way to add multiple invisible buttons, or something like it, over each word on the diagram on "2.gif", and when you click on it, I need a seperate window to come up with text on it. Is there any way to implement that into my current program? I have no idea where to start. Thank you!
I think you will be better off using a Canvas to hold your image(s) rather
than a Label. You can then place 'hotspots' over the diagram and bind
events to them. eg. something like:
from tkinter import *
class App():
def __init__(self):
self.root = Tk()
self.messages = {}
self.canvas = Canvas(self.root, bd=0, highlightthickness=0)
self.image = PhotoImage(file='2.gif')
self.canvas.create_image(0,0, image=self.image, anchor='nw')
w,h = self.image.width(), self.image.height()
self.canvas.config(width=w, height=h)
self.canvas.pack()
self.balloon = b = Toplevel(self.root)
b.withdraw()
b.wm_overrideredirect(1)
self.msg = Label(b, bg='black', fg='yellow', bd=2, text='')
self.msg.pack()
self.set_up_hotspots()
def set_up_hotspots(self):
box1 = self.canvas.create_polygon(50,100,100,100,100,150,50,150,
outline='blue', fill='')
#note: outline can be '' also ;)
self.messages[box1] = "The machine head consists of a "\
"Flynn mechanism,\na Demmel crank, "\
"and a heavy-duty frobulator. "
box2 = self.canvas.create_polygon(150,100,200,100,200,150,150,150,
outline='red', fill='')
self.messages[box2] = "And now for something completely different"
for item in [box1, box2]:
for event, handler in [('<Enter>', self.on_hotspot_enter),
('<Leave>', self.on_hotspot_leave)]:
self.canvas.tag_bind(item, event, handler)
def on_hotspot_enter(self, event):
if not self.balloon.winfo_ismapped():
txt = self.messages[event.widget.find_withtag('current')[0]]
self.msg.config(text=txt)
x,y = event.x_root, event.y_root
self.balloon.geometry('+%d+%d' %(x+16,y))
self.balloon.deiconify()
def on_hotspot_leave(self, event):
if self.balloon.winfo_ismapped():
self.balloon.withdraw()
if __name__ == "__main__":
app = App()
app.root.mainloop()

Categories