Creating a sub-process opens unwanted window - python

I'm currently developing a Windows application that requires the use of an .exe file I've created (called kill_game.exe in the below example). This .exe file accepts serialized objects as arguments. I call this .exe file using subprocess.Popen. When I do so, an exact copy of my current window opens and my .exe file won't run until I close the 2nd window myself. I'm completely stumped as to why it happens. I'd like the .exe file to run without the 2nd GUI opening itself. I tried to switch to multiprocessing as it exists in this example on SO, but that didn't work either.
Below, I'll post a simplified version (my original version is 300+ lines) of my code that illustrates the GUI and the function that is used to open the .exe file. I'll also post pictures of what happens when I press the button.
from tkinter import *
from tkinter import Tk
import subprocess
root = Tk()
sizex = sizey = 500
posx = posy = 100
root.wm_geometry("%dx%d+%d+%d" % (sizex, sizey, posx, posy))
myframe = Frame(root, relief=GROOVE, width=500, height=500, bd=1)
myframe.place(x=0, y=0)
canvas = Canvas(myframe)
frame = Frame(canvas)
canvas.pack(side="left")
canvas.create_window((0, 0), window=frame, anchor='nw')
button = Button(frame, text="Hello World")
button.grid(row=0, column=2)
games_to_stop = []
button.bind("<Button>",
lambda event, game_list=games_to_stop: some_function(game_list))
def some_function(game_list):
#This function is the function of interest, which is bound to my "Hello
#World" Button
child_script = r"C:\Users\Willy\AddictKiller\dist\kill_game.exe"
subprocess.Popen([child_script, game_list])
root.mainloop()
This is the GUI before the button is pressed:
This is the GUI and the 2nd GUI (which for some reason looks the the GUI of my non-simplified code) after the button is pressed:

I had a similar problem where when I run my program duplicates of my main Tkinter window would open and the function wouldn't run until I close all the duplicates.
you fix this by putting the part where the tkiner window is being created behind an if statement to make sure you only create a window in the main window as such
if __name__ == "__main__":
root = Tk()

Related

Open window on button click, close current window?

I have been searching for a solution for this issue, but I can't seem to find a viable answer.
I have the following code to open another tkinter script on button click:
# Program to Open on Button Click
def tkinter1():
ret = os.system('python C:\filepath\new_script.py"')
if ret:
# record updated, reload data
treeview_preview()
b1 = Button(master, text="New Window", command=tkinter1)
My problem I am facing is that I want the current window to close on the button click and only keep the new window open.
I know it is possible. I have this instance with many different windows and I seem to be stuck.
The unfortunate thing is that I have an entire different script for different parts of the beta software and the only way I could successfully run all of them is to access them as stated above.
I tried using the if ret: exit() command at the end with the same result. I have windows opening over and over again.
It seems simple, but I haven't been programming tkinter script for too long.(I still have a lot to learn)
All help is appreciated.
You can use master.withdraw(). I
made your code runnable with a few lines. Ok lets say your fixed main code is this:
import tkinter as tk
from tkinter import *
from seccond import *
from multiprocessing import Process
import os
def main():
master = tk.Tk()
# Program to Open on Button Click
def tkinter1():
master.withdraw()
master.destroy()
ret = Process(target=treeview_preview())
ret.start()
#if ret:
# # record updated, reload data
# treeview_preview()
#commented out bc i don't know what it is
b1 = Button(master, text="New Window", command=tkinter1)
b1.pack()
master.mainloop()
if __name__ == '__main__':
main()
the secondary code name seccond.py in the same folder as the main code is called as an external function but also as a separate process.
import tkinter as tk
def treeview_preview():
root = tk.Tk()
S = tk.Scrollbar(root)
T = tk.Text(root, height=4, width=50)
S.pack(side=tk.RIGHT, fill=tk.Y)
T.pack(side=tk.LEFT, fill=tk.Y)
S.config(command=T.yview)
T.config(yscrollcommand=S.set)
quote = """this is the seccond window."""
T.insert(tk.END, quote)
tk.mainloop()
The code will remove the window but not the terminal box as it will use it for the second script.

display single image in fullscreen mode (like powerpoint)

