handling "Exception in thread.." tkinter, convert in "messagebox.showerror" - multithreading

when I get error in target of thread (t = Thread (target = self._configure_clicked) it appears on terminal "Execption in thread Thread-1" (I have more threads in code).
I want a "messagebox.showerror" to appear if there is an error, and if there is no error "messagebox.showinfo". how can I do this?
I am attaching an extract of the GUI code and the screen of the terminal
from tkinter import * # importo tutto da tkinter
from tkinter import messagebox, ttk
from threading import Thread
import multi_sensor_acc_gyro1 as multi ##other script.py
...
...
def configure_clicked(self):
t=Thread(target=self._configure_clicked, daemon=True)
t.start()
...
self.pb.start() #progress bar start
while t.is_alive():
self.pb.update() #progress bar update
...
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\\n click OK to continue")
messagebox.showerror("Error","sensor disconnection")
...
...
def _configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
...
Error message
I tried to use try / except, but I am doing something wrong. I am not detecting any errors:
from tkinter import * # importo tutto da tkinter
from tkinter import messagebox, ttk
from threading import Thread
from PIL import Image
import multi_sensor_acc_gyro1 as multi
...
...
def configure_clicked(self):
try:
t=Thread(target=self._configure_clicked, daemon=True)
t.start()
...
self.pb.start()
while t.is_alive():
self.pb.update()
...
messagebox.showinfo("CONFIGURE clicked","the sensors have been configured\n\\n click OK to continue")
...
...
except:
messagebox.showerror("Error","sensor disconnection")
def _configure_clicked(self):
mac_address=["F7:64:55:AD:0A:19","F2:A1:3A:E2:F2:ED","F9:8E:32:DD:1A:EB"]
output_1=multi.configure(mac_address)
self.states=output_1[0]
self.loggers_acc=output_1[1]
self.loggers_gyro=output_1[2]
...
...

Related

Rotary encoder value looking sticky after using tkinter function " root.after"

I am quite new to python and tkinter ,I am working on a project where i give demand to slave device through rotary encoder value and reading feedback value from slave devices through communication.
I face issue when i use root.after () function .
Any suggestion regarding proper use of root.after () function so that my interrupt routine not affected welcome heartly.
Thank you.
Here is my code.
import pigpio
import tkinter as tk
from PIL import ImageTk,Image
import time
from RPi import GPIO
import serial
i="*00T%"
j="*01T%"
s=serial.Serial(port='/dev/ttyS0',
baudrate=9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
class decoder: # class for decoding rotary encoder
def __init__(self, pi, gpioA, gpioB, callback):
----------
---------------
----------------
if __name__ == "__main__":
import RPi.GPIO as GPIO
import time
import pigpio
import tkinter as tk
import board
import busio
rpm=0
tor=0
pow=0
pi = pigpio.pi()
st=1
pos=0
def callback(way): # interrupt event sense on pin no 17,18
global pos
global st
if st ==1:
pos += way
if pos >= 9999:
pos=9999
if pos <= 0:
pos=0
var.set(pos)
print("pos={}".format(pos))
def rpm_update():
global rpm
s.write(str.encode(i))
print(i)
time.sleep(0.2)
if s.inWaiting():
rpm=s.readline(s.inWaiting())
rpm=rpm.decode('utf-8',errors='ignore')
rpm=rpm[5:-1]
print(rpm)
var2.set(rpm)
def tor_update():
global tor
s.write(str.encode(j))
print(j)
time.sleep(0.2)
if s.inWaiting():
tor=s.readline(s.inWaiting())
tor=tor.decode('utf-8',errors='ignore')
tor=tor[4:-1]
print(tor)
var3.set(tor)
def pow_update():
global rpm,tor,pow
try:
rpm=float(rpm)
tor=float(tor)
except ValueError:
pass
pow=int(rpm*tor/5252)
var4.set(pow)
def update():
rpm_update()
time.sleep(0.5)
tor_update()
time.sleep(0.5)
pow_update()
root.after(1000,update)
path="/home/pi/logo.png"
root=tk.Tk()
img=ImageTk.PhotoImage(Image.open(path))
panel=tk.Label(root,image=img)
panel.pack()
panel.place(x=195,y=10,height=50,width=80)
root.title("Dynalec")
root.geometry("500x600")
{
body of tkinter screen
}
decoder=decoder(pi, 17, 18, callback)
root.after(1000,update)
root.mainloop()
everything is working fine before root.after() function " root.after(1000,update)
but i need it because i have to read slave values in every sec and update in gui screen.
Adding as a answer because long for comments, will remove soon.
Try this out:
def update():
root.after(500,rpm_update)
root.after(500,tor_update)
root.after(500,pow_update)
root.after(1000,update)
Do let me know.

Type Error: unsupported operand type(s) for /: 'Nonetype' and 'int'

from pytube import YouTube
from tkinter import filedialog
from tkinter import ttk
from tkinter import*
import threading
import re
class Application:
def __init__(self,root):
self.root=root
self.root.grid_rowconfigure(0,weight=2)
self.root.grid_columnconfigure(0,weight=1)
self.root.config(bg="#ffdddd")
top_label=Label(self.root,text="YouTube download manager",fg="blue",font=("ALGERIAN",70))
top_label.grid(pady=(0,10))
link_label=Label(self.root,text="Please paste your YouTube video link",bg="black",fg="red",font=("Agency FB",30))
link_label.grid(pady=(0,20))
self.YoutubeEntryVar=StringVar()
self.YoutubeEntry=Entry(self.root,width=70,textvariable=self.YoutubeEntryVar,font=("Lucida Console",25),fg="blue")
self.YoutubeEntry.grid(pady=(0,20),ipady=5)
self.YoutubeEntryError=Label(self.root,text="",font=("Colonna MT",20),fg="green")
self.YoutubeEntryError.grid(pady=(0,8))
self.YoutubeFileSave=Label(self.root,text="Choose Directory",font=("Agency FB",20),fg="black")
self.YoutubeFileSave.grid(pady=(0,8))
self.YoutubeButton=Button(self.root,text="Directory",font=("Colonna MT",20),command=self.FileDirectory)
self.YoutubeButton.grid(pady=(10,3),ipady=5)
self.FileLocation=Label(self.root,text="",font=("Harlow Solid Italic",20))
self.FileLocation.grid()
self.DownloadSelect=Label(self.root,text="Choose the format to download",font=("Century Gothic",20))
self.DownloadSelect.grid()
self.DownloadChoice=[("Audio MP3",1),("Video MP4",2)]
self.Choice=StringVar()
self.Choice.set(1)
for text,mode in self.DownloadChoice:
self.YoutubeChoice=Radiobutton(self.root,text=text,font=("Candara",10),variable=self.Choice,value=mode)
self.YoutubeChoice.grid()
self.DownloadButton=Button(self.root,text="Download",font=("Lucida Console",10),command=self.checkLink)
self.DownloadButton.grid(pady=(5,5))
def checkLink(self):
self.youtubeMatch=re.match("https://www.youtube.com/",self.YoutubeEntryVar.get())
if(not self.youtubeMatch):
self.YoutubeEntryError.config(text="Please choose a valid YouTube link !!")
elif(not self.FolderName):
self.FileLocation.config(text="Please choose a directory !!",fg="red")
elif(self.youtubeMatch and self.FolderName):
self.downloadFile()
def downloadFile(self):
self.newWindow=Toplevel(self.root)
self.root.withdraw()
self.newWindow.state("zoomed")
self.newWindow.grid_rowconfigure(0,weight=2)
self.newWindow.grid_columnconfigure(0,weight=1)
self.app=Second(self.newWindow,self.YoutubeEntryVar.get(),self.FolderName,self.Choice.get())
def FileDirectory(self):
self.FolderName=filedialog.askdirectory()
if(len(self.FolderName)>0):
self.FileLocation.config(text=self.FolderName,fg="green")
return True
else:
self.FileLocation.config(text="Please choose a directory !!",fg="red")
class Second:
def __init__(self,downloadWindow,youtubeLink,foldername,FileChoice):
self.downloadWindow=downloadWindow
self.youtubeLink=youtubeLink
self.foldername=foldername
self.FileChoice=FileChoice
self.yt=YouTube(self.youtubeLink)
if(FileChoice=='1'):
self.videoType=self.yt.streams.filter(only_audio=True).first()
self.MaxfileSize=self.videoType.filesize
if(FileChoice=='2'):
self.videoType=self.yt.streams.first()
self.MaxfileSize=self.videoType.filesize
self.Loading=Label(self.downloadWindow,text="Download in Progress.........",font=("Agency FB",40))
self.Loading.grid()
self.percent=Label(self.downloadWindow,text="0",font=("Agency FB",20))
self.percent.grid()
self.progressBar=ttk.Progressbar(self.downloadWindow,length=500,orient='horizontal',mode='indeterminate')
self.progressBar.grid(pady=(50,0))
self.progressBar.start()
threading.Thread(target=self.yt.register_on_progress_callback(self.show_Pregress)).start()
threading.Thread(target=self.downloadfile).start()
def downloadfile(self):
if(self.FileChoice=='1'):
self.yt.streams.filter(only_audio=True).first().download(self.foldername)
if(self.FileChoice=='2'):
self.yt.streams.filter().first().download(self.foldername)
def show_Pregress(self,streams=None,Chunks=None,filehandle=None,bytes_remaining=None):
percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))
if(percentCount<100):
self.percent.config(text=str(percentCount))
else:
self.progressBar.stop()
self.Loading.forget()
self.progressBar.forget()
self.downloadfinished=Label(self.downloadWindow,text="Download Finished",font=("ALGERIAN",20))
self.downloadfinished.grid(pady(150,0))
self.downloadfile=Label(self.downloadWindow,text=self.yt.title,font=("ALGERIAN",20))
self.downloadfile.grid(pady(50,0))
if __name__=="__main__":
window=Tk()
window.title("YouTube Download Manager")
window.state("zoomed")
app=Application(window)
mainloop()
Most probably your function:
def show_Pregress(self,streams=None,Chunks=None,filehandle=None,bytes_remaining=None):
percentCount = float("%0.2f"% (100 - (100*(bytes_remaining/self.MaxfileSize))))
Is called without passing a value for bytes_remaining which ends up in doing a division of None by self.MaxfileSize
See here for how to register a progress_bar callback with pytube:
How to add progress bar?

