how to open only 1 new window in tkinter after button click? - python

I have referred to this post Python tkinter: How can I ensure only ONE child window is created onclick and not a new window every time the button is clicked? but i couldn't get my code to work. Could anyone please help me?
from tkinter import *
import os
import sys
import _thread
from s2 import work
from s1 import work2
root = Tk()
root.resizable(width=False, height=False)
root.title("Sample tkinter")
root.geometry(r"550x550")
def open_entry():
os.system("data1.py")
def open_aisle():
os.system("data2.py")
def close_entry():
os.system("data10.py")
def close_aisle():
os.system("data20.py")
def run():
_thread.start_new_thread(work,())
_thread.start_new_thread(work2,())
def openNewWindow():
global createdb_btn
newWindow = Toplevel(root)
newWindow.resizable(width=False,height=False)
newWindow.title("New Window")
newWindow.geometry("300x300")
create_front = Button(newWindow,text="Entry DB",relief=FLAT,bg="black",fg="white",command=open_entry)
create_front.place(x=50,y=80)
create_aisle = Button(newWindow,text="Aisle DB",relief=FLAT,bg="black",fg="white",command=open_aisle)
create_aisle.place(x=145,y=80)
def openAnotherWindow():
global removedb_btn
otherWindow = Toplevel(root)
otherWindow.resizable(width=False,height=False)
otherWindow.title("New Window")
otherWindow.geometry("300x300")
remove_front = Button(otherWindow,text="Entry DB",relief=FLAT,bg="black",fg="white",command=close_entry)
remove_front.place(x=50,y=80)
remove_aisle = Button(otherWindow,text="Aisle DB",relief=FLAT,bg="black",fg="white",command=close_aisle)
remove_aisle.place(x=145,y=80)
removedb_btn = Button(root,text="Remove databases",relief=FLAT,bg="black",fg="white",state=DISABLED)
removedb_btn.place(x=380,y=120)
camera_btn = Button(root,text="Open Cams",relief=FLAT,bg="black",fg="white",command=run)
camera_btn.place(x=50,y=120)
createdb_btn = Button(root,text="Create databases",relief=FLAT,bg="black",fg="white",command=openNewWindow)
createdb_btn.place(x=205,y=120)
removedb_btn = Button(root,text="Remove databases",relief=FLAT,bg="black",fg="white",command=openAnotherWindow)
removedb_btn.place(x=380,y=120)
root.mainloop()
I am trying to achieve this in both the openNewWindow function and openAnotherWindow function.

This is what I did. Changed the lines:
createdb_btn = Button(root,text="Create databases",relief=FLAT,bg="black",fg="white")
createdb_btn.config(command=lambda b=createdb_btn: (openNewWindow(b), b.config(state='disabled')))
and added
newWindow.protocol("WM_DELETE_WINDOW", lambda:(button.config(state='active'), newWindow.destroy()))
Inside newWindow function so that when you pass in the button that created the window as a variable and use that on the overwrite of opennewWindows function to reactivate it just before newWindow.destroy()

Related

Binding a key to a function in Tkinter

