2

Here is what I coded...

import tkinter as tk
import subprocess
import sys
import time
import os
import tkinter.font as font
from tkinter.ttk import *

app = tk.Tk()
app.geometry("400x400")
app.configure(bg='gray')

photo = tk.PhotoImage(file=r"C:\Users\ex\ex_button_active.png")
myFont = font.Font(family='Helvetica', size=20, weight='normal')

tk.Label(app, text='EX', bg='gray', font=(
    'Verdana', 15)).pack(side=tk.TOP, pady=10)
app.iconbitmap(r'C:\Users\ex\ex_icon.ico')

start = time.time()
cmd = sys.executable + " -c 'import time; time.sleep(2)' &"
subprocess.check_call(cmd, shell=True)
assert (time.time() - start) < 1

p = subprocess.Popen(cmd, shell=True)


def ex_activation():
    #Python Code
    #Python Code...

def ex_stop():
    sys.exit(ex_activation) #This area is basically where I have a button to terminate the other script running. 
            #I have tried sys.exit() and had the same result

ex_activation_button = tk.Button(app,
                                    bg='black',
                                    image=photo,
                                    width=120,
                                    height=120,
                                    command=ex_activation)
ex_stop_button = tk.Button(app,
                              bg='Gray',
                              text='ex',
                              width=12,
                              command=ex_stop
                              height=3)
ex_stop_button['font'] = myFont

app.title("Example")
ex_activation_button.pack(side=tk.TOP)
ex_stop_button.pack(side=tk.LEFT)

app.mainloop()

I am looking for a way to get my program to stop the program the other button runs. I realized that this maybe be a "self destruct button" but I don't know how to do this with the script the other button runs. Any help greatly appreciated! I tried killing the code by putting the def ex_activation in the p.kill This did not work...

5
  • wait wait, what does the other python script contain? is it also tkinter? its best to import it rather than executing it. Try root.destroy() to get out of your current script Commented Aug 13, 2020 at 6:39
  • The other python script isnt really the problem. Its terminating it. Also, importing the python script wouldnt allow my button to run it when pressed right? And if I could, how would I do that? Commented Aug 13, 2020 at 7:21
  • put all of your code in the new script inside of a function and import that function and run it with the button? Commented Aug 13, 2020 at 7:59
  • I mean it sounds right but 1470 lines of code in the other script with it's own seperate functions doesn't feel right. Commented Aug 13, 2020 at 8:19
  • give it a try? all you have to do is define a new function and indent the rest of the code inside of it? if you think its not safe, then create a backup too Commented Aug 13, 2020 at 8:24

1 Answer 1

2

If the other python script is made to run forever (has some kind of while True:), you can't run it on the command line as you did, because it will freeze your window while that script is running.

In order to run a python script on background you will need to do it with the subprocess library. (Find out here)

I also found an answer of another question that uses check_ouput() in order to know when the python program has finished. This can also be useful if you want to send a status to the tkinter app: you can print("33% Complete"), for example. You could add this in tkinter's main loop, so you always know if your program is running or not.

And last but not least, to kill that process (using the stop button), you should do it using os, and looking for the subprocess' ID. Here you can also find a good example.

I would try something like this:

cmd = "exec python file.py"
p = subprocess.Popen(cmd, shell=True)
# Continue running tkinter tasks.
tk.update()
tk.update_idletasks() # These both lines should be inside a while True
# Stop secondary program
p.kill()

EDIT

Example code using your question's code. WARNING: I have changed the png file location for testing, commented the app icon, and tested ONLY on Windows.

It's important to remove the mainloop() on the main file and put update...() in order to catch the keyboardInterrupt that (I don't know why) is killing both parent and child process.

I invite you to try it and be as happy as I have been when it was working after half an hour of testing!!

File 1: daemon.py - this file will run forever.

from time import sleep
from sys import exit

while True:
    try:
        print("hello")
        sleep(1)
    except KeyboardInterrupt:
        print("bye")
        exit()

File 2: tkinterapp.py - The name is self-explainatory

import tkinter as tk
import subprocess
import sys
import time
import os
import tkinter.font as font
from tkinter.ttk import *

app = tk.Tk()
app.geometry("400x400")
app.configure(bg='gray')

photo = tk.PhotoImage(file=r"C:\Users\royal\github\RandomSketches\baixa.png")
myFont = font.Font(family='Helvetica', size=20, weight='normal')

tk.Label(app, text='EX', bg='gray', font=(
    'Verdana', 15)).pack(side=tk.TOP, pady=10)
# app.iconbitmap(r'C:\Users\ex\ex_icon.ico')


def ex_activation():
    global pro
    print("running!")
    pro = subprocess.Popen("python daemon.py", shell=True)

def ex_stop():
    global pro
    print("stopping!")
    os.kill(pro.pid, 0)

ex_activation_button = tk.Button(app,
                                    bg='black',
                                    image=photo,
                                    width=120,
                                    height=120,
                                    command=ex_activation)
ex_stop_button = tk.Button(app,
                              bg='Gray',
                              text='ex',
                              width=12,
                              command=ex_stop, # BE CAREFUL You were missing a "," here !!!
                              height=3)
ex_stop_button['font'] = myFont

app.title("Example")
ex_activation_button.pack(side=tk.TOP)
ex_stop_button.pack(side=tk.LEFT)

# app.mainloop()
while True:
    try:
        app.update()
        app.update_idletasks()
    except KeyboardInterrupt:
        pass
Sign up to request clarification or add additional context in comments.

9 Comments

This looks great and I will try this. If it works, I will accept the answer. The other program does infinitely run until I stop the process in the IDE or the program encounters an error and automatically stops. But the program will run when the button is pressed. It runs in the background. The issue is in stopping the program with the stop button that the other button executed.
Okey, let me know if I can help you with anything else ;)
I did the above comment from Cool Cloud. Now all of it is in one python file. The kill button doesn't work. I updated the question with the new code...
If you only have one python file, you will not be able to call the same python file in the terminal, to perform a different job. But i think you forgot the exec at the beginning of the command, so that's why a p.kill() wouldn't work. On the link above they stated that this "exec" was important in order to stop the program, so maybe consider trying it :)
WOW! It was incredible seeing it work! If I have an issue with any tkinter programs, I would totally come to you :)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.