Using python websocket client with tkinter

Question:

I’m trying to make use a websocket client in python 2.7. The client works fine when running with IDLE, as in the received messages are shown. However trying to insert the websocket messages in a tkinter text widget is not working. Messages are still being displayed in IDLE, but the tkinter window is not being displayed at all.

The package I’m using is called websocket-client 0.32.0 and I dowloaded it from here. I followed the instructions on how to make a javascript like api and somewhat adapted the code.

Here is my code:

from Tkinter import *
from websocket import *

master = Tk()
master.wm_title("Websocket Test")
minwidth = master.winfo_screenwidth()/4*3
minheight = master.winfo_screenheight()/4*3
master.minsize(width=minwidth, height=minheight)
master.resizable(0,0)

text = Text(master)
text.pack(expand=True,fill=BOTH)

def on_message(ws, message):
   text.insert(END, message+"n")
   print "Received: "+message
   return

def on_error(ws, error):
   text.insert(END, error+"n")
   print error
   return

def on_close(ws):
   text.insert(END, "### closed ###n")
   print "### closed ###"
   return

def on_open(ws):
   ws.send("hi")
   ws.send("test")
   return

enableTrace(True)
ws = WebSocketApp("ws://echo.websocket.org/", on_message = on_message, on_error = on_error, on_close = on_close)
ws.on_open = on_open

ws.run_forever()

master.mainloop()

Here is what is shown in IDLE if that is also helpful:

--- request header ---
GET / HTTP/1.1

Upgrade: websocket

Connection: Upgrade

Host: echo.websocket.org

Origin: http://echo.websocket.org

Sec-WebSocket-Key: tXWAVVlaRoq2S4+p/z12gg==

Sec-WebSocket-Version: 13




-----------------------
--- response header ---
HTTP/1.1 101 Web Socket Protocol Handshake
Connection: Upgrade
Date: Fri, 21 Aug 2015 05:16:54 GMT
Sec-WebSocket-Accept: LH12LFLFaek6HgCnGIugF0sg9lA=
Server: Kaazing Gateway
Upgrade: websocket
-----------------------
send: 'x81x82{bx97xfcx13x0b'
send: 'x81x84xa5Jxecfxd1/x9fx12'
Received: hi
Received: test

I’ve been stuck on this for a while and I cannot find any solutions to this sort of problem. Any help is appreciated as I’m a newbie.

Asked By: Bob Marshall

||

Answers:

Well, I do not use websocket , but the issue seems to be that , when you do –

ws.run_forever()

The application goes into an infinite loop , so the control never reaches master.mainloop() , which is required for the tkinter to show up , and which is again another infinite loop, which is only exited when you close the gui.

What you really want is to run two infinite loop simultaneously, which would require you to run them in two different threads, currently both of them are defined on the same thread, so one would only run after the other has exited.

A quick fix would be to use master.after() with a certain delay and giving a function, and then in the function start a new thread for a function in which websocket connects to the server. so that both the infinite loops are in different threads.

But the best fix would be to use a button, lets call it 'Connect' . Then the callback for that button would be a function like on_connect() below , which starts the function to connect –

def connect_to_socket():
    enableTrace(True)
    ws = WebSocketApp("ws://echo.websocket.org/", on_message = on_message, on_error = on_error, on_close = on_close)
    ws.on_open = on_open

    ws.run_forever()

def on_connect():
    import threading
    t = threading.Thread(target=connect_to_socket)
    t.start()

The button would be something like –

button = Button(master, text="Connect", command=on_connect)

Then you can place the button as you wish.

Answered By: Anand S Kumar

Thanks to Anand’s response, I was able to figure out the problem. The working and updated code is posted below:

from Tkinter import *
from websocket import *
from threading import *

master = Tk()
master.wm_title("Team Black Client")
master.withdraw()
minwidth = master.winfo_screenwidth()/4*3
minheight = master.winfo_screenheight()/4*3
master.minsize(width=minwidth, height=minheight)
x = (master.winfo_screenwidth() - minwidth)/2
y = (master.winfo_screenheight() - minheight)/2
master.geometry("+"+str(x)+"+"+str(y))
master.deiconify()
master.resizable(0,0)

text = Text(master)
text.pack(expand=True,fill=BOTH)

def on_message(ws, message):
   text.insert(END, message+"n")
   print "Received: "+message
   return

def on_error(ws, error):
   text.insert(END, error+"n")
   print error
   return

def on_close(ws):
   text.insert(END, "### closed ###n")
   print "### closed ###"
   return

def on_open(ws):
   ws.send("hi")
   ws.send("test")
   return

def connection():
   enableTrace(True)
   ws = WebSocketApp("ws://echo.websocket.org/", on_message = on_message, on_error = on_error, on_close = on_close)
   ws.on_open = on_open

   ws.run_forever()
   return

t = Thread(target=connection)
t.start()

master.mainloop()
Answered By: Bob Marshall

Thank you for your post! I did search for so long for solution like this to make it work. Not much guide on this on Python, what i could find, and most of them was copy paste each others text/code samples as well. 🙁

Answered By: TrickyDeath