Copied/merged from the 2.2 branch.
Changes needed to build with new event system git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9374 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
91
wxPython/wxPython/lib/anchors.py
Normal file
91
wxPython/wxPython/lib/anchors.py
Normal file
@@ -0,0 +1,91 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wxPython.lib.anchors
|
||||
# Purpose: A class that provides an easy to use interface over layout
|
||||
# constraints for anchored layout.
|
||||
#
|
||||
# Author: Riaan Booysen
|
||||
#
|
||||
# Created: 15-Dec-2000
|
||||
# RCS-ID: $Id$
|
||||
# Copyright: (c) 2000 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
from wxPython.wx import wxLayoutConstraints, wxTop, wxLeft, wxBottom, wxRight, \
|
||||
wxHeight, wxWidth
|
||||
|
||||
class LayoutAnchors(wxLayoutConstraints):
|
||||
""" A class that implements Delphi's Anchors with wxLayoutConstraints.
|
||||
|
||||
Anchored sides maintain the distance from the edge of the
|
||||
control to the same edge of the parent.
|
||||
When neither side is selected, the control keeps the same
|
||||
relative position to both sides.
|
||||
|
||||
The current position and size of the control and it's parent
|
||||
is used when setting up the constraints. To change the size or
|
||||
position of an already anchored control, set the constraints to
|
||||
None, reposition or resize and reapply the anchors.
|
||||
|
||||
Examples:
|
||||
|
||||
Let's anchor the right and bottom edge of a control and
|
||||
resize it's parent.
|
||||
|
||||
ctrl.SetConstraints(LayoutAnchors(ctrl, left=0, top=0, right=1, bottom=1))
|
||||
|
||||
+=========+ +===================+
|
||||
| +-----+ | | |
|
||||
| | * | -> | |
|
||||
| +--*--+ | | +-----+ |
|
||||
+---------+ | | * |
|
||||
| +--*--+ |
|
||||
+-------------------+
|
||||
* = anchored edge
|
||||
|
||||
When anchored on both sides the control will stretch horizontally.
|
||||
|
||||
ctrl.SetConstraints(LayoutAnchors(ctrl, 1, 0, 1, 1))
|
||||
|
||||
+=========+ +===================+
|
||||
| +-----+ | | |
|
||||
| * * | -> | |
|
||||
| +--*--+ | | +---------------+ |
|
||||
+---------+ | * ctrl * |
|
||||
| +-------*-------+ |
|
||||
+-------------------+
|
||||
* = anchored edge
|
||||
"""
|
||||
def __init__(self, control, left = 1, top = 1, right = 0, bottom = 0):
|
||||
wxLayoutConstraints.__init__(self)
|
||||
parent = control.GetParent()
|
||||
if not parent: return
|
||||
|
||||
pPos, pSize = parent.GetPosition(), parent.GetClientSize()
|
||||
cPos, cSize = control.GetPosition(), control.GetSize()
|
||||
|
||||
self.setConstraintSides(self.left, wxLeft, left,
|
||||
self.right, wxRight, right,
|
||||
self.width, wxWidth, self.centreX,
|
||||
cPos.x, cSize.x, pSize.x, parent)
|
||||
|
||||
self.setConstraintSides(self.top, wxTop, top,
|
||||
self.bottom, wxBottom, bottom,
|
||||
self.height, wxHeight, self.centreY,
|
||||
cPos.y, cSize.y, pSize.y, parent)
|
||||
|
||||
def setConstraintSides(self, side1, side1Edge, side1Anchor,
|
||||
side2, side2Edge, side2Anchor,
|
||||
size, sizeEdge, centre,
|
||||
cPos, cSize, pSize, parent):
|
||||
if side2Anchor:
|
||||
side2.SameAs(parent, side2Edge, pSize - (cPos + cSize))
|
||||
if side1Anchor:
|
||||
side1.SameAs(parent, side1Edge, cPos)
|
||||
if not side2Anchor:
|
||||
size.AsIs()
|
||||
else:
|
||||
size.AsIs()
|
||||
if not side2Anchor:
|
||||
centre.PercentOf(parent, sizeEdge,
|
||||
int(((cPos + cSize / 2.0) / pSize)*100))
|
@@ -67,6 +67,7 @@ class wxGenButton(wxControl):
|
||||
self.bezelWidth = 2
|
||||
self.hasFocus = false
|
||||
self.useFocusInd = true
|
||||
self.evtToSend = []
|
||||
|
||||
self.SetLabel(label)
|
||||
self.SetPosition(pos)
|
||||
@@ -86,6 +87,7 @@ class wxGenButton(wxControl):
|
||||
EVT_KEY_UP(self, self.OnKeyUp)
|
||||
EVT_ERASE_BACKGROUND(self, self.OnEraseBackground)
|
||||
EVT_PAINT(self, self.OnPaint)
|
||||
EVT_IDLE(self, self.OnIdle)
|
||||
|
||||
|
||||
def SetBestSize(self, size=None):
|
||||
@@ -174,7 +176,14 @@ class wxGenButton(wxControl):
|
||||
evt = wxGenButtonEvent(wxEVT_COMMAND_BUTTON_CLICKED, self.GetId())
|
||||
evt.SetIsDown(not self.up)
|
||||
evt.SetButtonObj(self)
|
||||
self.GetEventHandler().ProcessEvent(evt)
|
||||
self.evtToSend.append(evt)
|
||||
|
||||
|
||||
def OnIdle(self, evt):
|
||||
while self.evtToSend:
|
||||
evt = self.evtToSend[0]
|
||||
del self.evtToSend[0]
|
||||
self.GetEventHandler().ProcessEvent(evt)
|
||||
|
||||
|
||||
def DrawBezel(self, dc, x1, y1, x2, y2):
|
||||
|
249
wxPython/wxPython/lib/fancytext.py
Normal file
249
wxPython/wxPython/lib/fancytext.py
Normal file
@@ -0,0 +1,249 @@
|
||||
"""wxFancyText -- methods for rendering XML specified text
|
||||
|
||||
This module has four main methods:
|
||||
|
||||
def getExtent(str, dc=None, enclose=1):
|
||||
def renderToBitmap(str, background=None, enclose=1)
|
||||
def renderToDC(str, dc, x, y, enclose=1)
|
||||
|
||||
In all cases, 'str' is an XML string. The tags in the string can
|
||||
currently specify the font, subscripts, superscripts, and the angle
|
||||
sign. The allowable properties of font are size, family, style, weght,
|
||||
encoding, and color. See the example on the bottom for a better idea
|
||||
of how this works.
|
||||
|
||||
Note that start and end tags for the string are provided if enclose is
|
||||
true, so for instance, renderToBitmap("X<sub>1</sub>") will work.
|
||||
|
||||
"""
|
||||
# Copyright 2001 Timothy Hochberg
|
||||
# Use as you see fit. No warantees, I cannot be held responsible, etc.
|
||||
|
||||
|
||||
|
||||
# TODO: Make a wxFancyTextCtrl class that derives from wxControl.
|
||||
# Add support for line breaks
|
||||
# etc.
|
||||
# - Robin
|
||||
|
||||
|
||||
|
||||
from wxPython.wx import *
|
||||
import xml.parsers.expat, copy
|
||||
|
||||
_families = {"default" : wxDEFAULT, "decorative" : wxDECORATIVE, "roman" : wxROMAN,
|
||||
"swiss" : wxSWISS, "modern" : wxMODERN}
|
||||
_styles = {"normal" : wxNORMAL, "slant" : wxSLANT, "italic" : wxITALIC}
|
||||
_weights = {"normal" : wxNORMAL, "light" : wxLIGHT, "bold" : wxBOLD}
|
||||
|
||||
# The next three classes: Renderer, SizeRenderer and DCRenderer are
|
||||
# what you will need to override to extend the XML language. All of
|
||||
# the font stuff as well as the subscript and superscript stuff are in
|
||||
# Renderer.
|
||||
|
||||
class Renderer:
|
||||
|
||||
defaultSize = wxNORMAL_FONT.GetPointSize()
|
||||
defaultFamily = wxDEFAULT
|
||||
defaultStyle = wxNORMAL
|
||||
defaultWeight = wxNORMAL
|
||||
defaultEncoding = wxFont_GetDefaultEncoding()
|
||||
defaultColor = "black"
|
||||
|
||||
def __init__(self, dc=None):
|
||||
if dc == None:
|
||||
dc = wxMemoryDC()
|
||||
self.dc = dc
|
||||
self.offsets = [0]
|
||||
self.fonts = [{}]
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
method = "start_" + name
|
||||
if not hasattr(self, method):
|
||||
raise ValueError("XML tag '%s' not supported" % name)
|
||||
getattr(self, method)(attrs)
|
||||
|
||||
def endElement(self, name):
|
||||
method = "end_" + name
|
||||
if not hasattr(self, method):
|
||||
raise ValueError("XML tag '%s' not supported" % name)
|
||||
getattr(self, method)()
|
||||
|
||||
def start_wxFancyString(self, attrs):
|
||||
pass
|
||||
|
||||
def end_wxFancyString(self):
|
||||
pass
|
||||
|
||||
def start_font(self, attrs):
|
||||
for key, value in attrs.items():
|
||||
if key == "size":
|
||||
value = int(value)
|
||||
elif key == "family":
|
||||
value = _families[value]
|
||||
elif key == "style":
|
||||
value = _styles[value]
|
||||
elif key == "weight":
|
||||
value = _weights[value]
|
||||
elif key == "encoding":
|
||||
pass
|
||||
elif key == "color":
|
||||
pass
|
||||
else:
|
||||
raise ValueError("unknown font attribute '%s'" % key)
|
||||
attrs[key] = value
|
||||
font = copy.copy(self.fonts[-1])
|
||||
font.update(attrs)
|
||||
self.fonts.append(font)
|
||||
|
||||
def end_font(self):
|
||||
self.fonts.pop()
|
||||
|
||||
def start_sub(self, attrs):
|
||||
if attrs.keys():
|
||||
raise ValueError("<sub> does not take attributes")
|
||||
font = self.getCurrentFont()
|
||||
self.offsets.append(self.offsets[-1] + self.dc.GetFullTextExtent("M", font)[1]*0.5)
|
||||
self.start_font({"size" : font.GetPointSize() * 0.8})
|
||||
|
||||
def end_sub(self):
|
||||
self.fonts.pop()
|
||||
self.offsets.pop()
|
||||
|
||||
def start_sup(self, attrs):
|
||||
if attrs.keys():
|
||||
raise ValueError("<sup> does not take attributes")
|
||||
font = self.getCurrentFont()
|
||||
self.offsets.append(self.offsets[-1] - self.dc.GetFullTextExtent("M", font)[1]*0.3)
|
||||
self.start_font({"size" : font.GetPointSize() * 0.8})
|
||||
|
||||
def end_sup(self):
|
||||
self.fonts.pop()
|
||||
self.offsets.pop()
|
||||
|
||||
def getCurrentFont(self):
|
||||
font = self.fonts[-1]
|
||||
return wxFont(font.get("size", self.defaultSize),
|
||||
font.get("family", self.defaultFamily),
|
||||
font.get("style", self.defaultStyle),
|
||||
font.get("weight", self.defaultWeight),
|
||||
encoding = font.get("encoding", self.defaultEncoding))
|
||||
|
||||
def getCurrentColor(self):
|
||||
font = self.fonts[-1]
|
||||
return wxNamedColour(font.get("color", self.defaultColor))
|
||||
|
||||
|
||||
class SizeRenderer(Renderer):
|
||||
|
||||
def __init__(self, dc=None):
|
||||
Renderer.__init__(self, dc)
|
||||
self.width = self.height = 0
|
||||
self.minY = self.maxY = 0
|
||||
|
||||
def characterData(self, data):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
width, height = self.dc.GetTextExtent(data)
|
||||
self.width = self.width + width
|
||||
self.minY = min(self.minY, self.offsets[-1])
|
||||
self.maxY = max(self.maxY, self.offsets[-1] + height)
|
||||
self.height = self.maxY - self.minY
|
||||
|
||||
def start_angle(self, attrs):
|
||||
self.characterData("M")
|
||||
|
||||
def end_angle(self):
|
||||
pass
|
||||
|
||||
class DCRenderer(Renderer):
|
||||
|
||||
def __init__(self, dc=None, x=0, y=0):
|
||||
Renderer.__init__(self, dc)
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
def characterData(self, data):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
self.dc.SetTextForeground(self.getCurrentColor())
|
||||
width, height = self.dc.GetTextExtent(data)
|
||||
self.dc.DrawText(data, self.x, self.y + self.offsets[-1])
|
||||
self.x = self.x + width
|
||||
|
||||
def start_angle(self, attrs):
|
||||
self.dc.SetFont(self.getCurrentFont())
|
||||
self.dc.SetPen(wxPen(self.getCurrentColor(), 1))
|
||||
width, height, descent, leading = self.dc.GetFullTextExtent("M")
|
||||
y = self.y + self.offsets[-1] + height - descent
|
||||
self.dc.DrawLine(self.x, y, self.x+width, y)
|
||||
self.dc.DrawLine(self.x, y, self.x+width, y-width)
|
||||
self.x = self.x + width
|
||||
|
||||
def end_angle(self):
|
||||
pass
|
||||
|
||||
# This is a rendering function that is primarily used internally,
|
||||
# although it could be used externally if one had overridden the
|
||||
# Renderer classes.
|
||||
|
||||
def renderToRenderer(str, renderer, enclose=1):
|
||||
if enclose:
|
||||
str = '<?xml version="1.0"?><wxFancyString>%s</wxFancyString>' % str
|
||||
p = xml.parsers.expat.ParserCreate()
|
||||
p.returns_unicode = 0
|
||||
p.StartElementHandler = renderer.startElement
|
||||
p.EndElementHandler = renderer.endElement
|
||||
p.CharacterDataHandler = renderer.characterData
|
||||
p.Parse(str, 1)
|
||||
|
||||
|
||||
def getExtent(str, dc=None, enclose=1):
|
||||
"Return the extent of str"
|
||||
renderer = SizeRenderer(dc)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
return wxSize(renderer.width, renderer.height)
|
||||
|
||||
# This should probably only be used internally....
|
||||
|
||||
def getFullExtent(str, dc=None, enclose=1):
|
||||
renderer = SizeRenderer(dc)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
return renderer.width, renderer.height, -renderer.minY
|
||||
|
||||
def renderToBitmap(str, background=None, enclose=1):
|
||||
"Return str rendered on a minumum size bitmap"
|
||||
dc = wxMemoryDC()
|
||||
width, height, dy = getFullExtent(str, dc)
|
||||
bmp = wxEmptyBitmap(width, height)
|
||||
dc.SelectObject(bmp)
|
||||
if background is not None:
|
||||
dc.SetBackground(background)
|
||||
dc.Clear()
|
||||
renderer = DCRenderer(dc, y=dy)
|
||||
dc.BeginDrawing()
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
dc.EndDrawing()
|
||||
dc.SelectObject(wxNullBitmap)
|
||||
return bmp
|
||||
|
||||
def renderToDC(str, dc, x, y, enclose=1):
|
||||
"Render str onto a wxDC at (x,y)"
|
||||
width, height, dy = getFullExtent(str, dc)
|
||||
renderer = DCRenderer(dc, x, y+dy)
|
||||
renderToRenderer(str, renderer, enclose)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
str = ('<font style="italic" family="swiss" color="red" weight="bold" >some |<sup>23</sup> <angle/>text<sub>with <angle/> subscript</sub> </font> some other text'
|
||||
'<font family="swiss" color="green" size="40">big green text</font>')
|
||||
ID_EXIT = 102
|
||||
class myApp(wxApp):
|
||||
def OnInit(self):
|
||||
return 1
|
||||
app = myApp()
|
||||
frame = wxFrame(NULL, -1, "wxFancyText demo", wxDefaultPosition)
|
||||
frame.SetClientSize(getExtent(str))
|
||||
bmp = renderToBitmap(str, wxCYAN_BRUSH)
|
||||
sb = wxStaticBitmap(frame, -1, bmp)
|
||||
EVT_MENU(frame, ID_EXIT, frame.Destroy)
|
||||
frame.Show(1)
|
||||
app.MainLoop()
|
@@ -31,7 +31,7 @@ class FileBrowseButton(wxPanel):
|
||||
startDirectory -- Default directory for file dialog startup
|
||||
fileMask -- File mask (glob pattern, such as *.*) to use in file dialog
|
||||
fileMode -- wxOPEN or wxSAVE, indicates type of file dialog to use
|
||||
changeCallback -- callback receives all changes in value of control
|
||||
changeCallback -- callback receives all > > changes in value of control
|
||||
)
|
||||
GetValue() -- retrieve current value of text control
|
||||
SetValue(string) -- set current value of text control
|
||||
|
236
wxPython/wxPython/lib/rpcMixin.py
Normal file
236
wxPython/wxPython/lib/rpcMixin.py
Normal file
@@ -0,0 +1,236 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: rpcMixin
|
||||
# Version: 0.1
|
||||
# Purpose: provides xmlrpc server functionality for wxPython
|
||||
# applications via a mixin class
|
||||
#
|
||||
# Requires: (1) Python with threading enabled.
|
||||
# (2) xmlrpclib from PythonWare
|
||||
# (http://www.pythonware.com/products/xmlrpc/)
|
||||
# the code was developed and tested using version 0.9.8
|
||||
#
|
||||
# Author: greg Landrum (Landrum@RationalDiscovery.com)
|
||||
#
|
||||
# Copyright: (c) 2000 by Greg Landrum and Rational Discovery LLC
|
||||
# Licence: wxWindows license
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
Some Notes:
|
||||
|
||||
1) The xmlrpc server runs in a separate thread from the main GUI
|
||||
application, communication between the two threads using a custom
|
||||
event (see the Threads demo in the wxPython docs for more info).
|
||||
|
||||
2) Neither the server nor the client are particularly smart about
|
||||
checking method names. So it's easy to shoot yourself in the foot
|
||||
by calling improper methods. It would be pretty easy to add
|
||||
either a list of allowed methods or a list of forbidden methods.
|
||||
|
||||
3) Authentication of xmlrpc clients is *not* performed. I think it
|
||||
would be pretty easy to do this in a hacky way, but I haven't done
|
||||
it yet.
|
||||
|
||||
4) The default port number is 800, it's a windows thing... at least
|
||||
it seems like a windows thing to me. Since I'm not being smart
|
||||
about port numbers, you can probably hork yourself arbitrarily by
|
||||
firing up more than one xmlrpc-active frame at the same time, but
|
||||
I haven't tried that.
|
||||
|
||||
5) See the bottom of this file for an example of using the class.
|
||||
|
||||
Obligatory disclaimer:
|
||||
This is my first crack at both using xmlrpc and multi-threaded
|
||||
programming, so there could be huge horrible bugs or design
|
||||
flaws. If you see one, I'd love to hear about them.
|
||||
|
||||
"""
|
||||
|
||||
from wxPython.wx import *
|
||||
import xmlrpcserver
|
||||
import Threading
|
||||
import SocketServer
|
||||
|
||||
rpcPENDING = 0
|
||||
rpcDONE = 1
|
||||
rpcEXCEPT = 2
|
||||
class RPCRequest:
|
||||
"""A wrapper to use for handling requests and their responses"""
|
||||
status = rpcPENDING
|
||||
result = None
|
||||
|
||||
# here's the ID for external events
|
||||
wxEVT_EXTERNAL_EVENT = 25015
|
||||
class ExternalEvent(wxPyEvent):
|
||||
"""The custom event class used to pass xmlrpc calls from
|
||||
the server thread into the GUI thread
|
||||
"""
|
||||
def __init__(self,method,args):
|
||||
wxPyEvent.__init__(self)
|
||||
self.SetEventType(wxEVT_EXTERNAL_EVENT)
|
||||
self.method = method
|
||||
self.args = args
|
||||
self.rpcStatus = RPCRequest()
|
||||
self.rpcStatusLock = Threading.Lock()
|
||||
self.rpcCondVar = Threading.Condition()
|
||||
|
||||
def EVT_EXTERNAL_EVENT(win,func):
|
||||
win.Connect(-1,-1,wxEVT_EXTERNAL_EVENT,func)
|
||||
|
||||
class Handler(xmlrpcserver.RequestHandler):
|
||||
"""The handler class that the xmlrpcserver actually calls
|
||||
when a request comes in.
|
||||
"""
|
||||
def call(self,method,params):
|
||||
"""When an xmlrpc request comes in, this is the method that
|
||||
gets called.
|
||||
"""
|
||||
# construct the event
|
||||
evt = ExternalEvent(method,params)
|
||||
|
||||
# update the status variable
|
||||
evt.rpcStatusLock.acquire()
|
||||
evt.rpcStatus.status = rpcPENDING
|
||||
evt.rpcStatusLock.release()
|
||||
|
||||
# acquire the condition lock
|
||||
evt.rpcCondVar.acquire()
|
||||
# dispatch the event to the GUI
|
||||
wxPostEvent(self._app,evt)
|
||||
# wait for the GUI to finish
|
||||
while evt.rpcStatus.status == rpcPENDING:
|
||||
evt.rpcCondVar.wait()
|
||||
evt.rpcCondVar.release()
|
||||
evt.rpcStatusLock.acquire()
|
||||
if evt.rpcStatus.status == rpcEXCEPT:
|
||||
# The GUI threw an exception, release the status lock
|
||||
# and re-raise the exception
|
||||
evt.rpcStatusLock.release()
|
||||
raise evt.rpcStatus.result[0],evt.rpcStatus.result[1]
|
||||
else:
|
||||
# everything went through without problems
|
||||
s = evt.rpcStatus.result
|
||||
evt.rpcStatusLock.release()
|
||||
return s
|
||||
|
||||
class rpcMixin:
|
||||
"""A mixin class to provide xmlrpc server functionality to wxPython
|
||||
frames/windows
|
||||
|
||||
If you want to customize this, probably the best idea is to
|
||||
override the OnExternal method, which is what's invoked when an
|
||||
RPC is handled.
|
||||
|
||||
"""
|
||||
def __init__(self,host='',port=800):
|
||||
"""
|
||||
Arguments:
|
||||
host: (optional) the hostname for the server
|
||||
port: (optional) the port the server will use
|
||||
"""
|
||||
EVT_EXTERNAL_EVENT(self,self.OnExternal)
|
||||
if hasattr(self,'OnClose'):
|
||||
self._origOnClose = self.OnClose
|
||||
else:
|
||||
self._origOnClose = None
|
||||
EVT_CLOSE(self,self.OnClose)
|
||||
|
||||
exec('class Handler%d(Handler): pass'%(port))
|
||||
exec('tClass= Handler%d'%(port))
|
||||
tClass._app = self
|
||||
self._xmlServ = SocketServer.TCPServer((host,port),tClass)
|
||||
self.servThread = Threading.Thread(target=self._xmlServ.serve_forever)
|
||||
self.servThread.setDaemon(1)
|
||||
self.servThread.start()
|
||||
|
||||
def OnClose(self,event):
|
||||
""" be sure to shutdown the server and the server thread before
|
||||
leaving
|
||||
"""
|
||||
self._xmlServ = None
|
||||
self.servThread = None
|
||||
if self._origOnClose is not None:
|
||||
self._origOnClose(event)
|
||||
|
||||
def OnExternal(self,event):
|
||||
""" this is the callback used to handle RPCs
|
||||
|
||||
Exceptions are caught and returned in the global _rpcStatus
|
||||
structure. This allows the xmlrpc server to report the
|
||||
exception to the client without mucking up any of the delicate
|
||||
thread stuff.
|
||||
"""
|
||||
event.rpcStatusLock.acquire()
|
||||
try:
|
||||
res = eval('apply(self.%s,event.args)'%event.method)
|
||||
except:
|
||||
import sys,traceback
|
||||
traceback.print_exc()
|
||||
event.rpcStatus.result = sys.exc_info()[:2]
|
||||
event.rpcStatus.status = rpcEXCEPT
|
||||
else:
|
||||
if res is None:
|
||||
event.rpcStatus.result = []
|
||||
else:
|
||||
event.rpcStatus.result = res
|
||||
event.rpcStatus.status = rpcDONE
|
||||
event.rpcStatusLock.release()
|
||||
event.rpcCondVar.acquire()
|
||||
event.rpcCondVar.notify()
|
||||
event.rpcCondVar.release()
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
port = 800
|
||||
if len(sys.argv)>1:
|
||||
port = int(sys.argv[1])
|
||||
|
||||
class rpcFrame(wxFrame,rpcMixin):
|
||||
"""A simple wxFrame with the rpcMixin functionality added
|
||||
"""
|
||||
def __init__(self,*args,**kwargs):
|
||||
""" rpcHost or rpcPort keyword arguments will be passed along to
|
||||
the xmlrpc server.
|
||||
"""
|
||||
mixinArgs = {}
|
||||
if kwargs.has_key('rpcHost'):
|
||||
mixinArgs['host'] = kwargs['rpcHost']
|
||||
del kwargs['rpcHost']
|
||||
if kwargs.has_key('rpcPort'):
|
||||
mixinArgs['port'] = kwargs['rpcPort']
|
||||
del kwargs['rpcPort']
|
||||
|
||||
apply(wxFrame.__init__,(self,)+args,kwargs)
|
||||
apply(rpcMixin.__init__,(self,),mixinArgs)
|
||||
|
||||
EVT_CHAR(self,self.OnChar)
|
||||
|
||||
def TestFunc(self,args):
|
||||
"""a demo method"""
|
||||
return args
|
||||
|
||||
def OnChar(self,event):
|
||||
key = event.GetKeyCode()
|
||||
if key == ord('q'):
|
||||
self.OnQuit(event)
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.OnClose(event)
|
||||
|
||||
def OnClose(self,event):
|
||||
self.Destroy()
|
||||
|
||||
class MyApp(wxApp):
|
||||
def OnInit(self):
|
||||
frame = rpcFrame(NULL, -1, "wxPython RPCDemo", wxDefaultPosition, wxSize(300,300),rpcHost='localhost',rpcPort=port)
|
||||
frame.Show(TRUE)
|
||||
import time
|
||||
|
||||
#self.SetTopWindow(frame)
|
||||
frame2 = rpcFrame(NULL, -1, "wxPython RPCDemo2", wxDefaultPosition, wxSize(300,300),rpcHost='localhost',rpcPort=port+1)
|
||||
frame2.Show(TRUE)
|
||||
|
||||
return TRUE
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
||||
|
Reference in New Issue
Block a user