Flexxはpythonで書くので裏にブラウザがいるのを忘れてしまう。Flexxはpythonをjavascriptに変換してブラウザ上でGUIを実現してる。なのでjavascriptに存在しないライブラリは動かない。numpyなどのpython特有のモノを使うとエラー出してしまう。そこを何とかする方法を書いてみます。
display
という関数を使うGUIを書いてみます。これは文字の大きさを返す関数です。
from flexx import flx
def display(s):
return str(len(s)) + " Chars"
class View(flx.Widget):
def init(self):
self.e1 = flx.LineEdit(text='flexx')
self.b1 = flx.Button(text='文字数カウント')
self.t1 = flx.Label(text="", style='border:1px solid red')
def setLabelText(self, s):
self.t1.set_text(s)
@flx.reaction('b1.pointer_click')
def _foo(self):
self.setLabelText(display(self.e1.text))
if __name__ == '__main__':
m = flx.launch(View)
flx.run()
次にdisplay
をnumpyを使って無理やり書いてみます。
from flexx import flx
import numpy
def display(s):
return "{0} Chars".format(numpy.array((len(s),))[0])
class View(flx.Widget):
def init(self):
self.e1 = flx.LineEdit(text='flexx')
self.b1 = flx.Button(text='文字数カウント')
self.t1 = flx.Label(text="", style='border:1px solid red')
def setLabelText(self, s):
self.t1.set_text(s)
@flx.reaction('b1.pointer_click')
def _foo(self):
self.setLabelText(display(self.e1.text))
if __name__ == '__main__':
m = flx.launch(View)
flx.run()
これだと
ValueError: JS in "example_2nd.py" uses 'numpy.array' but cannot convert <class 'builtin_function_or_method'> to JS.
というエラーを出して止まってしまいます。どうやらnumpyがjavascriptに変換できないようです。で、どうするかですが、flx.PyComponentを使えば良さそうです。emit
を使ってイベントのキューを作るみたい。それをflx.PyComponentの方でイベントとして受け取って処理する手順のようです。この仕組みでeelやpywebviewでは必要な非同期処理のコード記述をしなくても良いのじゃないかと思っています。
from flexx import flx
import numpy
def display(s):
return "{0} Chars".format(numpy.array((len(s),))[0])
class View(flx.Widget):
def init(self):
self.e1 = flx.LineEdit(text='flexx')
self.b1 = flx.Button(text='文字数カウント')
self.t1 = flx.Label(text="", style='border:1px solid red')
@flx.action
def setLabelText(self, s):
self.t1.set_text(s)
@flx.reaction('b1.pointer_click')
def _foo(self):
self.emit('foo', {"text":self.e1.text})
class App(flx.PyComponent):
def init(self):
self.widget = View()
@flx.reaction('!widget.foo')
def _foo(self, *events):
for ev in events:
text = ev["text"]
self.widget.setLabelText(display(text))
if __name__ == '__main__':
m = flx.launch(App)
flx.run()
これで動くようになりました。self.emit('foo', {"text":self.e1.text})
ここで使うfoo
とかtext
とかは任意に決められます。
App
クラスにある @flx.reaction('!widget.foo')
で受け取るtype
を選ぶようです。ちなみにev
には
Dict(text='flexx', type='foo', source=<JsComponent 'View_2' at 0x1896ff950c8>)
が入っていました。
追記
self.emit
の部分が@flx.emitter
で書き直せました。なので@flx.reaction('widget.foo')
のwidget.foo
部分に納得がいきます。self.emit
を使う場合は!
を省くとwarningが出ますが@flx.emitter
を使う場合はwarningが出ません。
from flexx import flx
import numpy
def display(s):
return "{0} Chars".format(numpy.array((len(s),))[0])
class View(flx.Widget):
def init(self):
self.e1 = flx.LineEdit(text='flexx')
self.b1 = flx.Button(text='文字数カウント')
self.t1 = flx.Label(text="", style='border:1px solid red')
@flx.action
def setLabelText(self, s):
self.t1.set_text(s)
@flx.emitter
def foo(self):
return {"text":self.e1.text}
@flx.reaction('b1.pointer_click')
def _foo(self):
self.foo()
class App(flx.PyComponent):
def init(self):
self.widget = View()
@flx.reaction('widget.foo')
def _foo(self, *events):
for ev in events:
print(ev)
text = ev["text"]
self.widget.setLabelText(display(text))
if __name__ == '__main__':
m = flx.launch(App)
flx.run()
ここだけ理解していれば、後はドキュメントを見ながら何とかなると思います。
Flexxのドキュメントは