why a thread does not end

I'm trying to make an app to interact with an usb rfid reader on a Raspberry pi.
it looks like the solution is using the trheading module (otherwise the data entry leads to a disfunction)
After some essays I made an app that works... the first time. After that, a message error says "threads can only be started once"... so the interpretation is that the thread does not end naturally...why??
import time
import sys
import os
from tkinter import *
from tkinter.ttk import *
import threading
def activa_fil(self):
print ('activant fil')
fil.start()
def prova2():
print('hola')
print(Control.get())
print(NumCorr.get())
print(time.strftime("%H:%M:%S"))
DisplayCorr.config(text=NumCorr.get())
Llistacorr.insert(0, (Control.get(),NumCorr.get(), time.strftime("%H:%M:%S")))
marc.contador +=1
Contador.config (text=marc.contador)
print(marc.contador)
file = open("prova.txt", "a")
file.write(Control.get())
file.write(NumCorr.get())
file.write (time.strftime("%H:%M:%S"))
file.write('\n')
file.close()
NumCorr.after(500, NumCorr.delete(0,END))
def tick():
time_string = time.strftime("%H:%M:%S")
Hora.config(text=time_string)
Hora.after(200, tick)
def canvia_focus(self):
NumCorr.focus()
fil=threading.Timer(0.5, prova2)
marc = Tk()
marc.geometry('480x320')
marc.bind_all(''<'Key-Return'>'', activa_fil)
marc.contador =0
Control = Combobox(marc)
Control['values']=('sortida','can cuias','can campanya','papiol','sortida papiol', 'can olivero', 'ullastrell', 'coll olesa','pla fideuer','aeri', 'arribada')
Control.config(font="helvetica 30", )
Control.grid(column='0', row='0', columnspan='2')
Llistacorr = Listbox(marc)
Llistacorr.config(font='arial')
Llistacorr.grid_propagate(0)
Llistacorr.grid(column='0', row='1', rowspan='3')
DisplayCorr=Label(marc, font='Arial 10')
DisplayCorr.grid(column='1', row='1')
NumCorr = Entry(marc)
NumCorr.config(font='helvetica 6')
Control.bind('<<ComboboxSelected>>', canvia_focus)
NumCorr.grid(column='0', row='4', columnspan='2')
Contador=Label(marc, font='arial 30')
Contador.grid(column='1', row='2')
Hora=Label(marc, font='arial 30')
Hora.grid(column='1', row='3')
tick()
marc.mainloop()