I have a problem with binding a key (Ctrl-A) to a function (select all) in menu_bar function. Whatever I do, this key combination is moving me to beginning of the line.
My main program:
from tkinter import *
import tkinter as tk
import func
from tkinter import font
class Editor():
def __init__(self, window):
# Window + Title
window.geometry('1200x800')
window.title('SuperEditor')
# Scrool bar
scrollbar = Scrollbar(window)
scrollbar.pack(side=RIGHT,fill=Y)
# Text area
user_font=font.Font(size=20)
editor = Text(window,width=400,height=450,yscrollcommand=scrollbar.set, undo = True,
font=user_font)
editor.pack(fill=BOTH)
scrollbar.config(command = editor.yview)
# Selfs
self.window = window
self.editor = editor
self.user_font = user_font
editor.bind("<Control-A>", func.select_all(editor))
def menu_bar(self):
menubar = Menu(self.window)
# Edit menu
editmenu = Menu(menubar, tearoff=0)
editmenu.add_command(label="Select All", command=lambda: func.select_all(self.editor), accelerator='Ctrl-A')
menubar.add_cascade(label="Edit", menu=editmenu)
# Add the menu bar
self.window.config(menu=menubar)
def main():
# Create a SuperEditor window
se_window = Tk()
# Create a text editor
editor = Editor(se_window)
# Create menubar
editor.menu_bar()
# Rune the SuperEditor
se_window.mainloop()
if __name__ == "__main__":
main()
Functions file:
import tkinter as tk
import tkinter.filedialog as fd
from tkinter import font
def select_all(text, event=None):
'''Select all text'''
if event:
print('Up')
text.tag_add("sel", "1.0","end")
text.tag_config("sel",background="gray",foreground="white")
return 'break'
else:
text.tag_add("sel", "1.0","end")
text.tag_config("sel",background="gray",foreground="white")
When I put this in __init__, it selects everything at start, but doesn't work later:
self.editor.bind("<Control-A>", functions.select_all(editor))
I tried to do it with lambda, then i get:
TypeError: Editor.menu_bar.<locals>.<lambda>() takes 0 positional arguments but 1 was given
Change
editor.bind("<Control-A>", func.select_all(editor))
to
editor.bind("<Control-A>", lambda event: func.select_all(editor, event=event))
This answer was posted as an edit to the question Binding a key to a function in Tkinter by the OP koleks92 under CC BY-SA 4.0.

Tkinter Button - How to get the values and display it using a single module for different Buttons

