Python program will only run from IDLE - python

This is my first run at python and i am by no means a code writer. I have a project that I needed to write a GUI to command the arduino and after much googling and piecing together code I made this program which works perfectly when ran from IDLE. When I launch it from windows (double click it) or from linux (via command line python3 filler.py) it opens and closes like there is an error. I can launch other python programs by same methods with no problems. Where as its not an issue to launch it out of IDLE to make the hardware operate I just cant give up as I would like to get more knowledgeable with python for future projects. Any help would be greatly appreciated.
import tkinter as tk
import serial as s
import time as t
from tkinter import *
class Action:
def __init__(self):
def on():
ser.write(b'7')
def exit():
ser.close() # close serial port
quit()
self.window = Tk()
self.window.title("Moore Speciality Brewing")
self.window.geometry('640x480')
self.lbl = Label(self.window, text="Can Filler",fg='black',font=(None, 15))
self.lbl.place(relx=0.24, rely=0.10, height=50, width=350)
bo = Button(self.window, text="Fill Can", width=10 ,bg='red' ,command=on)
bo.place(relx=0.34, rely=0.30, height=40, width=200)
ext = Button(self.window, text="Exit", width=10, bg='white', command=exit)
ext.place(relx=0.34, rely=0.50, height=40, width=200)
class Prompt(tk.Tk):
def __init__(self):
global comm
comm = None
tk.Tk.__init__(self)
self.geometry('640x480')
self.label = tk.Label(self, text="Comm Port",fg='black',font=(None, 15))
self.entry = tk.Entry(self)
self.button = tk.Button(self, text="Get", command=self.on_button)
self.entry.place(relx=.5, rely=.5,anchor="center" )
self.label.place(relx=.5, rely=.44,anchor="center")
self.button.place(relx=.5, rely=.56,anchor="center")
def on_button(self):
comm = self.entry.get()
global ser
ser = s.Serial(comm, 9600, timeout=0) # check your com port
t.sleep(2)
Action()
self.destroy()
Prompt()

You need to call the mainloop.
Remove the call to Prompt() (last line) and substitute it with something like this (at the bottom of the script):
if __name__ == "__main__":
prm = Prompt()
prm.mainloop()
Here more on tkinter mainloop

you have already imported time in your code.
just use t.sleep(60) at the end of your code to make the cli wait for you to see if there is an error and let you debug.
at the end Prompt() is not correct. use something like this:
myPrompt = Prompt()
myPrompt.mainloop()
this part actualy calls the tkinter gui.

Related

how to close a Thread from Tkinter While the Thread is running Python selenium

So, I made a small canvas window with tkinter which has 2 buttons, One is a start button, the other is a stop button. (I'll attach the GUI tkinter code down below. I wont add the Selenium part because I don't want to confuse anyone with mushed up code.) The start button calls a function thats threaded and that launches my "Reporting_Backbone.py" which is a selenium/pyautogui bot that does a bunch of stuff. My problem is that the stop button does not stop the "Reporting_Backbone.py". In the stop button function I've tried sys.exit() but the selenium and the GUI stay open (and running), I've tried daemons (which I might not have been using them correctly because that did nothing)I've tried setting the stop button function to a lambda (which just freezes the GUI, but not the selenium part) and I've tried setting up some kind of a killswitch as a last resort but honestly this thing wont die, its like Thanos fused with Majin Buu. It just keeps running. How do I make it so that the stop button works? I I'm hoping someone can help me with a solution and explanation. I am still new to coding but I am really loving it, if possible I would really like to understand what I am doing wrong. Thank you.
enter code here
import tkinter as tk
from PIL import Image, ImageTk
import time
import os
import threading
import sys
root = tk.Tk()
#Canvas for GUI
canvas = tk.Canvas(root, width=600, height=800)
canvas.grid(columnspan=3, rowspan=4)
canvas.configure(bg="#b9be9c")
#Button Starting
def start_report():
time.sleep(0.5)
start_text.set("Armed!")
os.system("python Reporting_Backbone.py")
#Button Stopping
def stop_craigslist():
stop_text.set('Stopped')
time.sleep(3)
sys.exit()
#Logo
logo = Image.open('Logo.png')
logo = ImageTk.PhotoImage(logo)
logo_label = tk.Label(image=logo)
logo_label.image = logo
#playing logo in window
logo_label.grid(column=1, row=0)
logo_label.configure(bg="#b9be9c")
#instructions
instructions = tk.Label(root, text="Click the 'Start' Button to begin.")
instructions.grid(columnspan=3, column=0, row=1)
instructions.configure(font=("Helvetica", 25) ,bg="#b9be9c")
#Start Button
start_text = tk.StringVar()
start_btn = tk.Button(root, textvariable=start_text, command=threading.Thread(target=start_report).start, font=("Helvetica", 18), fg="black", height=2, width=15)
start_text.set("Start")
start_btn.grid(column=1, row=2)
#Stop Button
stop_text = tk.StringVar()
stop_btn = tk.Button(root, textvariable=stop_text, command=threading.Thread(target=stop_craigslist).start, font=("Helvetica", 18), fg="black", height=2, width=15) #If I set this to a lambda function the Tkinter GUI Freezes up on me
stop_text.set("Stop")
stop_btn.grid(column=1, row=3)
root.mainloop()
You cannot stop the task created by threading.Thread(). Use subprocess instead:
import subprocess
...
proc = None
def start_report():
global proc
if proc and not proc.poll():
print("process is still running")
return
proc = subprocess.Popen([sys.executable, "Reporting_backbone.py"])
start_text.set("Armed!")
def stop_craigslist():
global proc
if proc:
proc.terminate()
proc = None
stop_text.set('Stopped')
...
start_btn = tk.Button(root, ..., command=start_report, ...)
...
stop_btn = tk.Button(root, ..., command=stop_craigslist, ...)
...