How would I constantly update a variable within a script/program?

I am attempting to make a thermostat of sorts. To do this, I am using a Pi3 with a DHT22 Temperature sensor, and Python3.
What I need is for the temperature to be polled and the corresponding variable to update on its own.
Attempting to do so with any sort of While True: statements results in the gui I'm testing with, not opening.
I'm lost (And yes, this code is hacked together from others. LOL)
#! python3
import time
import RPi.GPIO as GPIO
import string
import tkinter
import tkinter.ttk
import Adafruit_DHT
from tkinter import messagebox
from tkinter import *
root = Tk()
root.title('PiTEST')
root.configure(background='black')
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
sensor = Adafruit_DHT.DHT22
pin = 4
def PRINTTEST():
print(temperature, humidity)
TESTTEXT = Label(root,text="TESTING",fg="white",bg="black",font='Consolas 20 bold')
TESTTEXT.grid(row=1,column=1,sticky="W,S,E")
B1 = tkinter.Button(root,bd=5,text="TEST",bg="gray",fg="white",command=PRINTTEST,height=4,width=20)
B1.grid(row=2,column=1,sticky="N,S,E,W",padx=8,pady=8)
while True:
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
temperature = temperature * 9/5.0 + 32
root.mainloop()
GPIO.cleanup()
Here is a code example without your GPIO things:
#! python3
import time
import string
import tkinter
import random
from tkinter import messagebox
from tkinter import *
root = Tk()
root.title('PiTEST')
root.configure(background='black')
def PRINTTEST():
temperature = random.randint(0,100)
humidity = random.randint(0,100)
print(temperature, humidity)
root.after(1000, PRINTTEST)
TESTTEXT = Label(root,text="TESTING",fg="white",bg="black",font='Consolas 20 bold')
TESTTEXT.grid(row=1,column=1,sticky="W,S,E")
B1 = tkinter.Button(root,bd=5,text="TEST",bg="gray",fg="white",command=PRINTTEST,height=4,width=20)
B1.grid(row=2,column=1,sticky="N,S,E,W",padx=8,pady=8)
root.mainloop()
This will print 2 random integers every second in your terminal.

