This code is to receive and display the text on the tk window.But what i want to achieve here is:
When the character is sent from master to slave. Receive the character on the slave, look up the character in the dict, display the value that corresponds to the key.
I tried but couldn't succeed, can any one help me with the correct code.
for example: when slave received a key called 'hw',It has to display "hello world",
when '0' received, should display "how are you?" on the tk text widget window.
thanks in advance.
import serial
import threading
import Queue
import Tkinter as tk
from Tkinter import *
import time
import sys
class SerialThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
s = serial.Serial('COM11',9600)
while True:
if s.inWaiting():
text = s.readline(s.inWaiting())
self.queue.put(text)
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("1360x750")
self.time = ''
self.clock = tk.Label(self, font=('times', 50, 'bold'), fg='black', bg='yellow')
self.clock.pack(side='bottom', anchor='se')
frameLabel = tk.Frame(self, padx=10, pady =50)
self.text = tk.Text(frameLabel, wrap='word', bg=self.cget('bg'), relief='flat')
frameLabel.pack()
self.text.pack()
self.queue = Queue.Queue()
thread = SerialThread(self.queue)
thread.start()
self.process_serial()
self.msgs = {
'hw':"hello world",
'wpp':"welcome to python programming",
'h':"hello",
0:"how are you?",
1:"bye....",
'egm': "english general message how are you",
'egm2':"If the world is flat be carefull not to fall off"
}
def process_serial(self):
self.time = time.strftime('%H:%M:%S')
self.clock.config(text=self.time)
firstitem = True
while self.queue.qsize():
try:
new = self.queue.get()
size = sys.getsizeof(new)
if size<40:
self.text.config(font='TimesNewRoman 100')
elif size>=40 and size<70:
self.text.config(font='TimesNewRoman 75')
else:
self.text.config(font='TimesNewRoman 50')
if firstitem:
self.text.delete(1.0, 'end')
firstitem = False
self.text.tag_configure("tag-center", justify='center')
#self.text.tag_add("center", 1.0, "end")
self.text.insert('end', my_dictionary.setdefault(signal, 'wrong signal'))
#self.text.insert('end', new, 'tag-center')
except Queue.Empty:
pass
self.after(1000, self.process_serial)
app = App()
app.mainloop()
Related
Sorry for the confusing title basically what I'm trying to figure out how to import a frame from one script into another. I'm not sure how I would call it since it has so many functions. Here are my two scripts:
File Name - wrapper:
import tkinter as tk
import workingcatch
from tkinter import *
root = tk.Tk()
outputframe = LabelFrame(master=root, width=800, height=700) #where i want to import the script
outputframe.pack(side=LEFT, padx=10,pady=10)
root.geometry('1280x720')
root.mainloop()
File Name - workingcatch:
from subprocess import Popen, PIPE, STDOUT
from threading import Thread
import tkinter as tk
import logging
import time
import sys
info = logging.getLogger(__name__).info
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(message)s")
platform = windows = 'mswin'
# define dummy subprocess to generate some output
cmd = [sys.executable or "python", "-u", "-c", """
import itertools, time
for i in itertools.count():
print(i)
time.sleep(0.5)
exit()
""", "exit"]
class OStream(Thread):
enable_print = True
def handel_line(self, line):
if platform == windows:
# Windows uses: "\r\n" instead of "\n" for new lines.
line = line.replace(b"\r\n", b"\n")
if self.enable_print:
info("got: %r", line)
if self.stream_print is not None:
self.stream_print(line)
def stop(self):
self.alive = False
def run(self):
while self.alive:
for s in self.ostrams:
line = s.stdout.readline()
if line:
self.handel_line(line)
time.sleep(0.2)
info("OStream Exit")
def pipe_proc(self, stream):
self.ostrams.append(stream)
def stream_callback(self, func):
self.stream_print = func
def __init__(self):
self.ostrams = []
self.alive = True
self.stream_print = None
Thread.__init__(self)
class Scrolable_Frame(tk.Frame):
def get(self):
return self.interior
def __init__(self, master):
tk.Frame.__init__(self, master)
self.scroll = tk.Scrollbar(self)
self.scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.canvas = tk.Canvas(
self, bd=0, highlightthickness=0,
yscrollcommand=self.scroll.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.TRUE)
self.scroll.config(command=self.canvas.yview)
self.canvas.xview_moveto(0)
self.canvas.yview_moveto(0)
self.interior = tk.Frame(self.canvas)
interior_id = self.canvas.create_window(
0, 0, window=self.interior, anchor=tk.NW
)
def _configure_interior(_):
size = (self.interior.winfo_reqwidth(), self.interior.winfo_reqheight())
self.canvas.config(scrollregion="0 0 %s %s" % size)
if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
self.canvas.config(width=self.interior.winfo_reqwidth())
self.interior.bind('<Configure>', _configure_interior)
def _configure_canvas(_):
if self.interior.winfo_reqwidth() != self.canvas.winfo_width():
self.canvas.itemconfigure(interior_id, width=self.canvas.winfo_width())
self.canvas.bind('<Configure>', _configure_canvas)
def _on_mousewheel(event):
self.canvas.yview_scroll(int(-1 * (event.delta / 120)), 'units')
self.canvas.bind_all("<MouseWheel>", _on_mousewheel)
class ShowProcessOutputDemo(tk.Tk):
def __init__(self):
"""Start subprocess, make GUI widgets."""
tk.Tk.__init__(self)
self.geometry('300x200+500+300')
self.protocol("WM_DELETE_WINDOW", self.stop)
self.proc = Popen(cmd, stdout=PIPE, stderr=STDOUT)
self.ostream = OStream()
self.ostream.pipe_proc(self.proc)
self.ostream.stream_callback(self.add_label)
self.ostream.start()
self.exit_button = tk.Button(
self, text="Stop subprocess", command=self.stop
)
self.exit_button.pack(pady=20)
self.scolable_frame = Scrolable_Frame(self)
self.scolable_frame.pack(
expand=True, fill=tk.BOTH, pady=20, padx=20
)
def add_label(self, line):
line_text = 'OStream line content: {0}'.format(line[:-1].decode())
tk.Label(
self.scolable_frame.get(), text=line_text
).pack(anchor=tk.CENTER, expand=True, fill=tk.X)
def stop(self):
"""Stop subprocess and quit GUI."""
self.ostream.stop()
self.proc.kill()
self.proc.stdout.close()
self.proc.wait(timeout=2)
info("GUI Exit")
self.quit()
if __name__ == '__main__':
app = ShowProcessOutputDemo()
app.mainloop()
So what I'm trying to do is get the output from "workingcatch" into 'wrapper's frame.
Thanks for reading
I have a simple graphics program that shows some instructions and touch buttons to a touch screen in a remote raspberry.
Instead of executing directly, I run it through a SSH connection, so I have in my desktop al application log.
I would like to have some short of interaction from the console I run the script, like execute some functions or change values of some variables.
Is that even possible?
I do not want to create a console inside the TKinter window, as alessandro asked:
How to embed a terminal in a Tkinter application?
not sure if I should use a short of subprocess, as user1941008, but htis seemes too complicate
Write to terminal in Tkinter GUI
and I do prefer not to create a client/server setup or a middle buffer for this thing, too complex, and i will have to rewrite things to send the logs to new program.
I add a little little version of my code:
#!/usr/bin/env python3
import tkinter as tk
class _tkapp(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.redButton = tk.Button(self, text='Make me red', command=self.paintMeRed)
self.redButton.pack(side='top')
self.blueButton = tk.Button(self, text='Make me blue', command=self.paintMeBlue)
self.blueButton.pack(side='top')
self.quit = tk.Button(self, text='QUIT', fg='red', command=self.master.destroy)
self.quit.pack(side='bottom')
def paintMeRed(self):
tk_root.configure(background='red')
print('user click on RED')
def paintMeBlue(self):
tk_root.configure(background='blue')
print('user click on BLUE')
tk_root = tk.Tk()
tk_root.geometry("200x120")
tk_app = _tkapp(master=tk_root)
tk_app.mainloop()
this allow me to see on console what user cliked,
my objetive, change the color also from console
Here is the answer for your question. My other (deleted) answer didn't fit to your question.
Unfortunately you can't do it without sockets but I add some easy to adapt methods (init_remote_execution, listener, do_remite_call and cleanup) to your example that you can copy and paste in your actually application. You only need to adapt the do_remote_call method:
#!/usr/bin/env python3
import socket
import tkinter as tk
from queue import Queue
from threading import Thread
from uuid import uuid1
UDP_HOST = ""
UDP_PORT = 5005
RECV_BUFFER = 1020
class _tkapp(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
self.init_remote_execution()
self.master.protocol("WM_DELETE_WINDOW", self.cleanup) # call cleanup on exit
def init_remote_execution(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.bind((UDP_HOST, UDP_PORT))
self.endmsg = str(uuid1()) # Random string to stop threads
self.queue = Queue()
self.treads_running = True
self.listener_thread = Thread(target=self.listener)
self.worker_thread = Thread(target=self.do_remote_call)
self.listener_thread.start()
self.worker_thread.start()
def listener(self):
print("listen")
while self.treads_running:
data, addr = self.sock.recvfrom(RECV_BUFFER)
data = data.decode().strip()
print("from {addr}: {data}".format(addr=addr, data=data))
if data == self.endmsg:
self.treads_running = False
self.queue.put(data)
self.sock.close()
def do_remote_call(self):
while self.treads_running:
data = self.queue.get()
if data == self.endmsg:
print("Bye")
elif data == "click RED":
self.paintMeRed()
elif data == "click BLUE":
self.paintMeBlue()
else:
print(">>> unknown command")
def cleanup(self):
print("cleanup")
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto(self.endmsg.encode(), ("127.0.0.1", UDP_PORT))
self.listener_thread.join()
self.worker_thread.join()
self.master.destroy()
def create_widgets(self):
self.redButton = tk.Button(self, text="Make me red", command=self.paintMeRed)
self.redButton.pack(side="top")
self.blueButton = tk.Button(self, text="Make me blue", command=self.paintMeBlue)
self.blueButton.pack(side="top")
self.quit = tk.Button(
self, text="QUIT", fg="red", command=self.cleanup
) # call cleanup!!!
self.quit.pack(side="bottom")
def paintMeRed(self):
tk_root.configure(background="red")
print("user click on RED")
def paintMeBlue(self):
tk_root.configure(background="blue")
print("user click on BLUE")
if __name__ == "__main__":
tk_root = tk.Tk()
tk_root.geometry("200x120")
tk_app = _tkapp(master=tk_root)
tk_app.mainloop()
It is important, that you call the cleanup method on the quit button (otherwise the threads will not stop and the application will hang)!
Now you can "click" the "make me blue" button by sending an udp message (click BLUE) to Port 5005 on your raspberry.
With the tool netcat on the raspberry (you may need to install it with apt) you can send the commad to click blue like this:
echo "click BLUE" | nc -uw0 127.0.0.1 5005
With python:
#!/usr/bin/env python3
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto('click BLUE'.encode(), ('127.0.0.1', 5005)
sock.close()
From your desktop you have to switch the '127.0.0.1' with the ip address of your raspberry.
Here an even simpler version using the cmd module from python. This module allows you to write an repl (read evaluete print loop) for any thing.
#!/usr/bin/env python3
import cmd
import os
import signal
import tkinter as tk
from threading import Thread
class _tkapp(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.pack()
self.create_widgets()
def create_widgets(self):
self.redButton = tk.Button(self, text="Make me red", command=self.paintMeRed)
self.redButton.pack(side="top")
self.blueButton = tk.Button(self, text="Make me blue", command=self.paintMeBlue)
self.blueButton.pack(side="top")
self.quit = tk.Button(self, text="QUIT", fg="red", command=self.master.destroy)
self.quit.pack(side="bottom")
def paintMeRed(self):
tk_root.configure(background="red")
print("user click on RED")
def paintMeBlue(self):
tk_root.configure(background="blue")
print("user click on BLUE")
class Command(cmd.Cmd):
intro = "Welcome to the repl of the Tk app. Type help or ? to list commands.\n"
prompt = ""
def __init__(self, tkapp):
super().__init__()
self.tkapp = tkapp
# New commands must start with do_ and have one argument.
# The docstring is the help text.
# They must not return anything!
# only the do_quit returns True to indicate that the command loop must stop
def do_paint(self, arg):
"""Paint the background in the color red or blue: PAINT RED"""
clean_arg = arg.strip().lower()
if clean_arg == "red":
self.tkapp.paintMeRed()
elif clean_arg == "blue":
self.tkapp.paintMeBlue()
else:
print("Can't paint the color %s." % clean_arg)
def do_quit(self, arg):
"""Stop the application: QUIT"""
self.tkapp.master.destroy()
return True
if __name__ == "__main__":
tk_root = tk.Tk()
tk_root.geometry("200x120")
tk_app = _tkapp(master=tk_root)
command = Command(tk_app)
command_thread = Thread(target=command.cmdloop)
command_thread.start()
tk_app.mainloop()
os.kill(os.getpid(), signal.SIGTERM)
If you run the program via ssh, you can directly type in command help paint and quit. All outputs from the tk app will be printed here as well.
Just type help or help paint to see how it goes.
In the tkinter GUI I created a run Button. I liked to click the button then it should start counting. But When I call the method into the ttk.Button as command. it does not work. In this code two class was created. run method was created in the first class and it will be call into the second class. Could you please kindly check the code. Thanks in advance.
from tkinter import *
import threading
import queue
from time import sleep
import random
from tkinter import ttk
class Thread_0(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
count = 0
while True:
count +=1
hmi.thread_0_update(count)
sleep(random.random()/100)
class HMI:
def __init__(self):
self.master=Tk()
self.master.geometry('200x200+1+1')
self.f=ttk.Frame(self.master,height = 100, width = 100, relief= 'ridge')
self.f.grid(row=1,column=1, padx=20, pady=20)
self.l0=ttk.Label(self.f)
self.l0.grid(row=1,column=1)
self.button=ttk.Button(self.master, text = 'run')
self.button.grid(row=2,column=2)
self.q0=queue.Queue()
self.master.bind("<<Thread_0_Label_Update>>",self.thread_0_update_e)
def start(self):
self.master.mainloop()
self.master.destroy()
#################################
def thread_0_update(self,val):
self.q0.put(val)
self.master.event_generate('<<Thread_0_Label_Update>>',when='tail')
def thread_0_update_e(self,e):
while self.q0.qsize():
try:
val=self.q0.get()
self.l0.config(text=str(val), font = ('Times New Roman', 15))
except queue.Empty:
pass
##########################
if __name__=='__main__':
hmi=HMI()
t0=Thread_0()
t0.start()
hmi.start()
You can use
Button( ..., command=t0.start )
See: start is without (). But you have to create t0 before hmi
if __name__ == '__main__':
t0 = Thread_0()
hmi = HMI()
hmi.start()
Full code which works for me
from tkinter import *
import threading
import queue
from time import sleep
import random
from tkinter import ttk
class Thread_0(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
count = 0
while True:
count +=1
hmi.thread_0_update(count)
sleep(random.random()/100)
class HMI:
def __init__(self):
self.master=Tk()
self.master.geometry('200x200+1+1')
self.f = ttk.Frame(self.master, height=100, width=100, relief='ridge')
self.f.grid(row=1, column=1, padx=20, pady=20)
self.l0 = ttk.Label(self.f)
self.l0.grid(row=1, column=1)
self.button = ttk.Button(self.master, text='run', command=t0.start)
self.button.grid(row=2, column=2)
self.q0 = queue.Queue()
self.master.bind("<<Thread_0_Label_Update>>", self.thread_0_update_e)
def start(self):
self.master.mainloop()
self.master.destroy()
#################################
def thread_0_update(self,val):
self.q0.put(val)
self.master.event_generate('<<Thread_0_Label_Update>>', when='tail')
def thread_0_update_e(self,e):
while self.q0.qsize():
try:
val = self.q0.get()
self.l0.config(text=str(val), font=('Times New Roman', 15))
except queue.Empty:
pass
##########################
if __name__ == '__main__':
t0 = Thread_0()
hmi = HMI()
hmi.start()
Hi Python and Tkinter Gurus,
I am trying to build a simple GUI which has two buttons. When the Button is clicked, a thread is started to do some work. This work normally takes 10s/15s. And the GUI also works fine.
But I want to implement a pop-up to notify which thread has been completed. I have checked t.isAlive() function and could not implement it because I don't know how to trigger an event based on isAlive in the main loop.
Here is my sample code
from threading import Thread
from time import sleep
import Tkinter
import ttk
class SmallGui:
def __init__(self, master):
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
def init_thread(self, work):
if work == 1:
t = Thread(target=self.work_1)
t.start()
else:
t = Thread(target=self.work_2)
t.start()
#staticmethod
def work_1():
print 'Work 1 started'
# Do some Task and return a list
sleep(10)
#staticmethod
def work_2():
print 'Work 2 Started'
# Do some Task and return a list
sleep(15)
if __name__ == '__main__':
root = Tkinter.Tk()
run_gui = SmallGui(root)
root.mainloop()
You can use tkinter's messagebox. Tkinter has a built in method that can be used for all kinds of pop-up messages or questions. Here we will use messagebox.showinfo.
I am working on Python 3.X so I added a import method that will work for both 3.X and 2.X versions of python.
from threading import Thread
from time import sleep
try:
import Tkinter as tk
import tkMessageBox as mb
import ttk
except ImportError:
import tkinter as tk
from tkinter import messagebox as mb
import tkinter.ttk as ttk
class SmallGui:
def __init__(self, master):
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
def init_thread(self, work):
if work == 1:
t = Thread(target=self.work_1)
t.start()
else:
t = Thread(target=self.work_2)
t.start()
#staticmethod
def work_1():
print ('Work 1 started')
# Do some Task and return a list
sleep(1)
mb.showinfo("test", "Work 1 complete")
#staticmethod
def work_2():
print ('Work 2 Started')
# Do some Task and return a list
sleep(1)
mb.showinfo("test", "Work 2 complete")
if __name__ == '__main__':
root = tk.Tk()
run_gui = SmallGui(root)
root.mainloop()
UPDATE:
For whatever reason my above solution works in python 3 but no in 2.7.14.
The below example however does work in 2.7.14 and should work for you.
What I have done here is create 2 class attributes to monitor each thread.
I have created a method that will check ever 1 second if a thread is active and if the thread becomes inactive a messagebox will popup.
from threading import Thread
from time import sleep
import Tkinter as tk
import tkMessageBox as mb
import ttk
class SmallGui(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.master = master
self.master.title('test gui')
self.button_1 = ttk.Button(self.master,
text='Start 1',
command=lambda: self.init_thread(1))
self.button_2 = ttk.Button(self.master,
text='Start 2',
command=lambda: self.init_thread(2))
self.button_1.pack()
self.button_2.pack()
self.work1_status = None
self.work2_status = None
def init_thread(self, work):
if work == 1:
self.work1_status = Thread(target=self.work_1)
self.work1_status.start()
self.check_thread(self.work1_status, work)
else:
self.work2_status = Thread(target=self.work_2)
self.work2_status.start()
self.check_thread(self.work2_status, work)
def check_thread(self, pass_thread, thread_name):
if pass_thread.isAlive() == False:
pass_thread = None
mb.showinfo("test", "Work {} complete".format(thread_name))
else:
self.after(1000, lambda: self.check_thread(pass_thread, thread_name))
#staticmethod
def work_1():
print ('Work 1 started')
# Do some Task and return a list
sleep(5)
#staticmethod
def work_2():
print ('Work 2 Started')
# Do some Task and return a list
sleep(5)
if __name__ == '__main__':
root = tk.Tk()
run_gui = SmallGui(root)
root.mainloop()
I want the received data to be centered on tk window instead of printing from top.So I want to write code using Label widget instad of TEXT widget.(TEXT widget print from top and LABEL widget centers the data on tk window) Label widget has 'ANCHOR' options controls where the text is positioned if the widget has more space than the text needs. The default is anchor=CENTER, which centers the text in the available space.
But in my code i always delete and insert data all the time,according to my knowledge delete and insert options are only in Text widget, is it possible in Label widget.
please help me out.
I tried to change my code bt using LABEL widget, but couls not succeed. can some one please help me to change my code to use label widget.
thanks.
import serial
import threading
import Queue
import Tkinter as tk
from Tkinter import *
class SerialThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
s = serial.Serial('COM11',9600)
while True:
if s.inWaiting():
text = s.readline(s.inWaiting())
self.queue.put(text)
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("1360x750")
frameLabel = tk.Frame(self, padx=40, pady =40)
self.text = tk.Text(frameLabel, wrap='word', font='TimesNewRoman 40',
bg=self.cget('bg'), relief='flat')
frameLabel.pack()
self.text.pack()
self.queue = Queue.Queue()
thread = SerialThread(self.queue)
thread.start()
self.process_serial()
def process_serial(self):
firstitem = True
while self.queue.qsize():
try:
new = self.queue.get()
if firstitem:
self.text.delete(1.0, 'end')
firstitem = False
self.text.insert('end', new)
except Queue.Empty:
pass
self.after(100, self.process_serial)
app = App()
app.mainloop()
The Tkinter Label widget has a text option to indicate the text that is being displayed. If you want to change all the content that the widget displays, then replace
self.text = tk.Text(frameLabel, ...)
# ...
new = self.queue.get()
self.text.delete(1.0, 'end')
self.text.insert('end', new)
With this:
self.label = tk.Label(frameLabel, ...)
# ...
new = self.queue.get()
self.label.config(text=new)