I am writing a UI for an external program using Tkinter. How could I redirect any print statements to widget in tkinter? Almost like a live log

This is the current UI script I have written...
import tkinter as ttk
import subprocess
import sys
import time
import os
import tkinter.font as font
from tkinter.ttk import *
app = ttk.Tk()
app.geometry("400x400")
app.configure(bg='gray')
photo = ttk.PhotoImage(file=r"C:\Users\ex\ex_button_active.png")
myFont = font.Font(family='Helvetica', size=20, weight='normal')
ttk.Label(app, text='Ex', bg='gray', font=(
'Verdana', 15)).pack(side=ttk.TOP, pady=10)
app.iconbitmap(r'C:\Users\ex\ex_icon.ico')
def ex_activation():
global pro
print("Running program!")
pro = subprocess.Popen("python programex.py", shell=True)
def ex_stop():
global pro
print("Stopping Program... Please Wait!")
os.kill(pro.pid, 0)
ex_activation_button = ttk.Button(app, bg='black', image=photo, width=120, height=120, command=ex_activation)
ex_stop_button = ttk.Button(app, bg='Gray', text='Stop Program', width=12, command=ex_stop, height=3)
ex_stop_button['font'] = myFont
app.title("Ex")
ex_activation_button.pack(side=ttk.TOP)
ex_stop_button.pack(side=ttk.LEFT)
# app.mainloop()
while True:
try:
app.update()
app.update_idletasks()
except KeyboardInterrupt:
pass
The main goal is to take ANY print statements from the external script and have them printed to a tkinter widget line by line. I wanted to use the stdout method. Here is a post I Had Found that May Help Thank you in advance to anyone that can help me achieve this goal.
You could use a ttk.Label() to show the last printed line on your GUI. You could try this:
# Insert a label on your window
lab = ttk.Label(root, text="Some text")
lab.pack()
# Change the label text
def update_label(print_output):
lab.configure(text=print_output)
If you prefer having all the lines, you could use a textarea instead of a Label and append the lines instead of replace them.
To get the program output you could do it in multiple ways:
Overload the python print() function, and add a line to call update_label(text). See more here, but it's a little bit tricky.
Replace all print() to your_print() so you can add the line above in a separate function, like this:
# You will need to make sure to only give one argument, and it should be a string.
def your_print(text):
update_label(text)
print(text)
The last one will come useful if you can't modify the other program, let's say it's already compiled. You could run the output of that program into a file (SomeCommand > SomeFile.txt), and then every second or so, your tkinter app could call update_label(). An example:
## REPLACE root.mainloop() for this:
# These three lines are the equivalent of mainloop()
while True:
root.update()
root.update_idletasks()
with open('somefile.txt') as filein:
last_line = filein.read().split('\n')[-1]
update_label(last_line)

