Hi WxPython Experts !
I have written a caller application,
it sits in the sys tray and waits for the tapi client to say there is an
incoming call.
When a call comes in
- the remote_call function (in the
TwistedClient Class) takes the details - it passes this on to the onIncomingCall
function (in the MailFrame class) - this function is supopsed to run
the Fader() class which in turn pops up the fading window !
I tested it by setting one of the menu
items to trigger the fade window, which worked just fine. But when I call
my phone it gives me the error "timercan
only be started from the main thread"
I suspect this is because the TAPI client
is running on its own thread but i’ve no idea how to fix it ? is there
any way around this problem. My wxpython knowledge is not great ! Here
is the relevant code from the app (sorry its not the best of code as I
was trying to get it working before tidying it up !)
#-STARTOFCODE
SERVER = “marvin”
PORT = 8800
ICON = “working.ico”
APPNAME = “tapiclient”
RECEPTIONPCNAME = “optiplex989”
ID_ICON_TIMER=wx.NewId()
OPEN_VOICEMAIL=wx.NewId()
OPEN_PHONEBOOK=wx.NewId()
OPEN_FADETEST=wx.NewId()
class TwistedClient(pb.Referenceable,Thread):
def __init__(self, parent):
self.parentApp
= parent
Thread.__init__(self)
self.setDaemon(True)
self.start()
def remote_call(self,
details):
detail =
details.split(",")
call
= detail[0]
caller =
detail[1]
company
= detail[2]
print "remote_call"
self.parentApp.onIncomingCall('abc')
#self.app.onIncomingCall(call,
caller, company)
def makeCall(self,number):
c = self.perspective.callRemote("call",number)
c.addErrback(self.makeCallErr)
def makeCallErr(self,failure):
try:
raise failure.trap(tapiserver.NoSuchLineError,
tapiserver.LineInUseException,
tapiserver.CallCreationError)
except tapiserver.LineInUseException:
getWxAppsModule().showError(“Sorry”,“Couldn’t make call:
Your line appears to be in use.”)
except tapiserver.NoSuchLineError:
getWxAppsModule().showError(‘Sorry’,“Couldn’t find you phone line.\n\nPicking
up your phone and putting it down again should fix this”)
except tapiserver.CallCreationError:
getWxAppsModule().showError(‘Sorry’,“Couldn’t create the call, are
you sure the number’s valid?”)
def run(self):
self.connect()
def connect(self):
factory
= pb.PBClientFactory()
global username
try:
reactor.connectTCP(SERVER, PORT, factory)
except:
logging.error(“Couldn’t connect to server %s:%s”%(SERVER,PORT))
if socket.gethostname()
== RECEPTIONPCNAME: username = ‘main’
else: username
= os.environ[‘username’]
logging.info(os.environ['username'])
def1 = factory.login(credentials.UsernamePassword(username,
‘’),client=self)
def1.addCallbacks(self.connected,self.failure)
reactor.run(installSignalHandlers=0)
def connected(self, perspective):
# this perspective
is a reference to our User object
self.perspective
= perspective
perspective.callRemote("register")
def failure(self,_):
logging.debug("Connection
to server failed")
self.shutdown()
self.app.quit()
def shutdown(self):
reactor.stop()
class MailTaskBarIcon(wx.TaskBarIcon):
def __init__(self, parent):
wx.TaskBarIcon.__init__(self)
self.parentApp
= parent
self.noMailIcon
= wx.Icon(“test.png”,wx.BITMAP_TYPE_PNG)
self.youHaveMailIcon
= wx.Icon(“test.png”,wx.BITMAP_TYPE_PNG)
self.CreateMenu()
self.SetIconImage()
def CreateMenu(self):
self.Bind(wx.EVT_TASKBAR_RIGHT_UP,
self.ShowMenu)
self.Bind(wx.EVT_MENU,
self.parentApp.onIncomingCall, id=OPEN_VOICEMAIL)
self.Bind(wx.EVT_MENU,
self.parentApp.OpenPhoneBook, id=OPEN_PHONEBOOK)
self.Bind(wx.EVT_MENU,
self.parentApp.FadeTest, id=OPEN_FADETEST)
self.menu=wx.Menu()
self.menu.Append(OPEN_FADETEST,
“FADETEST”)
self.menu.AppendSeparator()
self.menu.Append(OPEN_VOICEMAIL,
“Check VoiceMail”)
self.menu.Append(OPEN_PHONEBOOK,
“Crummock Phonebook”)
self.menu.AppendSeparator()
self.menu.Append(wx.ID_EXIT,
“Quit”)
def ShowMenu(self,event):
self.PopupMenu(self.menu)
def SetIconImage(self,
mail=False):
self.SetIcon(self.noMailIcon,
“Crumomck CallerID V2.0”)
class MailFrame(wx.Frame):
def __init__(self, parent,
id, title):
self.tapiManager
= TwistedClient(self)
comserver.loadServer(self.tapiManager)
wx.Frame.__init__(self,
parent, -1, title, size = (1, 1),
style=wx.FRAME_NO_TASKBAR|wx.NO_FULL_REPAINT_ON_RESIZE)
self.tbicon
= MailTaskBarIcon(self)
self.tbicon.Bind(wx.EVT_MENU,
self.exitApp, id=wx.ID_EXIT)
self.Show(True)
def voiceMail(self,app=None):
print "Voicemail
dialling …"
self.tapiManager.makeCall("*17")
def callNumber(self,number,app=None):
self.tapiManager.makeCall(number)
def onIncomingCall(self,
event):
print "onIncomingCall"
self.FadeTest('abc')
def FadeTest(self, abc):
print "running
FadeTest"
frm = Fader()
frm.Show()
def exitApp(self,event):
self.tbicon.RemoveIcon()
self.tbicon.Destroy()
sys.exit()
def OpenPhoneBook(self,event):
self.frame
= wx.Frame(self, wx.ID_ANY, “Phonebook”, size=(200, 350))
self.listbox
= wx.ListBox(self.frame, wx.ID_ANY, choices=[], size=wx.Size(195, 300),
style=0)
self.listbox.Bind(wx.EVT_LISTBOX,
self.OnListBox1Listbox)
self.button
= wx.Button(self.frame, id=wx.ID_ANY, label=u’Select person to call’,
name=‘button’, pos=wx.Point(0, 300),
size=wx.Size(193, 24), style=0)
self.button.Bind(wx.EVT_BUTTON,
self.MakeCall, id=wx.ID_ANY)
global numbers
numbers
= {}
filepath
= r’\leo\c$\tools\dat\agent_out.txt’
file = open(filepath,
‘r’)
for line
in file.readlines():
mywords = line.split(’,’)
if (mywords[0][:9] == ‘901875825’):
numbers[mywords[1]] = mywords[0][9:]
for item
in sorted(numbers):
self.listbox.Append(item)
self.frame.Center()
self.frame.Show(True)
return True
def OnListBox1Listbox(self,
event):
'''
click list
item and display the selected string in frame’s title
'''
selName
= self.listbox.GetStringSelection()
if numbers.has_key(selName):
self.number = numbers[selName]
self.button.SetLabel(“Call “+ selName + " (”+self.number+”)")
def MakeCall(self, event):
m.callNumber(self.number)
self.frame.Show(False)
class Fader(wx.Frame):
def __init__(self):
print "Running
fader…"
popWidth
= 250
popHeight
= 100
displayRect
= wx.GetClientDisplayRect()
posWidth
= (displayRect.width - 10 ) - popWidth
posHeight
= (displayRect.height -10) - popHeight
self.frame
= wx.Frame.init(self, None, title=‘Test’, pos=(posWidth, posHeight),
size=(popWidth, popHeight), style=wx.STAY_ON_TOP | wx.FRAME_NO_TASKBAR)
self.amount
= 10
self.delta
= 10
self.panel
= wx.Panel(self, wx.ID_ANY, pos=(0, 0), size=(popWidth, 20))
self.panel.SetBackgroundColour(wx.Colour(220,
220, 220))
self.CloseButton
= wx.BitmapButton(self.panel, wx.ID_ANY, wx.Bitmap(“close.bmp”),
pos=(228, 0), size=(20, 20), style=0)
self.Bind(wx.EVT_BUTTON,
self.OnClose, self.CloseButton)
self.panel2
= wx.Panel(self, wx.ID_ANY, pos=(0, 20), size=(popWidth, 80))
self.panel2.SetBackgroundColour(wx.Colour(238,
238, 238))
self.calltype
= wx.StaticText(self.panel, wx.ID_ANY, “Internal Call”, pos=(88,2))
self.calltype.SetFont(wx.Font(8,
wx.SWISS, wx.NORMAL, wx.BOLD))
self.calltype.SetBackgroundColour(wx.Colour(220,
220, 220))
self.calltype.SetForegroundColour(wx.Colour(100,
100, 100))
self.callImage
= wx.StaticBitmap(self.panel2, wx.ID_ANY, wx.Bitmap(“call.bmp”),
size=(22, 22), pos=(2,5))
self.callNumber
= wx.StaticText(self.panel2, wx.ID_ANY, “01234 567890”, pos=(28,5))
self.callNumber.SetFont(wx.Font(14,
wx.SWISS, wx.NORMAL, wx.BOLD))
self.callImage
= wx.StaticBitmap(self.panel2, wx.ID_ANY, wx.Bitmap(“person.bmp”),
size=(20, 31), pos=(4,37))
self.caller
= wx.StaticText(self.panel2, wx.ID_ANY, “Username”, pos=(28,37))
self.caller.SetFont(wx.Font(10,
wx.SWISS, wx.NORMAL, wx.BOLD))
self.caller.SetBackgroundColour(wx.Colour(238,
238, 238))
self.company
= wx.StaticText(self.panel2, wx.ID_ANY, “Company Name”, pos=(29,54))
self.company.SetFont(wx.Font(8,
wx.SWISS, wx.NORMAL, wx.BOLD))
self.company.SetBackgroundColour(wx.Colour(238,
238, 238))
self.SetTransparent(self.amount)
# -------
Fader Timer -------- ##
self.timer
= wx.Timer(self, wx.ID_ANY)
self.timer.Start(30)
self.Bind(wx.EVT_TIMER,
self.AlphaCycleUp)
# ----------------------------
···
def AlphaCycleUp(self,
evt):
self.amount
+= self.delta
if self.amount
= 230:
self.timer.Stop()
self.delta = -5
------- Fader Timer --------
self.timer2 = wx.Timer(self, wx.ID_ANY)
self.timer2.Start(5000)
self.Bind(wx.EVT_TIMER, self.AlphaWait)
----------------------------
self.amount = 230
self.SetTransparent(self.amount)
def AlphaWait(self, evt):
self.timer2.Stop()
self.timer3
= wx.Timer(self, wx.ID_ANY)
self.timer3.Start(60)
self.Bind(wx.EVT_TIMER,
self.AlphaCycleDown)
def AlphaCycleDown(self,
evt):
self.amount
+= self.delta
if self.amount
<= 0:
self.timer3.Stop()
self.amount = 0
self.SetTransparent(self.amount)
def OnClose(self, evt):
self.timer.Stop()
try:
self.timer2.Stop()
except:
print “Can’t stop timer2”
try:
self.timer3.Stop()
except:
print “Can’t stop timer3”
self.Destroy()
#---------------- run the program -----------------------
def go():
app = wx.App(False)
MyApp = MailFrame(None,
-1, ’ ')
MyApp.Center(wx.BOTH)
MyApp.Show(False)
app.MainLoop()
#m.tapiManager.shutdown()
if name == ‘main’:
go()
#-ENDOFCODE
Thanks !
Christopher McEwan
Crummock (Scotland) Limited is a limited company registered in Scotland.
Registered company no.: 130376
Registered office: Crummock, Butlerfield Ind. Est., Bonnyrigg, Midlothian, EH19 3JQ
Crummock may monitor email traffic data and also the content of email for the purposes of security.
Scanned by MIMEDefang