When I choose either on the first window and then the second window are apparent, but the first window not missing.
from tkinter import *
import subprocess
master = Tk()
master.title("CPG")
master.geometry('460x430')
master.P1 = PhotoImage(file=r"A1.png")
master.P2 = PhotoImage(file=r"A2.png")
def program1():
subprocess.Popen("E://Game Online//Steam//Apex.exe)
def program2():
subprocess.Popen("E://Game Online//Steam//Steam.exe")
def close():
master.destroy()
master.quit()
Button(master,image=master.P1, command=program1).pack(side=TOP)
Button(master,image=master.P2, command=program2).pack()
master.mainloop()
For example, running program:
There are 2 choice for my program:
choose for running by Apex Steam and
choose for running by Apex Origin.
When I choose either on the first window, the second window appears; but the first window does not disappear. How can I fix it?
Related
I ran into a probleme when coding a bigger project (at least for me as an absolute newby). I want to open a new tk-window with some text and an image by pressing a Button from another tk-window. I created a code for demonstration.
import tkinter as tk
def fct():
testwin = tk.Tk()
testbutt1 = tk.Button(testwin, text="Button1").pack()
img = tk.PhotoImage(master=testwin,file="picture.png")
imglabel = tk.Label(root,image=img)
imglabel.pack()
testbutt2 = tk.Button(testwin, text="Button2").pack()
testwin.mainloop()
root = tk.Tk()
picbutt = tk.Button(root,text="Exit",command=fct).pack()
label = tk.Label(root)
label.after(5000, fct)
root.mainloop()
This code throws error: "_tkinter.TclError: image "pyimage1" doesn't exist"
When I exchange
img = tk.PhotoImage(master=testwin,file="picture.png")
to
img = tk.PhotoImage(testwin,file="picture.png")
I get error: "images may not be named the same as the main window"
Changing import tkinter as tk to from tkinter import * sadly doesn't change anything either. It also doesnt matter if fct() is called by pressing the button or waiting 5 seconds (label.after(5000, fct))
Python stops executing code at this point. Meaning, testbutt1 shows up, testbutt2 does not.
Hope this explaination is enough to describe the probleme. Thanks for your answers :)
Tkinter button only runs a separate script once
Hello all, Im a new to python and raspberry pi and have been searching high and low on how to get a Tkinter button to run a script more than once on my raspberry pi. From research I believe it has something to do with name="main", but I cant figure out what needs to be done and why. My button runs a separate python file (called SendRF.py) in the same directory that generates an RF signal, it works the first time but then the button click does nothing else after. Any advice would be much appreciated :)
from tkinter import *
#create a window
window =Tk()
window.title("Chappers Home Automation project")
#define a function
def test_function ():
import SendRF
#create a button
B = Button(text ="Test Button 1", command=test_function)
B.pack(padx = 100, pady = 50)
window.mainloop()
No error messages appear. The button sends the RF signal when pressed the first time, but nothing happens for further button clicks.
You can't import a module multiple times. Each additional import for the same module is a NOP. You need to functionize whatever is in sendRF, and call that function in test_function.
You can check if the function is working correctly by adding a simple print statement inside your function
from tkinter import *
#create a window
window =Tk()
window.title("Chappers Home Automation project")
#define a function
def test_function ():
import SendRF
print('CHECK')
#create a button
B = Button(text ="Test Button 1", command=test_function)
B.pack(padx = 100, pady = 50)
window.mainloop()
It is working one time, cause you alredy have the SendRf function mported, you need to close it, after to import again
Imagine there are two Tkinter.Toplevel() windows, called Window_1 and Window_2, which can be opened by clicking the same button (lets called Button_0).
Button_0 is pressed and Window_1 pops up. In Window_1, I can scroll up and down using a mouse pad (MAC OS). After that, I left Window_1 open.
Button_0 is pressed again and Window_2 pops up, while Window_1 stays open. In Window_2, I can again scroll up and down.
Now, I go back to Window_1 and try to scroll using mouse pad, contents in Window_1 DO NOT MOVE, but contents in Window_2 DO MOVE.
Then I close Window_2, and try to scroll on Window_1, this time I got error messages asking for a canvas on Window_2.
I did bind function,
def on_vertical(canvas,event):
canvas.yview_scroll(-3 * event.delta, 'units')
to a canvas inside each windows. As far as I know about the error, it seems that this function could not be used twice at the same time (both windows are opened).
I would like the way that when both Windows stay open. While on each window, I can scroll up-down while the another one do not move. Is it possible to code that?
This is the code example (please do noted that the Window name is not corrected label.)
from tkinter import *
######################## FUNCTIONS (DEF) ########################
def on_vertical(canvas,event):
canvas.yview_scroll(-3 * event.delta, 'units')
######################## FUNCTIONS (CLASS) ########################
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
#INITIAL WINDOW
def init_window(self):
self.master.title("Main Window")
self.pack(fill=BOTH, expand=1)
Button(self, text="Button_0",command = self.load_and_print).place(x = 7, y = 95)
# creating a button instance
Button(self, text="EXIT PROGRAM", command=self.client_exit).place(x=500, y=250)
#OPEN A NEW WINDOW CONTAINING STOCK LISTS
def load_and_print(self):
new_window = Toplevel(self)
new_window.title("Window")
canvas = Canvas(new_window, width = 800, height = 500, scrollregion = (0, 0, 0, 2500))
frame = Frame(canvas)
vbar = Scrollbar(new_window, orient = VERTICAL, command = canvas.yview)
vbar.pack(side = RIGHT,fill = Y)
canvas.create_window(0,0, window = frame, anchor = NW)
canvas.config(yscrollcommand = vbar.set)
canvas.pack(side = TOP,expand = True,fill = BOTH)
canvas.bind_all('<MouseWheel>', lambda event, canvas=canvas: on_vertical(canvas,event))
#MAKE PROGRAM EXIT
def client_exit(self):
exit()
######################## MAIN PROGRAMME ########################
#call window
root = Tk()
#size of the window
root.geometry("700x300")
app = Window(root)
root.mainloop()
root.update()
The problem is that you are using bind_all instead of bind for the mousewheel event.
Because you're using bind_all, each time you create a new window it replaces the old binding with a new binding. No matter which window gets the event, your function will always only work for the last window to be created. And, of course, when that window is destroyed then the mouse binding will throw an error since the canvas no longer exists.
Using bind
One solution is simple: use bind instead of bind_all.
canvas.bind_all('<MouseWheel>', lambda event, canvas=canvas: on_vertical(canvas,event))
Using bind_all
If you want the benefits of bind_all -- namely, that the scrolling works even if the mouse is over some other widget, you need to modify on_vertical to figure out which canvas to scroll at the time that it is running instead of having the canvas being passed in.
You can do that with a little bit of introspection. For example, the event object knows which widget received the event. From that you can figure out which window the mouse is in, and from that you can figure out which canvas to scroll.
For example, move the binding up to the __init__ and change it like this:
self.bind_all('<MouseWheel>', on_vertical)
Next, change on_vertical to figure out which canvas to scroll. In the following example I assume each toplevel has exactly one canvas and that you always want to scroll that canvas (ie: you lose the ability to scroll text widgets and listboxes)
If that's not the case, you can add whatever logic you want to figure out which widget to scroll.
def on_vertical(event):
top = event.widget.winfo_toplevel()
for child in top.winfo_children():
if child.winfo_class() == "Canvas":
child.yview_scroll(-3 * event.delta, 'units')
break
UPDATE : The problem was solved by removing the window.mainloop() in my second function.
I'm trying to make a game in Python 3.7 using tkinter.
The game begins with a menu (button-widgets in a frame). Clicking in the 'Play' button should open another menu using a different frame. This second menu should contain a 'back' button to return to the first menu.
Each menu is defined in a function. So to go from the main menu to the play menu I call the function playMenu(window) in the function used as command by the 'Play' button.
It looks like this :
def clickButtonPlay():
menuFrame.grid_remove()
playMenu(window)
menuFrame.grid()
In the play menu, the function used as 'back button' command put an end to the function by destroying its frame and using return.
So the program should get back to the clickButtonPlay() function and show the frame of the main menu back, but instead I get a tkinter error :
_tkinter.TclError: can't invoke "grid" command: application has been destroyed
But my frame menuFrame hasn't been destroyed, just un-grid!
Can anyone help me understand what's wrong with the code or find an easier way to do the same thing?
Thank you very much!
Here's a sample of how my program works:
mainMenu file :
import tkinter as tk
from PlayMenu import playMenu
window = tk.Tk()
window.grid()
def menu(window):
def clickButtonPlay():
menuFrame.grid_remove()
playMenu(window)
menuFrame.grid()
menuFrame = tk.Frame(window)
menuFrame.grid()
background = tk.Label(menuFrame, image= backgroundImage)
background.grid()
playButton = tk.Button(menuFrame, image= playButtonImage[0], command= clickButtonPlay)
playButton.place(relx= 0.5, rely= 0.15)
window.mainloop()
menu(window)
playMenu file :
class MyError(Exception):
pass
def _playMenu(window):
def clickButtonBack():
playMenuFrame.destroy()
raise MyError
playMenuFrame = tk.Frame(window)
playMenuFrame.grid()
background = tk.Label(playMenuFrame, image= backgroundImage)
background.grid()
backButton = tk.Button(playMenuFrame, image= backButtonImage[0], command= clickButtonBack)
backButton.place(relx=0.375, rely=0.8)
window.mainloop()
def playMenu(window):
try:
return _playMenu(window)
except MyError:
return
The problem (or at least a problem) is that you're calling mainloop more than once. Each time you call it, a new infinite loop is created. The new loop won't exit until the main window is destroyed. Once that happens, the previous loop will likely throw errors since the widgets it's managing no longer exist.
I would like to bind a menu item to a notebook frame using a function(like gotofirst tab).
for instance a menu: file with 3 item such that if I click on the 3rd item in the menu file, the 3rd tab in the notebook should be selected or it should go to the 3rd tab and at the same time not see other tabs(hide them or disable them).
from tkinter import *
from tkinter import ttk
### defining functions ###
def GotoFirst():
pass
def Gotosecond():
pass
def Gotothird():
pass
### Frame and notebook ###
root = Tk()
root.geometry('1000x700+1000+40')
root.resizable(FALSE,FALSE)
root.rowconfigure(0,weight=1)
root.columnconfigure(0,weight=1)
root.title("Test Fieldbook")
fieldbook = ttk.Notebook(root)
f1 = ttk.Frame(fieldbook);
f2 = ttk.Frame(fieldbook);
f3 = ttk.Frame(fieldbook);
fieldbook.add(f1, text="1st")
fieldbook.add(f2, text="2nd")
fieldbook.add(f3, text="3rd")
fieldbook.grid(row=0, column=0, sticky=(N,W,S,E))
### Creating menu bar ###
menubar=Menu(root)
filemenu=Menu(menubar)
filemenu.add_command(label="Help Docs",command=GotoFirst)
filemenu.add_command(label="About ESB",command=Gotosecond)
filemenu.add_command(label="About ESB",command=Gotothird)
menubar.add_cascade(label="Help",menu=filemenu)
root.config(menu=menubar)
root.mainloop()
You can use the select method:
fieldbook.select(0)
and
fieldbook.select(f1)
do the same thing.
Thank you for the hint, I manage to make it work.
fieldbook.tab(f1, state='normal')
fieldbook.select(f1)
fieldbook.hide(f3)
with .tab() I can change the state as I wish and with .hide() I can make a specific tab disappear momentarily and call it back anytime with .add()