Tkinter progress bar during telnet session

I want to push some configlines through a telnetsession from a tkinter gui.
Simplified; in my GUI I have a button. After pressing this button the telnet session starts (it fetches the config lines from an external fileshare).
But at this moment it is not very user friendly, there is now way to tell whether it is still busy or not. I want to fix this by a progress bar popup.
I've got my main script with all the fetching of the configuration files, adapting and sending it to a switch.
I got a "standalone" script with the popup progress bar.
Now I want to combine those two, but it won't work. I've read about multi-threading, but since I'm new to coding I need some help to understand how this works, if it is needed in my case
The mainscript:
#window stuff
window = Tk()
window.geometry('700x500')
window.title("Switchconfig generator")
window.lift()
def btntelnetclicked():
try:
telnet()
except:
messagebox.showinfo("Status", "Something went wrong, config was not pushed.")
#buttons
btntelnet= Button(window, text="Push config", command=btntelnetclicked)
btntelnet.grid(column=2, row=4, padx=10, pady=10)
This is offcourse just a little piece of code
The progressbar
import threading
try: import tkinter
except ImportError:
import Tkinter as tkinter
import ttk
else: from tkinter import ttk
class GUI_Core(object):
def __init__(self):
self.root = tkinter.Tk()
self.progbar = ttk.Progressbar(self.root)
self.progbar.config(maximum=4, mode='indeterminate')
self.progbar.pack()
self.b_start = ttk.Button(self.root, text='Start')
self.b_start['command'] = self.start_thread
self.b_start.pack()
def start_thread(self):
self.b_start['state'] = 'disable'
self.progbar.start()
self.secondary_thread = threading.Thread(target=arbitrary)
self.secondary_thread.start()
self.root.after(50, self.check_thread)
def check_thread(self):
if self.secondary_thread.is_alive():
self.root.after(50, self.check_thread)
else:
self.progbar.stop()
self.b_start['state'] = 'normal'
def arbitrary():
btntelnetclicked()
gui = GUI_Core()
gui.root.mainloop()

How to quit tkinter window with schedule running?

