I'm using wxPython, and I'm trying to make a single instance application. As far as this goes, there is no problem. My problem is passing commands to the already existing instance.
So lets say that when I double click a file that is associated with my application, it reads the file and displays, here is an example:
import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))
getfile = os.path.abspath(sys.argv[1])
print getfile
fopen = open (getfile, 'r')
fread = fopen.read()
panel = wx.Panel(self, -1)
wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
cur_thread = threading.currentThread()
# do something with the request
print "work"
# could instead of the length of the input, could return error codes, more
# information (if the request was a query), etc. Using a length function
# as a simple example
response = 'string length: %d' % len(data)
print 'responding to',data,'with',response
self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
stopped = False
allow_reuse_address = True
def serve_forever(self):
while not self.stopped:
self.handle_request()
def force_stop(self):
self.server_close()
self.stopped = True
def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
sock.send(message)
response = sock.recv(1024)
print "Received: %s" % response
sock.close()
def start_server(host, port):
server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.setDaemon(True)
server_thread.start()
return server
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'test')
frame.Show(True)
self.SetTopWindow(frame)
return True
def main():
app = MyApp(0)
app.MainLoop()
if __name__ == '__main__':
HOST, PORT = socket.gethostname(), 61955
server = None
try:
client(HOST, PORT, ' '.join(sys.argv))
sys.exit()
except socket.error:
server = start_server(HOST, PORT)
main()
This works just fine, but now I want to make it a single instance application. And I know that there are several ways to accomplish this, and in my case, I found that listening to a defined port is probably the best option. But even using such option, I have no idea on how I could pass the information of the file or, atleast, the name to the original instance and display it.
So the application should be:
Also, I didn't include any code for listening to a defined port because I really don't know much about it, so any help on this subject is also greatly appreciated.
EDIT: Code edited with "listening to a defined port", it is taken from an example. Note that print "work"
does send to the running instance, I just don't know how to make it work in my occasion (because of my plain ignorance).
This is the solution:
import wx
import sys
import os
import SocketServer
import socket
import threading
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, wx.Size(320, 350))
getfile = os.path.abspath(sys.argv[1])
print getfile
fopen = open (getfile, 'r')
fread = fopen.read()
panel = wx.Panel(self, -1)
self.static = wx.StaticText(panel, -1, fread, (45, 25), style=wx.ALIGN_CENTRE)
self.Centre()
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
cur_thread = threading.currentThread()
data = data.split()
gfile = os.path.abspath(data[-1])
fopen = open(gfile, 'r')
fread = fopen.read()
self.server.app.static.SetLabel(fread)
#Note to the self.server.app
response = 'string length: %d' % len(data)
print 'responding to',data,'with',response
self.request.send(response)
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
stopped = False
allow_reuse_address = True
def serve_forever(self):
while not self.stopped:
self.handle_request()
def force_stop(self):
self.server_close()
self.stopped = True
def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
sock.send(message)
response = sock.recv(1024)
print "Received: %s" % response
sock.close()
def start_server(host, port):
server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.setDaemon(True)
server_thread.start()
return server
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'test')
frame.Show(True)
server.app = frame
#Note the server.app
self.SetTopWindow(frame)
return True
def main():
app = MyApp(0)
app.MainLoop()
if __name__ == '__main__':
HOST, PORT = socket.gethostname(), 61955
server = None
try:
client(HOST, PORT, ' '.join(sys.argv))
sys.exit()
except socket.error:
server = start_server(HOST, PORT)
main()
Essentially I had to bind the server.app with my frame:
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'test')
frame.Show(True)
server.app = frame
#Note the server.app
So I could call later on:
data = self.request.recv(1024)
cur_thread = threading.currentThread()
data = data.split()
gfile = os.path.abspath(data[-1])
fopen = open(gfile, 'r')
fread = fopen.read()
self.server.app.static.SetLabel(fread)
The important here is the self.server.app, although what I wanted was to pass the commands to the running instance. And the data
does this for me. Let's say I open up the already open application with the file test.app then the data value will be:
\pathtoyourapplication\application.py test.app
So I grabbed its location and read, and that's pretty much it for my stupidity, hope this might be helpful for someone, in some way.