I am creating a GUI, where I have placed three buttons for selecting a file. When I click the button it browse for a file and display the selected file path and I am trying to do it with a single browse function since the operation is same. I am bit confused to how I should proceed . Can anyone please help me out.
Thanks in advance.
Here is my code:
Browse_Files.py
from tkinter import filedialog
def Browse_File():
global Bfilepath
Bfilepath = filedialog.askopenfilename(filetypes = (("Please select the required file", "*"), ("All files", "*")))
return Bfilepath
Main.py
from tkinter import *
import sys
import fileinput
import Browse_Files
root = Tk()
root.geometry('1400x800')
root.title('Dr Configuration')
Heading = Label(root, font=('Times New Roman',50,'bold'),text = "Arxml
Configuration Tool").place(x=300,y=25)
BasepathLabel = Label(root,font=('Times New Roman',20,'bold'),text = " Base
arxml").place(x=200,y=150)
NewpathLabel= Label(root,font=('Times New Roman',20,'bold'),text = "
New/Unedited arxml").place(x=200,y=250)
InterfaceLabel = Label(root,font=('Times New Roman',20,'bold'),text = "
Interface_File").place(x=200,y=350)
BpathtoDisp = StringVar(None)
BpathEntry = Entry(root,font=('Times New Roman',18),textvariable=
BpathtoDisp,justify='left',width=48).place(x=500,y=150)
NpathtoDisp = StringVar(None)
NpathEntry = Entry(root,font=('Times New Roman',18),textvariable=
NpathtoDisp,justify='left',width=48).place(x=500,y=250)
InterPathtoDisp = StringVar(None)
InterPathEntry = Entry(root,font=('Times New Roman',18),textvariable=
NpathtoDisp,justify='left',width=48).place(x=500,y=350)
button1 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=150)
button2 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=250)
button3 = Button(root,text="...",height=1,width=3,command=lambda:Browse_Files.Browse_File()).place(x=1100,y=350)
root.mainloop()
You could create a class that contains the functionality to have a button, open a file dialog, store it and make it available to other parts of the program.
I have a similar widget that I use in many different programs
from tkinter import *
from tkinter import filedialog
class FileSelect(Frame):
def __init__(self,master,label="",**kw):
Frame.__init__(self,master)
self.configure(**kw)
self.file = StringVar()
self.Label = Label(self, text=label)
self.Label.config(width=10,anchor=E)
self.filenamebox = Entry(self,text=self.file)
self.filenamebox.config(width=50)
self.btnBrowse = Button(self,text='Browse',command=self.browse_file)
self.btnBrowse.config(width=10)
self.Label.grid(row=0,column=0,pady=5,sticky=E)
self.filenamebox.grid(row=0,column=1,pady=5)
self.btnBrowse.grid(row=0,column=2,pady=5,padx=5)
def browse_file(self):
filename = filedialog.askopenfilename(filetypes=[('All File','*.*')])
self.file.set(filename)
def get_filename(self):
return self.file.get()
def main():
root = Tk()
root.title("Example Widget")
fileSelect1 = FileSelect(root,label="My File 1")
fileSelect1.grid()
fileSelect2 = FileSelect(root,label="My File 2")
fileSelect2.grid()
root.mainloop()
if __name__ == '__main__':
main()
In your code if you want the value of the file selected use
fileSelect1.get_filename()
EDIT: I've created a new version that is only a Button 'with memory' to remember which item was selected by the file dialog. This will allow you to place using the place geometry manager (which I don't recommend). Its not complete but you should get the idea.
from tkinter import *
from tkinter import filedialog
class FileSelectButton(Button):
def __init__(self,master,**kw):
Button.__init__(self,master,text='Browse',command=self.browse_file,width=10,**kw)
self.file = StringVar()
def browse_file(self):
filename = filedialog.askopenfilename(filetypes=[('All File','*.*')])
self.file.set(filename)
def get_filename(self):
return self.file.get()
def main():
root = Tk()
root.geometry('1400x800')
root.title("Example Widget")
Label(root, font=('Times New Roman',50,'bold'),text = "Label1").place(x=200,y=150)
fileSelect1 = FileSelectButton(root)
fileSelect1.place(x=500,y=150)
Label(root, font=('Times New Roman',50,'bold'),text = "Label2").place(x=200,y=250)
fileSelect2 = FileSelectButton(root)
fileSelect2.place(x=500,y=250)
root.mainloop()
if __name__ == '__main__':
main()

How do you close a tkinter window in another function?

I want a button in my window to open a new window and close the previous one. Is it possible to have one button do both of these? I've tried in the following code, but it hasn't worked, just told me that window is not defined:
import tkinter
def window1():
window = tkinter.Tk()
tkinter.Button(window, text = "Next", command = window2).pack()
window.mainloop()
def window2():
window.destroy() #This is where the error is
menu = tkinter.Tk()
etc, etc, etc
window1()
First, you need to return the window object from the first function:
def window1():
window = tkinter.Tk()
tkinter.Button(window, text = "Next", command = lambda: window2(window)).pack()
window.mainloop()
return window
Then, you need to pass the window as an argument to your function:
def window2(window):
window.destroy()
menu = tkinter.Tk()
And then call window1 with:
window = window1()
and click the button to destroy it and do the rest
This is an example using Toplevels, which is usually a better choice than creating, destroying, re-creating Tk() instances. The unique Toplevel ID is passed to the close_it function using partial(). You would, of course, combine them or have the close function call the open function.
try:
import Tkinter as tk ## Python 2.x
except ImportError:
import tkinter as tk ## Python 3.x
from functools import partial
class OpenToplevels():
""" open and close additional Toplevels with a button
"""
def __init__(self):
self.root = tk.Tk()
self.button_ctr=0
but=tk.Button(self.root, text="Open a Toplevel",
command=self.open_another)
but.grid(row=0, column=0)
tk.Button(self.root, text="Exit Tkinter", bg="red",
command=self.root.quit).grid(row=1, column=0, sticky="we")
self.root.mainloop()
def close_it(self, id):
id.destroy()
def open_another(self):
self.button_ctr += 1
id = tk.Toplevel(self.root)
id.title("Toplevel #%d" % (self.button_ctr))
tk.Button(id, text="Close Toplevel #%d" % (self.button_ctr),
command=partial(self.close_it, id),
bg="orange", width=20).grid(row=1, column=0)
Ot=OpenToplevels()
Yes. Is possible. But you'll need to def that:
def window1:
blablabla
blablabla
def window2:
window2.destroy() <-- Here where the error was
How you noticed, put your name of window what you want Destroy and it will work!
using Python3
You could use a "global" such as:
root = Tk()
root.title('This is the root window')
def window_create():
global window_one
window_one = Tk()
window_one.title('This is window 1')
Then, from any function (or elsewhere) when you want to destroy window_one, do:
def window_destroyer():
window_one.destroy()
You could call your window_destroyer function from a button anywhere such as root which the example shows:
kill_window_btn = Button(root, text="Destroy", command=window_destroyer).pack()
Of course, follow your own naming conventions. :)
It seems to me, just 'global window_one' would solve it.