I am creating a scheduler for a few different python scripts and I am using a tkinter window to take in the usernames and passwords for the servers I am accessing.
I seem to be able to get the scheduler to work, but when it does, it now breaks the mainloop so the window no longer responds.
I have tried putting the mainloop inside the loop that keeps the schedule running, but that causes the scheduler to stop functioning.
import tkinter as tk
import subprocess
import schedule
import time
class MainWindow(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.e_user_label = tk.Label(self, text="Email Username")
self.e_pw_label = tk.Label(self, text="Email Password")
self.e_account_label = tk.Label(self, text="Email Account")
self.email_user = tk.Entry(self, width=30)
self.email_pw = tk.Entry(self, show="*", width=30)
self.email_account = tk.Entry(self, width=30)
self.start_scheduler = tk.Button(self, text="Start Scheduler",
command=self.check_email_request)
self.e_user_label.pack()
self.email_user.pack()
self.e_pw_label.pack()
self.email_pw.pack()
self.e_account_label.pack()
self.email_account.pack()
self.start_scheduler.pack()
def check_email_request(self):
call_email_script = 'call python email_monitor.py {} {} {}'.format(self.email_user.get(),
self.email_pw.get(), self.email_account.get())
completed = subprocess.run(call_email_script, shell=True)
print('returncode:', completed.returncode)
def print_stuff(self):
schedule.every(1).minutes.do(self.check_email_request)
while True:
schedule.run_pending()
time.sleep(1)
w.mainloop() #my failed attempt to solve this problem
w = MainWindow()
w.mainloop()
Expected the scheduler to keep calling my check_email_request function every 1 minute. If I don't include the main loop in schedule loop, the window no longer functions. When I include the mainloop, the scheduler no longer functions.

Tkinter: Calling a multithreaded instance

I am a beginner at python, and it is my first language. I have been tasked with something that is quickly becoming too large for me to grasp that I need to finish. I am almost done. At this moment, I have created a dialog box that serves as a Main Menu, a dialog box that is a selectable option from the main menu that runs a test, and a multithreaded instance which runs the test, opens up a "please wait" box and up on finishing the test, another dialog box pops up which declares the test complete.
My issue: Within the "Run Test" dialog, I am trying to create a button that will call the multithreaded instance into action. From the code I have parsed together with the help of others, I can not see which class to instantiate within the "Run Test" dialog box.
I am beginning to believe my implementation of threading is incorrect. However there must be a way.
This is the module I am trying to call on.
from slice_setup import SLICE_SETUP
import Tkinter as tk
import threading
import Queue
class GuiPart:
def __init__(self, master, queue):
self.queue = queue
self.master = master
self.master.geometry("300x100+400+250")
self.master.title("RSAM BCT")
tk.Label(master, text="REDCOM SLICE", fg="red").pack()
tk.Label(master, text="BCT - Basic Configuration Test", fg= "red").pack()
tk.Label(master, text="Please wait...", fg= "black").pack()
tk.Label(master, text="Estimated time: 3 min 6 sec", fg= "black").pack()
def processIncoming(self):
while self.queue.qsize():
try:
text = self.queue.get(0)
Complete(self.master, text)
except Queue.Empty:
pass
class ThreadedClient:
def __init__(self, master):
self.master = master
self.queue = Queue.Queue()
self.gui = GuiPart(master, self.queue)
self.running = True
self.thread = threading.Thread(target=self.workerThread1)
self.thread.start()
self.periodicCall()
def periodicCall(self):
self.gui.processIncoming()
if not self.running:
return
self.master.after(100, self.periodicCall)
def workerThread1(self):
obj_rcs = SLICE_SETUP()
obj_rcs.SLICE()
self.queue.put("Configuration Complete!")
self.running = False
class Complete(tk.Toplevel):
def __init__(self, master=None, completetext=""):
tk.Toplevel.__init__(self, master)
self.geometry("400x300+400+250")
self.title("RSAM BCT")
tk.Label(self, text="REDCOME SLICE", fg="red").pack()
tk.Label(self, text="BCT - Basic Configuration Test", fg="red").pack()
tk.Label(self, text=completetext, fg="dark green").pack()
tk.Label(self, text="Trunk 1: Port 1: Phone 1: 760-450-4500", fg="black").pack()
tk.Label(self, text="Trunk 1: Port 2: Phone 2: 760-450-4501", fg="black").pack()
tk.Button(self, text=" Exit ", command=self.destroy).pack()
if __name__ == "__main__":
root = tk.Tk()
client = ThreadedClient(root)
root.mainloop()
and this is where I am trying to call from:
import sys
import Tkinter as Tk()
from bct_pleasewait import ????
import threading
import Queue
import time
sGui = Tk()
class slice_menu:
def runtest(self):
obj_wait = ????
obj_wait.????
def slicemenu(self):
sGui.geometry("400x300+400+250")
sGui.title("RSAM BCT")
Label(sGui, text= "REDCOM SLICE", fg="red").pack()
Label(sGui, text= "BCT - Basic Configuration Test", fg= "red").pack()
Label(sGui, text= "-Ensure you are logged off of HyperTerminal", fg= "black").pack()
Label(sGui, text= "-Turn on your REDCOM SLICE unit",
fg= "black").pack()
Label(sGui, text= "-Please connect your laptop to SLICE CONSOLE", fg= "black").pack()
Label(sGui, text= "-This configuration will take 3 minutes", fg= "black").pack()
Button(sGui, text = " Run ", command = self.runtest).pack()
Button(sGui, text = " Exit test ", command = sGui.destroy).pack()
sGui.mainloop()
This class still has minor errors in it but I just want to get this issue solved first.
Not a specific answer, but your question is very broad.
Some points to keep in mind:
Tk is not thread-safe. That is, you should only invoke Tk calls from the main thread. It is OK to let other threads do non-gui work.
In CPython, only one thread at a time can be executing Python bytecode, due to the Global Interpreter Lock ("GIL"). So your non-gui thread could make the GUI unresponsive.
If you are only running one test at a time, and if you can divide that test into small pieces, you could use a timeout (also called alarm handler). This handler does a little bit of work, saves its state, updates the progress dialog and then exits, waiting to be invoked again.
If the test runs a long time and you want the GUI to remain responsive, I would suggest using multiprocessing instead of threading. Start your test in a different process, and use things like Queues and Semaphores et cetera to communicate between the GUI and non-qui processes.

Categories

Resources