Make a wxPython application also acting as a XML-RPC server, listening to a dedicated port. For example a GUI logging application, where logging messages come from other applications via xml-rpc calls.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | # -*- coding: iso-8859-1 -*-
import wx
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor
from twisted.web import xmlrpc, server
#---------------------------------------------------------------------------
class MyFrame(wx.Frame):
def __init__(
self, parent, ID, title, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
):
wx.Frame.__init__(self, parent, ID, title, pos, size, style)
panel = wx.Panel(self, -1)
button = wx.Button(panel, 1003, "Close Me")
button.SetPosition((15, 15))
self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
def OnCloseMe(self, event):
self.Close(True)
reactor.stop()
def OnCloseWindow(self, event):
self.Destroy()
reactor.stop()
#---------------------------------------------------------------------------
class MyXMLRPCApp(wx.App, xmlrpc.XMLRPC):
# Make a mixin of both
# the wx related startup code, building the gui
def OnInit(self):
self.frame = MyFrame(None, -1, 'Hallo')
self.frame.Show(True)
self.SetTopWindow(self.frame)
return True
# some XML-RPC function calls for twisted server
def xmlrpc_stop(self):
"""Closes the wx application."""
self.frame.Close() # Sending closing event
return 'Shutdown initiated'
def xmlrpc_title(self, x):
"""Return all passed args."""
self.frame.SetTitle(x)
return x.upper()
def xmlrpc_add(self, a, b):
"""Return sum of arguments."""
return a + b
if __name__ == '__main__':
# Initiliaze MyApp
app = MyXMLRPCApp(False) # False -> printing stdout/stderr to shell,
# not in an additional wx window
# Make wx application twisted aware
# Must have to start "wxreactor.install()" on top before
reactor.registerWxApp(app)
# Make a XML-RPC Server listening to port 7080
reactor.listenTCP(7080, server.Site(app))
# Start both reactor parts (wx MainLoop and XML-RPC server)
reactor.run()
|
Focus: Make a wxPython application also acting as a XML-RPC server, listening to a dedicated port.
Problem: A wx application has a mainloop, so has the xml-rpc server. Various approaches to join these loops are: - blocking - ugly / hackish - complex
Solution: Twisted wxreactor to support wxPython (/TwistedDocs/examples/wxdemo.py) Twisted xml-rpc server (/TwistedDocs/howto/xmlrpc.xhtml)
Joining them compact into this demo.
Testing: Starting module from shell. Opening other shell with python interpreter:
>>> from xmlrpclib import *
>>> s = ServerProxy('http://localhost:7080') # Get access to xmlrpc server
>>> s.title('Hallo xmlrpc app') # this call changes the title of the wx application
'HALLO XMLRPC APP'
>>> s.add(4,5) # a non gui related call
9
>>> s.stop() # killing the wx application
'Shutdown initiated'
Environment: Python 2.3.4 wxPython 2.5.1.5 twisted 1.3.0
Tested on WIN XP
On WinXP with wxPython 2.8.9.1 and Twisted 8.1 I needed to change the following for it to work:
... class MyXMLRPCApp(wx.App, xmlrpc.XMLRPC): # Make a mixin of both allowNone = True ...