I can't figure out where I got this, but it was someone from this list.
Run it and telnet to port 8001.
Its a demo of asynchronous networking/GUI'ing. If it gets too
garbled, I can email it in a nicer format.
···
On Friday 09 March 2001 09:59 pm, you wrote:
In over my head now. (not that I wasn't before).
I'm *trying* to build an instant_messaging-type client. Now that most of
the GUI is built, the fun begins.
I'm trying to figure out the most *appropriate* way to 1. start the GUI, 2.
simultaneously start the network,
3. update the GUI based on incoming (and outgoing) network events.
#
# A demonstration of a wxPython GUI co-existing with threading and networking
#
import os
import string
import sys
import threading
import time
import socket
import asyncore
import asynchat
from wxPython.wx import *
SOCKET_PORT = 8001
BUFSIZE = 1024 # maximum size of a message read from the network
class MainFrame(wxFrame):
ID_EXIT = 102
def __init__(self, parent, ID, title):
wxFrame.__init__(self, parent, ID,
title,
wxDefaultPosition, # position
wxSize(512,512))
self.SetAutoLayout(true)
self.CreateStatusBar()
menuBar = wxMenuBar()
menu = wxMenu()
menu.AppendSeparator()
menu.Append(self.ID_EXIT, "E&xit", "Terminate the program")
menuBar.Append(menu, "&File");
self.SetMenuBar(menuBar)
EVT_MENU(self,self.ID_EXIT,self.TimeToQuit)
sizer = wxBoxSizer(wxVERTICAL)
self.SetSizer(sizer)
# a logging window
self.log = wxTextCtrl(self,-1,style = wxTE_MULTILINE|wxTE_READONLY)
wxLog_SetActiveTarget(wxLogTextCtrl(self.log))
sizer.Add(self.log,1,wxEXPAND|wxALL,1)
# trap characters
EVT_CHAR(self, self.OnChar)
# start the thread
self.network = NetworkThread(self)
self.network.start()
EVT_NETWORK(self,self.OnNetwork)
# cleanup
EVT_CLOSE(self, self.OnCloseWindow)
self.show_status("Try telnet'ing to this host on port %d." %
SOCKET_PORT)
def OnCloseWindow(self, event):
self.shutdown_network()
self.Destroy()
def OnChar(self, event):
key = event.KeyCode()
if key == ord('c'):
wxLog_FlushActive()
else:
event.Skip()
return
def TimeToQuit(self, event):
self.Close(true)
def OnNetwork(self, evt):
wxLogMessage("Received: \"%s\"." % evt.msg)
def shutdown_network(self):
wxLogMessage('Shutting down server.')
# wait for network thread to die
if self.network.is_running():
self.network.stop()
nd = 1
while self.network.is_running():
self.show_status("Shutting down network service" + nd*'.')
time.sleep(0.3)
nd = nd + 1
def show_status(self,t):
self.SetStatusText(t)
class NetworkServer (asyncore.dispatcher):
def __init__ (self,port,handler=None):
self.port = port
asyncore.dispatcher.__init__ (self)
self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(1) # max of one connection at a time
self.handler = handler
def handle_accept (self):
conn, addr = self.accept()
wxLogMessage ('Incoming connection from %s:%d' % (addr[0], addr[1]))
NetworkChannel (conn, addr,self.handler)
class NetworkChannel (asynchat.async_chat):
def __init__ (self, conn, addr,handler=None):
asynchat.async_chat.__init__ (self, conn)
self.set_terminator ('\r\n')
self.in_buffer = ''
self.handler = handler
def handle_connect (self):
self.send('\377\375\"')
def collect_incoming_data (self, data):
self.in_buffer = self.in_buffer + data
def found_terminator (self):
if self.handler:
self.handler(self.in_buffer)
else:
print 'warning: unhandled message:',self.in_buffer
self.in_buffer = ''
# Adapted from class event_loop in Sam Rushing's async package
class EventLoop:
socket_map = asyncore.socket_map
def __init__ (self):
self.events = {}
def go (self, timeout=5.0):
events = self.events
while self.socket_map:
now = int(time.time())
for k,v in events.items():
if now >= k:
v (self, now)
del events[k]
asyncore.poll (timeout)
def schedule (self, delta, callback):
now = int (time.time())
self.events[now + delta] = callback
def unschedule (self, callback, all=1):
"unschedule a callback"
for k,v in self.events:
if v is callback:
del self.events[k]
if not all:
break
#
# the network thread communicates back to the main GUI thread via
# this sythetic event
#
class NetworkEvent(wxPyEvent):
def __init__(self,msg=""):
wxPyEvent.__init__(self)
self.SetEventType(wxEVT_NETWORK)
self.msg = msg
wxEVT_NETWORK = 2000
def EVT_NETWORK(win, func):
win.Connect(-1, -1, wxEVT_NETWORK, func)
#
# This thread runs in the background receiving commands via
# a socket, then sends the command back to the GUI as a "NetworkEvent"
#
class NetworkThread(threading.Thread):
def __init__(self,win):
threading.Thread.__init__(self)
self.win = win
self.keep_going = true
self.running = false
self.server = NetworkServer(SOCKET_PORT,self.received_a_line)
self.event_loop = EventLoop()
def is_running(self):
return self.running
def stop(self):
self.keep_going = 0
def check_status(self,el,time):
if not self.keep_going:
asyncore.close_all()
else:
self.event_loop.schedule(1,self.check_status)
def received_a_line(self,m):
self.send_event(m)
def run(self):
self.running = true
self.event_loop.schedule(1,self.check_status)
# loop here checking every 0.5 seconds for shutdowns etc..
self.event_loop.go(0.5)
# server has shutdown
self.send_event("Closed down network")
time.sleep(1)
self.running = false
# send a synthetic event back to our GUI thread
def send_event(self,m):
evt = NetworkEvent(m)
wxPostEvent(self.win,evt)
del evt
class MyApp(wxApp):
def OnInit(self):
self.frame = frame = MainFrame(NULL, -1,
"wxPython+threading+asynchat")
self.SetTopWindow(frame)
frame.Show(true)
EVT_CHAR(self, self.OnChar)
return true
def OnChar(self, event):
key = event.KeyCode()
if key == 27:
self.shutdown()
else:
event.Skip()
return
def shutdown(self):
self.frame.Close(true)
if __name__=='__main__':
app = MyApp(0)
app.MainLoop()
_______________________________________________
wxPython-users mailing list
wxPython-users@lists.sourceforge.net
http://lists.sourceforge.net/lists/listinfo/wxpython-users