I am trying to open an image in fullscreen to overlap the taskbar and show no menu bar using python.
I got it to work using Tkinter with following code, but since its just a single image that does not need to be updated (ever), the blocking loop of mainloop() is very inconvenient and unnecessary. However, I can't get tkinter to stay open without that update loop. I've tried using root.after() to run the function afterwards but that froze my program (and isn't really what I want to do anyway)
root = tk.Tk()
root.update_idletasks()
root.attributes('-fullscreen', True)
root.overrideredirect(1)
output = self.create_image_from_array(image_array)
canvas = tk.Canvas(root, width=root.winfo_width(), height=root.winfo_height())
canvas.create_image(0, 0, image=output, anchor="nw")
canvas.pack(fill=tk.BOTH, expand=1)
# after freezes my window
# root.after(0,someFunction)
# main loop blocking the function.
root.mainloop()
How can I display a single image on the entire screen using python (in both windows and linux) or how can I "pause" the tkinter loop to prevent the window from closing and updating?
It looks like you will have to handle tkinter's thread yourself rather than relying on mainloop(). Here is one way to do it:
import tkinter as tk
from threading import Thread
import time
class SomeFunc:
def __init__(self):
self.running=True
t = Thread(target=self.func)
t.start()
def func(self):
self.root = tk.Tk()
self.root.update_idletasks()
#root.attributes('-fullscreen', True)
#root.overrideredirect(1)
canvas = tk.Canvas(self.root, width=self.root.winfo_width(), height=self.root.winfo_height())
#canvas.create_image(0, 0, image=output, anchor="nw")
canvas.pack(fill=tk.BOTH, expand=1)
while self.running:
self.root.update()
a = SomeFunc()
x = 10
while x:
x-=1
time.sleep(1)
print(x)

Using Python, how do you call a tkinter GUI from another GUI?

I created a couple of GUIs using tkinter. But now I am interested in combining them into one caller GUI. So the caller GUI would have buttons that, when clicked, would open the other GUIs. However, I cannot get it to work. I've done the imports correctly (I think), edited the main functions in the subGUIs, and added the command=GUI.main in my buttons. I get it to load but I get errors about missing files...but when I run a GUI by itself it works fine.
In my research, I read that there can only be one mainloop in a Tkinter program. Basically, I cannot use a Tkinter GUI to call another Tkinter GUI. Do you know what I can do different, for instance, can I create the caller GUI using wxPython and have it call all other GUIs that use Tkinter?
Thank you!
You can't "call" another GUI. If this other GUI creates its own root window and calls mainloop(), your only reasonable option is to spawn a new process. That's a simple solution that requires little work. The two GUIs will be completely independent of each other.
If you have control over the code in both GUIs and you want them to work together, you can make the base class of your GUI a frame rather than a root window, and then you can create as many windows as you want with as many GUIs as you want.
For example, let's start with a simple GUI. Copy the following and put it in a file named GUI1.py:
import tkinter as tk
class GUI(tk.Frame):
def __init__(self, window):
tk.Frame.__init__(self)
label = tk.Label(self, text="Hello from %s" % __file__)
label.pack(padx=20, pady=20)
if __name__ == "__main__":
root = tk.Tk()
gui = GUI(root)
gui.pack(fill="both", expand=True)
tk.mainloop()
You can run that GUI normally with something like python GUI1.py.
Now, make an exact copy of that file and name it GUI2.py. You can also run it in the same manner: python GUI2.py
If you want to make a single program that has both, you can create a third file that looks like this:
import tkinter as tk
import GUI1
import GUI2
# the first gui owns the root window
win1 = tk.Tk()
gui1 = GUI1.GUI(win1)
gui1.pack(fill="both", expand=True)
# the second GUI is in a Toplevel
win2 = tk.Toplevel(win1)
gui2 = GUI2.GUI(win2)
gui2.pack(fill="both", expand=True)
tk.mainloop()
Depending on your OS and window manager, one window might be right on top of the other, so you might need to move it to see both.
Thank you for the ideas. At first, your code wouldn't print the text on the toplevel window. So I edited it a little and it worked! Thank you. GUI1 and GUI2 look like:
import tkinter as tk
def GUI1(Frame):
label = tk.Label(Frame, text="Hello from %s" % __file__)
label.pack(padx=20, pady=20)
return
if __name__ == "__main__":
root = tk.Tk()
GUI1(root)
root.mainloop()
And then the caller looks like this:
from tkinter import *
import GUI1
import GUI2
def call_GUI1():
win1 = Toplevel(root)
GUI1.GUI1(win1)
return
def call_GUI2():
win2 = Toplevel(root)
GUI2.GUI2(win2)
return
# the first gui owns the root window
if __name__ == "__main__":
root = Tk()
root.title('Caller GUI')
root.minsize(720, 600)
button_1 = Button(root, text='Call GUI1', width='20', height='20', command=call_GUI1)
button_1.pack()
button_2 = Button(root, text='Call GUI2', width='20', height='20', command=call_GUI2)
button_2.pack()
root.mainloop()

Automatically Activate Main Window in TkInter

Is it possible to automatically activate the main window of a tkinter app? I am using Yosemite on a Mac. When the window comes up, the title bar is grayed out, and I have to click on the window before it will respond to events. The Tk manual says that event generate, "Generates a window event and arranges for it to be processed just as if it had come from the window system." I tried generating a <Button-1> event, but it had no effect. The manual goes on to say, "Certain events, such as key events, require that the window has focus to receive the event properly." I tried focus_force, but it didn't work either.
Is it possible to do what I want? Is this a Mac peculiarity? In the code below, the text changes as the mouse cursor enters and leaves the label, but the app is unresponsive until you click on the window.
import tkinter as tk
root = tk.Tk()
def visit(event):
kilroy['text'] = 'Kilroy was here.'
def gone(event):
kilroy['text'] = 'Kilroy has left the building'
def startup():
root.focus_force()
root.event_generate('<Button-1>')
frame = tk.Frame(root, width=500,height=100)
kilroy = tk.Label(frame, text="Kilroy hasn't been here.", width = 50)
kilroy.grid(row=0,column=0)
frame.grid(row=0,column=0)
kilroy.grid_propagate(0)
frame.grid_propagate(0)
kilroy.bind('<Enter>', visit)
kilroy.bind('<Leave>', gone)
root.after(100,startup)
root.mainloop()

Python Tkinter : Canvas with Image takes forever to execute

I've been experimenting a little with the Canvas function of Tkinter and tried to add some imagefile to the window, to test if i can create proper background images.The code so far seems to be working fine (atleast i get no errors when executing). But as soon as i try to execute the Python script it just takes forever to load and doesn't display a window or anything. As soon as i remove the Canvas block from my script it works fine.
from Tkinter import *
root = Tk()
root.title("ImageTest")
root.geometry("350x150")
root.minsize(350,150)
root.maxsize(350,150)
#***** Canvas *****
photo = PhotoImage(file="derp.gif")
w = Canvas(root, width=350, height=150)
w.pack()
w.create_image(0,0, anchor=NW, image=photo)
w.image = photo
root.mainloop()

Categories

Resources