I'm using this forum for some time, but this is the first time that I ask a question, since I haven't been able to find a good way around my difficulties, and because I hope this question will be useful to other people too.
I am implementing a simple notification board, i.e. a window where messages coming from a socket connection are displayed. This board prints in red the last message received and in blue the old ones, up to ten. When a message sent by the client is 'Q', the connection terminates and the notification board is destroyed.
I am using Tkinter, threading and sockets, but the behaviour is not smooth (it takes a while to refresh the notification board). I can think of a few problems: the thread handling the connection is not closed; the update of the window is performed by destroying and recreating the toplevel. Unfortunately I can't understand if these issues are the source of the problem.
Here is the code for the client, a very simple one:
#!/usr/bin/env python
import socket
HOST = '' # Symbolic name meaning the local host
PORT = 24073 # Arbitrary non-privileged port
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST,PORT))
while True:
message = raw_input('Enter your command (Q=quit): ')
s.send(message)
reply = s.recv(1024)
if reply=='Q':
print 'Request to disconnect was received.'
break
else :
print reply
s.close()
And here is the server. The server has implemented a class that handles the notification board characteristics, a thread for the socket connection and finally the main part with the mainloop()
.
#!/usr/bin/env python
import socket
import threading
from Tkinter import *
from datetime import datetime
### Class definition
class NoticationsBoard() :
def __init__(self, title):
self.messages = []
self.toplevel = None
self.title = title
self.backgroundColor = 'black'
self.textColor = 'blue'
self.textColorFirst = 'red'
self.boardSize = '200x250+0+0'
self.listsize = 10
def createBoard(self):
self.toplevel = Toplevel()
self.toplevel.title(self.title)
self.toplevel.configure(background='black')
self.toplevel.geometry(self.boardSize)
def publish(self, message):
self.addToList(message)
self.displayList()
def addToList(self, msg):
if len(self.messages) == self.listsize:
self.messages.pop(0)
timestamp = datetime.utcnow().strftime('%H:%M:%S')
newMessage = (msg, timestamp)
self.messages.append(newMessage)
def displayList(self):
# Destroy and create the window (is it really necessary?)
if self.toplevel is not None :
self.toplevel.destroy()
self.createBoard()
# create labels for all the messages in the list
index = 1
for m, t in self.messages :
color = self.textColor
if index == len(self.messages) :
color = self.textColorFirst
label = Label(self.toplevel, text=m, height=0, width=100, fg=color, anchor=W)
label.grid(row=0,column=1)
label.configure(background=self.backgroundColor)
label.pack(side='bottom')
index = index +1
####### Run
def receiveMessages(newsboard) :
print '===== Inside receiveMessages ======'
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error code: ' + str(msg[0]) + 'Error message: ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(1)
print 'Socket now listening on port', PORT
# Accept the connection once
(conn, addr) = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
stored_data = ''
while True:
# RECEIVE DATA
data = conn.recv(1024)
# PROCESS DATA
if data == 'Q' :
print 'Client wants to disconnect.'
reply = 'Q'
conn.send(reply)
break
else :
print data
newsboard.publish(data)
reply = 'Message received:' + data
conn.send(reply)
print 'Close connection.'
conn.close()
board.destroy()
HOST = '' # Symbolic name meaning the local host
PORT = 24073 # Arbitrary non-privileged port
app = Tk()
app.title("GUI main")
board = NoticationsBoard('Notifications')
t = threading.Thread(target=receiveMessages, args = (board,))
t.start()
app.update() # Not sure what it does and if it is necessary
app.mainloop()
I am using Python 2.7.5.
Finally, but this is something minor, I was trying to display the timestamp of each message on the left of the message itself, in a different color. It seems to me that it is not possible to have text of different colours on the same label, so I had created other labels in the for
loop with the timestamps. I tried to display the timestamp and message labels one next to the others using .grid(column=0)
and .grid(column=1)
, but they were not one next to the other but one below the other, and I haven't figured out why.
As you understood, I am not a skilled programmer, and definitely a newbie with Python...
Thanks in advance to whom will give me some advice, and I hope this question will be useful to many people.