Tkinter GUI - Can't pass argument to script - python

I've made a GUI with Tkinter and i linked a script to a button. I've also created a browse file option in my GUI and when i select a file i store it's path into a variable named "file". What i'm trying to do is click the button and run the script using the path i stored into the variable "file", but i get a 'no such file or directory error'. The solution must be pretty obvious but i just can't figure it out. Here's my GUI code:
from tkinter import *
from tkinter import filedialog
from tkinter import ttk
from tkinter import messagebox
import subprocess
window = Tk()
#modify window
window.title("Random Title")
window.geometry("600x400")
tab_control = ttk.Notebook(window)
#Creating tabs
tab1 = ttk.Frame(tab_control)
tab2 = ttk.Frame(tab_control)
#Modifying tabs
tab_control.add(tab1, text='Issue')
tab_control.add(tab2, text='Verify')
file = ""
var = StringVar()
var.set("")
w = Entry(tab2,textvariable=var)
w.grid(column=1,row=0)
#Creating button & actions
def issue():
subprocess.call('./issue_script.sh', shell=True)
messagebox.showinfo('Issue Certificate', 'Certificate issued successfully!')
btn = Button(tab1, text="Issue Certificate", command=issue)
btn.grid(column=1, row=5)
def browse():
file = filedialog.askopenfilename(filetypes = (("all files","*.*"),("Text files","*.txt")))
var.set(file)
print(file)
btn2 = Button(tab2, text="Browse", command=browse)
btn2.grid(column=3, row=0)
def verify():
subprocess.call(['./verify_script.sh', file], shell=True)
btn = Button(tab2, text="Verify Certificate", command=verify)
btn.grid(column=1, row=5)
tab_control.pack(expand=1, fill='both')
#event loop
window.mainloop()
I've also added a print(file) command so that i see what is stored in the variable and i get the correct result(the path i selected). Maybe the error is in the line i call the script subprocess.call(['./verify_script.sh', file], shell=True) or in the script itself. Here's the script code:
#!/bin/bash
echo "Verifying certificate..."
cd
python3 cert-issuer/cert-verifier/cert_verifier/verifier.py $1

I actually made it work, but i don't know why it does.
All i changed was instead of calling my script like this
subprocess.call(['./verify_script.sh', var.get()], shell=True)
i omitted the shell=True command and the argument passes correctly into the script.
So i called subprocess.call(['./verify_script.sh', var.get()]) and it works just fine but i can't think why. Any explanation is much appreciated.

Related

Trying to run .ahk files in tkinter