Multiple windows open at once in python

I've searched and found a few things on parent windows in python but that is not what I was looking for. I am trying make a simple program that opens a window and another window after that when the previous one is closed. I was also trying to implement some kind of loop or sleep time to destroy the window by default if the user does not. This is what I have (I'm new please don't laugh)
from tkinter import *
import time
root = Tk()
i = 0
if i < 1:
root.title("title")
logo = PhotoImage(file="burger.gif")
w1 = Label(root, image=logo).pack()
time.sleep(3)
root.destroy()
i = i + 1
if i == 1:
root.title("title")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(root, image=photoTwo).pack()
time.sleep(3)
root.destroy()
i = i + 1
mainloop.()
Perhaps you're looking for something like this:
from tkinter import *
import time
def openNewWindow():
firstWindow.destroy()
secondWindow = Tk()
secondWindow.title("Second Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(secondWindow, image=photoTwo).pack()
secondWindow.mainloop()
firstWindow = Tk()
firstWindow.title("First Window")
logo = PhotoImage(file="burger.gif")
w1 = Label(firstWindow, image=logo).pack()
closeBttn = Button(firstWindow, text="Close!", command=openNewWindow)
closeBttn.pack()
firstWindow.mainloop()
This creates a button in the first window, which the user clicks. This then calls the openNewWindow function, which destroys that window, and opens the second window. I'm not sure there's a way to do this using the window exit button.
To get create a more sustainable window creation, use this:
from tkinter import *
import time
def openThirdWindow(previouswindow):
previouswindow.destroy()
thirdWindow = Tk()
thirdWindow.title("Third Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(thirdWindow, image=photoTwo).pack()
thirdWindow.mainloop()
def openSecondWindow(previouswindow):
previouswindow.destroy()
secondWindow = Tk()
secondWindow.title("Second Window")
photoTwo = PhotoImage(file="freedom.gif")
labelTwo = Label(secondWindow, image=photoTwo).pack()
closeBttn = Button(secondWindow, text="Close!", command= lambda: openThirdWindow(secondWindow))
closeBttn.pack()
secondWindow.mainloop()
def openFirstWindow():
firstWindow = Tk()
firstWindow.title("First Window")
logo = PhotoImage(file="burger.gif")
w1 = Label(firstWindow, image=logo).pack()
closeBttn = Button(firstWindow, text="Close!", command= lambda: openSecondWindow(firstWindow))
closeBttn.pack()
firstWindow.mainloop()
openFirstWindow()
This places the opening of each window in a seperate function, and passes the name of the window through the button presses into the next function. Another method would be setting the window names as global, but this is messy.
The function "lambda:" calls the function, in tkinter you must type this if you want to pass something through a command.
We initiate the whole process first first called "openFirstWindow()"

Python Tkinter Label Delay

This maybe a silly question to ask. I have a label in Tkinter GUI and i want it to be updated through time.
Example:
Msglabel=Tkinter.Label(... text="")
Msglabel.Cofigure(text=" EXAMPLE!")
Wait(5sec)
Msglabel.Configure(text=" NEW EXAMPLE!")
I've read about the after() method but im looking for something like Wait.
You'll need to hand over control to Tkinter during your wait period since Tkinter updates the UI in a single threaded loop.
Sleeping between the configure calls will hang the UI.
As you mentioned, after is the method you want. Try something like this:
try:
import Tkinter as tkinter # Python 2
except ImportError:
import tkinter # Python 3
import itertools
class MyApplication(object):
def __init__(self):
# Create and pack widgets
self.root = tkinter.Tk()
self.label = tkinter.Label(self.root)
self.button = tkinter.Button(self.root)
self.label.pack(expand=True)
self.button.pack()
self.label['text'] = 'Initial'
self.button['text'] = 'Update Label'
self.button['command'] = self.wait_update_label
# Configure label values
self.label_values = itertools.cycle(['Hello', 'World'])
def launch(self):
self.root.mainloop()
def wait_update_label(self):
def update_label():
value = next(self.label_values)
self.label['text'] = value
update_period_in_ms = 1500
self.root.after(update_period_in_ms, update_label)
self.label['text'] = 'Waiting...'
if __name__ == '__main__':
app = MyApplication()
app.launch()

Categories