kivy

kivy戦記(13-4) ObjectProperty(None)と禁断の技

kivy
この記事は約12分で読めます。

あれから2週間が経った。

 

その間、kivyを嫌になったわけでも、ボブネミミッミ版エイサイハラマスコイおどりを踊っていたわけでもない。

延々と悩んでいたのだ。

その間、質問サイトに質問すれば、すぐに解決したかも知れない。

しかし、根本的に理解していないと、また同じようなところで、壁にぶち当たるのだ。

 

そして、遂に禁断の技を使用してしまうのである。

それは・・・・

kivyのソースを読むことである。

け、決してヒマ人じゃないですからね!

 

もともとPythonも慣れてないので、その解読作業は難航した。

app.pyからbuilder.pyに入り、さらにはkvファイル内容を内部表現に変換&チェックするperser.pyまで読んでようやくわかった。

修正前のソースが、

filelist.py


import os
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeViewLabel
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from pprint import pprint
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.resources import resource_add_path
# 日本語フォント設定
resource_add_path('./fonts')
LabelBase.register(DEFAULT_FONT, 'ipaexg.ttf')
sm = ScreenManager()
class SetSCN(Screen):
    pass
class LoadDialog(FloatLayout):
    load = ObjectProperty(None)
    cancel = ObjectProperty(None)
class AllSCN(Screen):
    tv = ObjectProperty(None)
    file_name = ObjectProperty(None)
    loadfile = ObjectProperty(None)
    text_input = ObjectProperty(None)
    def __init__(self, **kwargs):
         super(AllSCN, self).__init__(**kwargs)
         self.tv.add_node(TreeViewLabel(text ='シンカリオン E1 とき'))
         self.tv.add_node(TreeViewLabel(text ='シンカリオン 0 ひかり'))
         self.tv.add_node(TreeViewLabel(text ='シンカリオン キハ32 鉄道ホビートレイン'))
    def setupButtonClicked(self):
        sm.current = 'set'
    def show_load(self):
        content = LoadDialog(load = self.load, cancel = self.dismiss_popup)
        self._popup = Popup( title="読み込み中", content=content, size_hint=(0.9,0.9))
        self._popup.open()
    def load (self, path, filename):
        pprint(filename)
        self.file_name.text = filename[0]
        #with open (os.path.join(path, filename[0])) as stream:
        #    self.text_input.text = stream.read()
        self.dismiss_popup()
    def dismiss_popup(self):
        self._popup.dismiss()
class FilelistApp(App):
    def build(self):
        sm.add_widget(AllSCN(name='all'))
        sm.add_widget(AllSCN(name='set'))
        return AllSCN()
if __name__ == '__main__':
    FilelistApp().run()

filelist.kv


<SetSCN>:
    Label:
        text: 'おほほ'
<AllSCN>:
    BoxLayout:
        tv: tv
        file_name: file_name
        orientation: 'vertical'
        BoxLayout: #OpnSCN
            size_hint_y: 0.1
            Button:
                size_hint_x: 0.1
                text: '設定'
                on_release: root.setupButtonClicked()
            TextInput:
                id: file_name
                size_hint_x: 0.7
                text: 'ファイルパス'
            Button:
                size_hint_x: 0.1
                text: '…'
                on_release: root.show_load()
            Button:
                size_hint_x: 0.1
                text: '実行'
    BoxLayout: #ResultSCN
        size_hint_y: 0.9
        TreeView:
            id: tv
<LoadDialog>:
    BoxLayout:
        size: root.size
        pos: root.pos
        orientation: 'vertical'
        FileChooserListView:
            id: filechooser
        BoxLayout:
            size_hint_y : None
            height : 30
            Button:
                text: 'キャンセル'
                on_release: root.cancel()
            Button:
                text: '読み込み'
                on_release: root.load(filechooser.path, filechooser.selection)
AllSCN:

なのだが、perserオブジェクトを見ていて、野生の勘が働いた。

こうすればいいのだ。

filelist.kv


<SetSCN>:
    Label:
        text: 'おほほ'
<AllSCN>:
    tv: tv
    file_name: file_name

    BoxLayout: #OpnSCN
        orientation: 'vertical'
        BoxLayout:
            size_hint_y: 0.1
            Button:
                size_hint_x: 0.1
                text: '設定'
                on_release: root.setupButtonClicked()
            TextInput:
                id: file_name
                size_hint_x: 0.7
                text: 'ファイルパス'
            Button:
                size_hint_x: 0.1
                text: '…'
                on_release: root.show_load()
            Button:
                size_hint_x: 0.1
                text: '実行'
    BoxLayout: #ResultSCN
        size_hint_y: 0.9
        TreeView:
            id: tv
<LoadDialog>:
    BoxLayout:
        size: root.size
        pos: root.pos
        orientation: 'vertical'
        FileChooserListView:
            id: filechooser
        BoxLayout:
            size_hint_y : None
            height : 30
            Button:
                text: 'キャンセル'
                on_release: root.cancel()
            Button:
                text: '読み込み'
                on_release: root.load(filechooser.path, filechooser.selection)
AllSCN:

これで実行、

不完全ながら、それっぽい画面が出た。

 

どうも、ObjectProperty(None)を使って、KVファイルとPythonと値を交換するときは、
kvファイル側の値を渡すプロパティ(でいいのかな?)は、2番目のレベルに書かないといけない様だと思ったが、もとのkvファイルをよく見たら、tvのレベルが違っていたね。こりゃ。

 

この2週間は一体何だったのだろう、と思ったりしたが。

 

気を取り直して、残りデバッグ。

filelist.kv


<SetSCN>:
    Label:
        text: 'おほほ'
<AllSCN>:
    tv: tv
    file_name: file_name
    BoxLayout:
        orientation: 'vertical'

        BoxLayout: #OpnSCN
            size_hint_y: 0.1
            orientation: 'horizontal'
            BoxLayout:
                Button:
                    size_hint_x: 0.1
                    text: '設定'
                    on_release: root.setupButtonClicked()
                TextInput:
                    id: file_name
                    size_hint_x: 0.7
                    text: 'ファイルパス'
                Button:
                    size_hint_x: 0.1
                    text: '…'
                    on_release: root.show_load()
                Button:
                    size_hint_x: 0.1
                    text: '実行'
        BoxLayout: #ResultSCN
            size_hint_y: 0.9
            TreeView:
                id: tv
<LoadDialog>:
    BoxLayout:
        size: root.size
        pos: root.pos
        orientation: 'vertical'
        FileChooserListView:
            id: filechooser
        BoxLayout:
            size_hint_y : None
            height : 30
            Button:
                text: 'キャンセル'
                on_release: root.cancel()
            Button:
                text: '読み込み'
                on_release: root.load(filechooser.path, filechooser.selection)
AllSCN:

これで、

 

そして、「設定」ボタンを押して、

 

と言うわけで、ようやくここまで戻った。

 

 

kivyをやる人って、ひょっとして私がやったように、kivy内部まで読み込んでいるのだろうか?

本来なら、kivy内部を読み込むのは、kivyのバージョンアップでどうなってしまうのかわからないので、ドキュメントだけにとどめた方がいいと思うのだが、Pythonの文化的(さらにはオープンソースの文化的)には、システムの内部まで読み込んだ方がいいのだろうか?

 

今回はケアレスミスの様だが、次に未知なるトラブルが起きた場合、最終的には再びkivy内部を読まなければいけないのだろうか?

ソースをいろいろいじりたいという誘惑が出てきて、バージョン管理が大変なことになりそうだが。

 

タイトルとURLをコピーしました