this is my first time here so if I break some unwritten rules please don't shoot me
I've been trying build an app for editing, reading and opening .ahk files. The last one gives me problems.
this code kind of does what I want except it fires the command immediately after opening the app.
from tkinter import *
from tkinter import filedialog
import os
import threading
root = Tk()
def openfile():
os.system( r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk')
def func():
print("hello")
btn1 = Button(text='programma', command=threading.Thread(target=openfile).start())
btn2 = Button(text='ander ding', command=func)
btn1.pack()
btn2.pack()
root.mainloop()
Any help would be much appreciated!
Change the following line (it just assigns the result of threading.Thread(...) to command option):
Button(text="run program1", command=threading.Thread(target=lambda: os.system(r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk').start()))
to
Button(text="run program1", command=lambda: threading.Thread(target=lambda: os.system(r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk')).start())
or
Button(text="run program1", command=lambda: threading.Thread(target=os.system, args=[r'\Users\merijn\PycharmProjects\infoprojectP3\venv\Scripts\ahkScript1.ahk']).start())
Same for buttons of run program2 and run program3.
Update: based on your updated code, you need to change the following line:
btn1 = Button(text='programma', command=threading.Thread(target=openfile).start())
to
btn1 = Button(text='programma', command=lambda: threading.Thread(target=openfile).start())

How would I continue to run code after importing a Tkinter file?

So I'm trying to use a Tkinter window as an output log. My main program is a command line interface, so if the output from the "side programs" that run fills up the python console, it can ruin the user experience.
I have the Tkinter output log program in a seperate file, which I import into my main file. This is the gyst of the Tkinter file I created:
import time
from datetime import datetime
root = Tk()
root.configure(background='black')
root.geometry('700x460')
console = Listbox(root, width=40000, height=30000, font=('Lucida Console', 14), relief=FLAT, bg='black',
fg='white',
borderwidth=0, highlightbackground='black', selectbackground='black',
selectforeground='white')
console.pack()
def log(what_to_log):
now = datetime.now()
console.insert('[' + now.strftime("%H:%M:%S") + ']: ' + what_to_log)
root.mainloop()
So I import it into my main program like so:
# this is the file with the Tkinter code
import Logs
Logs.log('Test')
The issue is that the main program doesn't continue running after importing Logs, it just stops, and continues to run the mainloop in the Logs file.
So my question is, how could I get both files to continue running, while also being able to update the Tkinter listbox via the log function??
You should not execute root.mainloop() as it will block your console application. Use root.update() at the end of log() to force tkinter to update the list box. Also there is syntax error in console.log(...).
Below is a modified Logs.py:
from tkinter import *
from datetime import datetime
root = Tk()
root.configure(background='black')
root.geometry('700x460')
console = Listbox(root, font=('Lucida Console', 14), relief=FLAT, bg='black', fg='white',
borderwidth=0, highlightbackground='black', selectbackground='black',
selectforeground='white')
console.pack(fill='both', expand=1)
def log(what_to_log):
now = datetime.now()
console.insert('end', '['+now.strftime("%H:%M:%S")+']: '+what_to_log)
console.see('end') # make sure last log is visible
root.update() # force tkinter to update

How do you execute another file when a button is pressed(tkinter) in Python?

I'm trying to make a launcher for another program but I just started with Python so I made a button, but I struggle to figure out how to execute another .py file. Any help?
When the button is pressed it activates the open_file() function and os opens the .py script.
from tkinter import *
import os
def open_file():
os.system('python file path here')
root=Tk()
btn = Button(root, text='Open .PY File', command=open_file)
btn.pack()
root.mainloop()
Here is a solution using from subprocess import call. All you have to do is replace 'YOUR_FILE_NAME' with... your file name :D
from tkinter import *
from subprocess import call
root=Tk()
root.geometry('200x100')
frame = Frame(root)
frame.pack(pady=20,padx=20)
def Open():
call(["python", "YOUR-FILE-NAME.py"])
btn=Button(frame,text='Open File',command=Open)
btn.pack()
root.mainloop()
What it will look like:
I hope this works for you :D

Show command line results in Tkinter text widget

I want the output of a Python script in a Tkinter text widget instead of in the command line. I have this script from https://stackoverflow.com/a/665598/3524043:
from Tkinter import *
import subprocess as sub
p = sub.Popen('./Scripts/Speedtest.py',stdout=sub.PIPE,stderr=sub.PIPE, shell=True)
output, errors = p.communicate()
root = Tk()
text = Text(root)
text.pack()
text.insert(END, output)
root.mainloop()
I've added shell=true at the subprocess, cause I had a OSError: [Errno 13] Permission denied.
When I run the program there's only an empty text widget.
Edited with a better solution:
Import the script and call the objects
from Tkinter import *
from Speedtest import ping_speed, download_speed, upload_speed
root = Tk()
text = Text(root)
text.insert(INSERT, ping_speed)
text.insert(END, download_speed)
text.pack()
mainloop()
Based on this answer you can do it fairly simply with the below code:
import subprocess # required for redirecting stdout to GUI
try:
import Tkinter as tk # required for the GUI python 2
except:
import tkinter as tk # required for the GUI python 3
def redirect(module, method):
'''Redirects stdout from the method or function in module as a string.'''
proc = subprocess.Popen(["python", "-c",
"import " + module + ";" + module + "." + method + "()"], stdout=subprocess.PIPE)
out = proc.communicate()[0]
return out.decode('unicode_escape')
def put_in_txt():
'''Puts the redirected string in a text.'''
txt.insert('1.0', redirect(module.get(), method.get()))
if __name__ == '__main__':
root = tk.Tk()
txt = tk.Text(root)
module = tk.Entry(root)
method = tk.Entry(root)
btn = tk.Button(root, text="Redirect", command=put_in_txt)
#layout
txt.pack(fill='both', expand=True)
module.pack(fill='both', expand=True, side='left')
btn.pack(fill='both', expand=True, side='left')
method.pack(fill='both', expand=True, side='left')
root.mainloop()
given that the module is in the same directory. The code returns console output of a method or a function(rightmost entry) in a module(leftmost entry) as a string. It then puts that string in a Text field.
See this answer for Returning all methods/functions from a script without explicitly passing method names.

Simplest way to open a file in tkinter

trying to make a GUI with an 'open file' button. When I run the code shown below, the open file dialog opens straight away, and not when I press the button. Why? Is there a simple way to fix this that doesn't involve using classes? (I don't currently know anything about classes and am working on a time-pressured project)
from tkinter import *
interface = Tk()
def openfile():
return filedialog.askopenfilename()
button = ttk.Button(interface, text = "Open", command = openfile())
button.grid(column = 1, row = 1)
interface.mainloop()
The code is passing the return value of the openfile function call, not the function itself. Pass the function itself by removing trailing () which cause a call.
from tkinter import *
from tkinter import ttk
from tkinter import filedialog
interface = Tk()
def openfile():
return filedialog.askopenfilename()
button = ttk.Button(interface, text="Open", command=openfile) # <------
button.grid(column=1, row=1)
interface.mainloop()

Categories