[英]wxPython and Autobahn websockets
Im trying to create GUI app for my test project, based on Python/Twisted/Autobahn.ws. 我试图基于Python / Twisted / Autobahn.ws为测试项目创建GUI应用。 Im following article as like there: wxPython and Twisted and try to connect my application to the server. 我在下面的文章中像这样: wxPython和Twisted并尝试将我的应用程序连接到服务器。 But at the start i'll get an error: 但是一开始我会得到一个错误:
Unhandled Error
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 88, in callWithLogger
return callWithContext({"system": lp}, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/log.py", line 73, in callWithContext
return context.call({ILogContext: newCtx}, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 118, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/usr/local/lib/python2.7/dist-packages/twisted/python/context.py", line 81, in callWithContext
return func(*args,**kw)
--- <exception caught here> ---
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/_threadedselect.py", line 283, in _doReadOrWrite
why = getattr(selectable, method)()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 593, in doConnect
self._connectDone()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/tcp.py", line 607, in _connectDone
self.protocol = self.connector.buildProtocol(self.getPeer())
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1071, in buildProtocol
return self.factory.buildProtocol(addr)
File "/usr/local/lib/python2.7/dist-packages/twisted/protocols/policies.py", line 171, in buildProtocol
return self.protocol(self, self.wrappedFactory.buildProtocol(addr))
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/protocol.py", line 123, in buildProtocol
p = self.protocol()
exceptions.AttributeError: GUIClientProtocol instance has no __call__ method
How i can fix this issue? 我该如何解决此问题? Need to define call method in my class or maybe i have better solution for this? 需要在我的课堂上定义调用方法,还是我对此有更好的解决方案?
Code: 1) client_gui: 代码:1)client_gui:
import wx
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor, ssl
from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS
from gui.filemanager import CloudStorage
class GUIClientProtocol(WebSocketClientProtocol):
def __init__(self, gui):
self.gui = gui
if __name__ == '__main__':
app = wx.App(False)
frame = CloudStorage(None, -1, 'CloudStorage')
frame.Show()
host_url = "wss://%s:%s" % ("localhost", 9000)
# create a WS server factory with our protocol
factory = WebSocketClientFactory(host_url, debug = False)
factory.protocol = GUIClientProtocol(frame)
# SSL client context: using default
if factory.isSecure:
contextFactory = ssl.ClientContextFactory()
else:
contextFactory = None
reactor.registerWxApp(app)
connectWS(factory, contextFactory)
reactor.run()
2) server.py 2)server.py
import sys
import datetime
import pickle
from json import dumps, loads
from hashlib import sha256
from time import gmtime, strftime
from subprocess import Popen, PIPE, STDOUT
import sqlalchemy
import sqlalchemy.exc
from sqlalchemy import and_, func, asc
from sqlalchemy.orm import sessionmaker
from twisted.internet import reactor, ssl
from twisted.internet.task import deferLater
from twisted.python import log, logfile
from twisted.web.server import Site
from twisted.web.wsgi import WSGIResource
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol, listenWS
from balancer.balancer import Balancer
from db.tables import File as FileTable
from db.tables import Users, FileServer, FileSpace, Catalog
from flask_app import app
from utils import commands
log_file = logfile.LogFile("service.log", ".")
log.startLogging(log_file)
engine = sqlalchemy.create_engine('postgresql://user:password@localhost/csan', pool_size=20, max_overflow=0)
def checkServerStatus(ip, port):
p = Popen(["python", "statuschecker.py", str(ip), str(port)], stdout=PIPE, stdin=PIPE, stderr=STDOUT)
result = p.communicate()[0].replace('\n', '')
return result.split('|')
class DFSServerProtocol(WebSocketServerProtocol):
... # ~450 lines of code
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'debug':
log.startLogging(sys.stdout)
debug = True
port = int(sys.argv[2])
else:
debug = False
port = int(sys.argv[1])
contextFactory = ssl.DefaultOpenSSLContextFactory('web/keys/server.key', 'web/keys/server.crt')
server_addr = "wss://localhost:%d" % (port)
factory = WebSocketServerFactory(server_addr, debug = debug, debugCodePaths = debug)
factory.protocol = DFSServerProtocol
factory.setProtocolOptions(allowHixie76 = True)
listenWS(factory, contextFactory)
# Flask with SSL under Twisted
resource = WSGIResource(reactor, reactor.getThreadPool(), app)
site = Site(resource)
reactor.listenSSL(8080, site, contextFactory)
# reactor.listenTCP(8080, web)
reactor.run()
Update #1: client_gui.py looks like that: 更新#1:client_gui.py看起来像这样:
import wx
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor, ssl
from autobahn.twisted.websocket import WebSocketClientFactory, WebSocketClientProtocol, connectWS
from gui.filemanager import CloudStorage
class GUIClientProtocol(WebSocketClientProtocol):
def __init__(self):
WebSocketClientProtocol.__init__(self)
self.gui = None
def connectionMade(self):
self.gui = self.factory._frame
self.gui.Show()
if __name__ == '__main__':
app = wx.App(False)
frame = CloudStorage(None, -1, 'CloudStorage')
# create a WS server factory with our protocol
host_url = "wss://%s:%s" % ("localhost", 9000)
factory = WebSocketClientFactory(host_url)
factory.protocol = GUIClientProtocol
factory._frame = frame
# SSL client context: using default
if factory.isSecure:
contextFactory = ssl.ClientContextFactory()
else:
contextFactory = None
reactor.registerWxApp(app)
connectWS(factory, contextFactory)
reactor.run()
Update #2: 更新#2:
code of my CloudStorage class: 我的CloudStorage类的代码:
import wx
import os
import time
ID_BUTTON=100
ID_EXIT=200
ID_SPLITTER=300
class MyListCtrl(wx.ListCtrl):
def __init__(self, parent, id):
wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT)
files = os.listdir('.')
images = ['images/empty.png', 'images/folder.png', 'images/source_py.png',
'images/image.png', 'images/pdf.png', 'images/up16.png']
self.InsertColumn(0, 'Name')
self.InsertColumn(1, 'Ext')
self.InsertColumn(2, 'Size', wx.LIST_FORMAT_RIGHT)
self.InsertColumn(3, 'Modified')
self.SetColumnWidth(0, 220)
self.SetColumnWidth(1, 70)
self.SetColumnWidth(2, 100)
self.SetColumnWidth(3, 420)
self.il = wx.ImageList(16, 16)
for i in images:
self.il.Add(wx.Bitmap(i))
self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
j = 1
self.InsertStringItem(0, '..')
self.SetItemImage(0, 5)
for i in files:
(name, ext) = os.path.splitext(i)
ex = ext[1:]
size = os.path.getsize(i)
sec = os.path.getmtime(i)
self.InsertStringItem(j, name)
self.SetStringItem(j, 1, ex)
self.SetStringItem(j, 2, str(size) + ' B')
self.SetStringItem(j, 3, time.strftime('%Y-%m-%d %H:%M',
time.localtime(sec)))
# if os.path.isdir(i):
# self.SetItemImage(j, 1)
# elif ex == 'py':
# self.SetItemImage(j, 2)
# elif ex == 'jpg':
# self.SetItemImage(j, 3)
# elif ex == 'pdf':
# self.SetItemImage(j, 4)
# else:
# self.SetItemImage(j, 0)
if (j % 2) == 0:
self.SetItemBackgroundColour(j, '#e6f1f5')
j = j + 1
class CloudStorage(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, -1, title)
self.splitter = wx.SplitterWindow(self, ID_SPLITTER, style=wx.SP_BORDER)
self.splitter.SetMinimumPaneSize(50)
p1 = MyListCtrl(self.splitter, -1)
p2 = MyListCtrl(self.splitter, -1)
self.splitter.SplitVertically(p1, p2)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.Bind(wx.EVT_SPLITTER_DCLICK, self.OnDoubleClick, id=ID_SPLITTER)
filemenu= wx.Menu()
filemenu.Append(ID_EXIT,"E&xit"," Terminate the program")
editmenu = wx.Menu()
netmenu = wx.Menu()
showmenu = wx.Menu()
configmenu = wx.Menu()
helpmenu = wx.Menu()
menuBar = wx.MenuBar()
menuBar.Append(filemenu,"&File")
menuBar.Append(editmenu, "&Edit")
menuBar.Append(netmenu, "&Net")
menuBar.Append(showmenu, "&Show")
menuBar.Append(configmenu, "&Config")
menuBar.Append(helpmenu, "&Help")
self.SetMenuBar(menuBar)
self.Bind(wx.EVT_MENU, self.OnExit, id=ID_EXIT)
tb = self.CreateToolBar( wx.TB_HORIZONTAL | wx.NO_BORDER |
wx.TB_FLAT | wx.TB_TEXT)
# tb.AddSimpleTool(10, wx.Bitmap('images/previous.png'), 'Previous')
# tb.AddSimpleTool(20, wx.Bitmap('images/up.png'), 'Up one directory')
# tb.AddSimpleTool(30, wx.Bitmap('images/home.png'), 'Home')
# tb.AddSimpleTool(40, wx.Bitmap('images/refresh.png'), 'Refresh')
# tb.AddSeparator()
# tb.AddSimpleTool(50, wx.Bitmap('images/write.png'), 'Editor')
# tb.AddSimpleTool(60, wx.Bitmap('images/terminal.png'), 'Terminal')
# tb.AddSeparator()
# tb.AddSimpleTool(70, wx.Bitmap('images/help.png'), 'Help')
tb.Realize()
self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
button1 = wx.Button(self, ID_BUTTON + 1, "F3 View")
button2 = wx.Button(self, ID_BUTTON + 2, "F4 Edit")
button3 = wx.Button(self, ID_BUTTON + 3, "F5 Copy")
button4 = wx.Button(self, ID_BUTTON + 4, "F6 Move")
button5 = wx.Button(self, ID_BUTTON + 5, "F7 Mkdir")
button6 = wx.Button(self, ID_BUTTON + 6, "F8 Delete")
button7 = wx.Button(self, ID_BUTTON + 7, "F9 Rename")
button8 = wx.Button(self, ID_EXIT, "F10 Quit")
self.sizer2.Add(button1, 1, wx.EXPAND)
self.sizer2.Add(button2, 1, wx.EXPAND)
self.sizer2.Add(button3, 1, wx.EXPAND)
self.sizer2.Add(button4, 1, wx.EXPAND)
self.sizer2.Add(button5, 1, wx.EXPAND)
self.sizer2.Add(button6, 1, wx.EXPAND)
self.sizer2.Add(button7, 1, wx.EXPAND)
self.sizer2.Add(button8, 1, wx.EXPAND)
self.Bind(wx.EVT_BUTTON, self.OnExit, id=ID_EXIT)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.splitter,1,wx.EXPAND)
self.sizer.Add(self.sizer2,0,wx.EXPAND)
self.SetSizer(self.sizer)
size = wx.DisplaySize()
self.SetSize(size)
self.sb = self.CreateStatusBar()
self.sb.SetStatusText(os.getcwd())
self.Center()
self.Show(True)
def OnExit(self,e):
self.Close(True)
def OnSize(self, event):
size = self.GetSize()
self.splitter.SetSashPosition(size.x / 2)
self.sb.SetStatusText(os.getcwd())
event.Skip()
def OnDoubleClick(self, event):
size = self.GetSize()
self.splitter.SetSashPosition(size.x / 2)
if __name__ == '__main__':
app = wx.App(0)
CloudStorage(None, -1, 'CloudStorage')
app.MainLoop()
Update: I have created a complete example of using wxPython with Autobahn to create WebSocket enabled UIs. 更新:我已经创建了使用wxPython和Autobahn创建启用WebSocket的UI的完整示例 。
The problem is the line 问题是线
factory.protocol = GUIClientProtocol(frame)
This sets factory.protocol
to an instance of GUIClientProtocol
. 这GUIClientProtocol
factory.protocol
设置为GUIClientProtocol
的实例 。 But it needs to be the class. 但这必须是课程。
Now, you apparently want to have frame
accessible from within GUIClientProtocol
. 现在,您显然想从GUIClientProtocol
访问frame
。 There are (at least) two options. 有(至少)两个选项。
Option 1: 选项1:
factory.protocol = GUIClientProtocol
factory._frame = frame
and then access as self.factory._frame
from the (running) protocol instance. 然后从(正在运行的)协议实例中以self.factory._frame
进行访问。
Option 2: Implement Factory.buildProtocol
. 选项2:实现Factory.buildProtocol
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.