tkinter window not closing properly

My tkinter app windows are not closing properly. I am using python 3.6.6 with tkinter 8.6
My code does basically this:
Open a process, where:
A test function is called via a thread that closes Gui window after 3s
Gui window is created
Wait for thread to complete (join) and guess window was closed
I tried to use:
quit -> window only closes when i hover my mouse over it
destroy -> destroy does not return
I stripped it down to the following code, please copy & execute and/or tell me whats wrong...
from time import sleep, time
import threading
from multiprocessing import Process, set_start_method
from tkinter import *
CtrlApplObj = None
def Start():
global CtrlApplObj
CtrlApplObj = None
CtrlApplObj = ControlApplication()
CtrlApplObj.run()
def End():
print("Quit now...")
#CtrlApplObj.root.destroy()
CtrlApplObj.root.quit()
class ControlApplication():
def __init__(self):
pass
def run(self):
self.root=Tk()
print("Mainloop...")
self.root.mainloop()
def test():
sleep(3)
End()
def execute():
T1 = threading.Thread(target=test)
T1.start()
Start()
T1.join()
if __name__ == "__main__":
set_start_method("spawn")
for i in range(2):
TestProcess = Process(target=execute)
TestProcess.start()
TestProcess.join()
My final solution was not using any tkinter operations in test thread. Then destroy worked.
I had another problem with my test process not closing. This was because a queue was not empty. That porevented process to close.

Resources