では、いよいよjson読み込みから、一通り動くか確認してみる。
json読み込みロジックを書いてみよう。
filelist.py(余計なロジックやimportは、外しています。)
import os
import sys
import json
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeViewLabel
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
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()
path_inf = 'path_inf.json'
class MsgboxOk(BoxLayout):
message_text = StringProperty()
ok_button = ObjectProperty(None)
class MsgboxOkCancel(BoxLayout):
message_text = StringProperty()
ok_button = ObjectProperty(None)
cancel_button = ObjectProperty(None)
class SetSCN(Screen):
begin_path_dsp = ObjectProperty(None)
def __init__(self, **kwargs):
super(SetSCN, self).__init__(**kwargs)
def setSelect(self):
self._popup = LstPOP( load = self.setSelectLoad, \
cancel = self.setSelectCancel)
self._popup.open()
def setSelectLoad (self, path, filename):
self.begin_path_dsp.text = path
self._popup.dismiss()
def setSelectCancel(self):
self._popup.dismiss()
def msgTestOk(self):
pprint ('OKが押されました')
self.popup.dismiss()
def msgTestCancel(self):
pprint ('CANCELが押されました')
self.popup.dismiss()
def selfOk(self):
self.bl = {}
self.bl['begin_path'] = self.begin_path_dsp.text
pprint (self.bl)
try:
#raise OverflowError('やっちまったな')
with open(path_inf, 'w') as fd:
json.dump(self.bl, fd)
except PermissionError as err:
self.msg = '保存データを書き込もうとしましたが、書き込み許可がありません。\n'
self.msg += 'パスは、' + self.bl['begin_path'] + 'です。\n'
self.msg += '保存先の書き込み許可を確認するか、パスが適当かを確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='書き込み許可エラー', content=content)
self.popup.open()
except IOError as err:
self.msg = '保存データを書き込もうとしましたが、書き込めません。\n'
self.msg += '書き込み先機器に問題があるようです。\n'
self.msg += '書き込み先機器の状態を確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='I/Oエラー', content=content)
self.popup.open()
except BaseException as err:
self.msg = '保存データを書き込もうとしましたが、何らかのエラーが起きました。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='その他のエラー', content=content)
self.popup.open()
finally:
sm.current = 'all'
def selfCancel(self):
sm.current = 'all'
class LstPOP(Popup):
current_dir = os.path.dirname(os.path.abspath(__file__))
load = ObjectProperty(None)
cancel = ObjectProperty(None)
def __init__(self, **kwargs):
super(LstPOP, self).__init__(**kwargs)
self.title ='読み込み中 ' + os.path.dirname(os.path.abspath(__file__))
def is_dir(self, dirname, filename):
# ディスレクトリならTrueを返す
return os.path.isdir(os.path.join(dirname, filename))
def lstChooser(self, path, selection):
if 0 < len(selection):
self.title = '読み込み中 ' + selection[0]
class AllSCN(Screen):
tv = ObjectProperty(None)
file_name = ObjectProperty(None)
loadfile = ObjectProperty(None)
text_input = ObjectProperty(None)
def msgOsErrorOk(self):
print('OKが押されました')
self.popup.dismiss()
sys.exit()
def begin_display(self, dt):
#
# SetSCNの最初期内容
#
path = ''
thisos = os.name
if thisos == 'posix':
path = os.environ.get('HOME')
elif thisos == 'nt':
path = os.environ.get('HOMEDRIVE') + os.environ.get('HOMEPATH')
else:
msg = '内部OS判定(os.name)が、"' + thisos + '”でした。\n'
msg += 'サポートしているOSは、UNIX系統と、Windowsです。\n'
msg += 'したがってこのOSはサポート外です。すみません。'
content = MsgboxOk \
(ok_button= self.msgOsErrorOk, \
message_text= msg)
self.popup = Popup(title='OSサポートエラー', content=content)
self.popup.open()
return
self.manager.get_screen('set').begin_path_dsp.text = path
#
# AllSCNのtree処理
#
self.tv.add_node(TreeViewLabel(text ='シンカリオン E1 とき'))
self.tv.add_node(TreeViewLabel(text ='シンカリオン 0 ひかり'))
self.tv.add_node(TreeViewLabel(text ='シンカリオン キハ32 鉄道ホビートレイン'))
def setupButtonClicked(self):
#
# SetSCNへの画面遷移時の内容
#
try:
#raise OverflowError('やっちまったな')
with open(path_inf, 'r') as fd:
path_json = json.load(fd)
self.manager.get_screen('set').begin_path_dsp.text = path_json['begin_path']
except PermissionError as err:
self.msg = '保存データを読み込もうとしましたが、読み込み許可がありません。\n'
self.msg += 'パスは、' + self.bl['begin_path'] + 'です。\n'
self.msg += '保存先の読み込み許可を確認するか、パスが適当かを確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='読み込み許可エラー', content=content)
self.popup.open()
except IOError as err:
self.msg = '保存データを読み込もうとしましたが、読み込めません。\n'
self.msg += '読み込み先機器に問題があるようです。\n'
self.msg += '読み込み先機器の状態を確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='I/Oエラー', content=content)
self.popup.open()
except BaseException as err:
self.msg = '保存データを読み込もうとしましたが、何らかのエラーが起きました。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='その他のエラー', content=content)
self.popup.open()
else:
sm.current = 'set'
def show_load(self):
self._popup = LstPOP( load = self.load, \
cancel = self.dismiss_popup)
self._popup.open()
def load (self, path, filename):
pprint(filename)
#self.file_name.text = filename[0]
self.file_name.text = path
#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()
def msgTestOk(self):
pprint ('OKが押されました')
self.popup.dismiss()
def msgTestCancel(self):
pprint ('CANCELが押されました')
self.popup.dismiss()
class FilelistApp(App):
def build(self):
allscn = AllSCN()
setscn = SetSCN()
Clock.schedule_once(allscn.begin_display, 0)
sm.add_widget(allscn)
sm.add_widget(setscn)
return sm
if __name__ == '__main__':
FilelistApp().run()
filelist.kvは、変更なし。
SetSCNの初期処理を、AllSCN側に入れなければならないのは釈然としないが、ScreenManagerを使用しているときは、どちらも同じ画面になっているという思想である。
これしかしようがないが、なんだか釈然としない。
で、動かしてみよう。(path_inf.jsonは、あらかじめ変更しています)
「設定」押下で、
「(なんたら)/左巻きなると」というのは、もともとpath_inf.jsonの値で実在するパス。
で、「・・・」押下で、このパスに行けばいいのだが、、、、
ああ、苦労してパス表示をつくって良かった、、、、、は、いいとして、左巻きなるとのパスに移ってない。
これは困った、対処しなければ。
そんなわけで、対処しました。
filelist.py
import os
import sys
import json
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.treeview import TreeViewLabel
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
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()
path_inf = 'path_inf.json'
class MsgboxOk(BoxLayout):
message_text = StringProperty()
ok_button = ObjectProperty(None)
class MsgboxOkCancel(BoxLayout):
message_text = StringProperty()
ok_button = ObjectProperty(None)
cancel_button = ObjectProperty(None)
class SetSCN(Screen):
begin_path_dsp = ObjectProperty(None)
def __init__(self, **kwargs):
super(SetSCN, self).__init__(**kwargs)
def setSelect(self):
self._popup = LstPOP( load = self.setSelectLoad, \
cancel = self.setSelectCancel , \
start_path = self.begin_path_dsp.text)
self._popup.open()
def setSelectLoad (self, path, filename):
self.begin_path_dsp.text = path
self._popup.dismiss()
def setSelectCancel(self):
self._popup.dismiss()
def msgTestOk(self):
pprint ('OKが押されました')
self.popup.dismiss()
def msgTestCancel(self):
pprint ('CANCELが押されました')
self.popup.dismiss()
def selfOk(self):
self.bl = {}
self.bl['begin_path'] = self.begin_path_dsp.text
pprint (self.bl)
try:
#raise OverflowError('やっちまったな')
with open(path_inf, 'w') as fd:
json.dump(self.bl, fd)
except PermissionError as err:
self.msg = '保存データを書き込もうとしましたが、書き込み許可がありません。\n'
self.msg += 'パスは、' + self.bl['begin_path'] + 'です。\n'
self.msg += '保存先の書き込み許可を確認するか、パスが適当かを確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='書き込み許可エラー', content=content)
self.popup.open()
except IOError as err:
self.msg = '保存データを書き込もうとしましたが、書き込めません。\n'
self.msg += '書き込み先機器に問題があるようです。\n'
self.msg += '書き込み先機器の状態を確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='I/Oエラー', content=content)
self.popup.open()
except BaseException as err:
self.msg = '保存データを書き込もうとしましたが、何らかのエラーが起きました。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='その他のエラー', content=content)
self.popup.open()
finally:
sm.current = 'all'
def selfCancel(self):
sm.current = 'all'
class LstPOP(Popup):
#current_dir = os.path.dirname(os.path.abspath(__file__))
load = ObjectProperty(None)
cancel = ObjectProperty(None)
start_path = ObjectProperty(None)
def __init__(self, **kwargs):
super(LstPOP, self).__init__(**kwargs)
self.title ='読み込み中 ' + self.start_path
def is_dir(self, dirname, filename):
# ディスレクトリならTrueを返す
return os.path.isdir(os.path.join(dirname, filename))
def lstChooser(self, path, selection):
if 0 < len(selection):
self.title = '読み込み中 ' + selection[0]
class AllSCN(Screen):
tv = ObjectProperty(None)
file_name = ObjectProperty(None)
loadfile = ObjectProperty(None)
text_input = ObjectProperty(None)
def msgOsErrorOk(self):
print('OKが押されました')
self.popup.dismiss()
sys.exit()
def begin_display(self, dt):
#
# SetSCNの最初期内容
#
path = ''
thisos = os.name
if thisos == 'posix':
path = os.environ.get('HOME')
elif thisos == 'nt':
path = os.environ.get('HOMEDRIVE') + os.environ.get('HOMEPATH')
else:
msg = '内部OS判定(os.name)が、"' + thisos + '”でした。\n'
msg += 'サポートしているOSは、UNIX系統と、Windowsです。\n'
msg += 'したがってこのOSはサポート外です。すみません。'
content = MsgboxOk \
(ok_button= self.msgOsErrorOk, \
message_text= msg)
self.popup = Popup(title='OSサポートエラー', content=content)
self.popup.open()
return
self.manager.get_screen('set').begin_path_dsp.text = path
#
# AllSCNのtree処理
#
self.tv.add_node(TreeViewLabel(text ='シンカリオン E1 とき'))
self.tv.add_node(TreeViewLabel(text ='シンカリオン 0 ひかり'))
self.tv.add_node(TreeViewLabel(text ='シンカリオン キハ32 鉄道ホビートレイン'))
def setupButtonClicked(self):
#
# SetSCNへの画面遷移時の内容
#
try:
#raise OverflowError('やっちまったな')
with open(path_inf, 'r') as fd:
path_json = json.load(fd)
self.manager.get_screen('set').begin_path_dsp.text = path_json['begin_path']
except PermissionError as err:
self.msg = '保存データを読み込もうとしましたが、読み込み許可がありません。\n'
self.msg += 'パスは、' + self.bl['begin_path'] + 'です。\n'
self.msg += '保存先の読み込み許可を確認するか、パスが適当かを確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='読み込み許可エラー', content=content)
self.popup.open()
except IOError as err:
self.msg = '保存データを読み込もうとしましたが、読み込めません。\n'
self.msg += '読み込み先機器に問題があるようです。\n'
self.msg += '読み込み先機器の状態を確認してください。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='I/Oエラー', content=content)
self.popup.open()
except BaseException as err:
self.msg = '保存データを読み込もうとしましたが、何らかのエラーが起きました。\n\n'
self.msg += str(err)
content = MsgboxOk \
(ok_button= self.msgTestOk, \
message_text= self.msg)
self.popup = Popup(title='その他のエラー', content=content)
self.popup.open()
else:
sm.current = 'set'
def show_load(self):
# 暫定ロジックです
self._popup = LstPOP( load = self.load, \
cancel = self.dismiss_popup, \
start_path='あああ')
self._popup.open()
def load (self, path, filename):
pprint(filename)
#self.file_name.text = filename[0]
self.file_name.text = path
#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()
def msgTestOk(self):
pprint ('OKが押されました')
self.popup.dismiss()
def msgTestCancel(self):
pprint ('CANCELが押されました')
self.popup.dismiss()
class FilelistApp(App):
def build(self):
allscn = AllSCN()
setscn = SetSCN()
Clock.schedule_once(allscn.begin_display, 0)
sm.add_widget(allscn)
sm.add_widget(setscn)
return sm
if __name__ == '__main__':
FilelistApp().run()
filelist.kv
<SetSCN>:
name: 'set'
begin_path_dsp: begin_path_dsp
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 0.1
orientation: 'horizontal'
BoxLayout:
Label:
size_hint_x: 0.1
text: '開始パス'
TextInput:
id: begin_path_dsp
size_hint_x: 0.8
Button:
size_hint_x: 0.1
text: '…'
on_release: root.setSelect()
BoxLayout:
size_hint_y: 0.8
BoxLayout:
size_hint_y: 0.1
Button:
size_hint_x: 0.5
text: 'OK'
on_release: root.selfOk()
Button:
size_hint_x: 0.5
text: 'キャンセル'
on_release: root.selfCancel()
<AllSCN>:
name: 'all'
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
<MsgboxOk>
orientation: 'vertical'
Label:
size_hint_y: 0.9
text: root.message_text
BoxLayout:
size_hint_y: 0.1
orientation: 'horizontal'
Button:
size_hint_x: 10
text: 'OK'
on_release: root.ok_button()
<MsgboxOkCancel>
orientation: 'vertical'
Label:
size_hint_y: 0.9
text: root.message_text
BoxLayout:
size_hint_y: 0.1
orientation: 'horizontal'
Button:
size_hint_x: 10
text: 'OK'
on_release: root.ok_button()
Button:
size_hint_x: 10
text: 'キャンセル'
on_release: root.cancel_button()
<LstPOP>:
id:lst_pop
size_hint: 0.9, 0.9
#title: '読み込み中 ' + root.start_path
BoxLayout:
size: root.size
pos: root.pos
orientation: 'vertical'
FileChooserListView:
id: filechooser
dirselect: True
path: root.start_path
filters: [root.is_dir]
on_touch_down: lst_pop.lstChooser(filechooser.path, filechooser.selection)
BoxLayout:
size_hint_y : None
height : 30
Button:
text: 'キャンセル'
on_release: root.cancel()
Button:
text: '読み込み'
on_release: root.load(filechooser.path, filechooser.selection)
AllSCN:
まず、クラスLstPOPに、外部からパス設定できるように、start_pathを新設。
初期表示で表示できるようにする。
filelist.py
class LstPOP(Popup):
#current_dir = os.path.dirname(os.path.abspath(__file__))
load = ObjectProperty(None)
cancel = ObjectProperty(None)
start_path = ObjectProperty(None)
def __init__(self, **kwargs):
super(LstPOP, self).__init__(**kwargs)
self.title ='読み込み中 ' + self.start_path
def is_dir(self, dirname, filename):
# ディスレクトリならTrueを返す
return os.path.isdir(os.path.join(dirname, filename))
def lstChooser(self, path, selection):
if 0 < len(selection):
self.title = '読み込み中 ' + selection[0]
filelist.kv側の<LstPOP>
のFileChooserListView:
のpath指定はroot.start_path
に変更。
<LstPOP>:
id:lst_pop
size_hint: 0.9, 0.9
#title: '読み込み中 ' + root.start_path
BoxLayout:
size: root.size
pos: root.pos
orientation: 'vertical'
FileChooserListView:
id: filechooser
dirselect: True
path: root.start_path
filters: [root.is_dir]
on_touch_down: lst_pop.lstChooser(filechooser.path, filechooser.selection)
呼び出し側では、そのstart_path
に初期パスのtextフィールドを設定する。
filelist.py
class SetSCN(Screen):
begin_path_dsp = ObjectProperty(None)
def __init__(self, **kwargs):
super(SetSCN, self).__init__(**kwargs)
def setSelect(self):
self._popup = LstPOP( load = self.setSelectLoad, \
cancel = self.setSelectCancel , \
start_path = self.begin_path_dsp.text)
self._popup.open()
では実行。その前に、最初期の操作という設定で、jsonファイルpath_inf.jsonを消しておく。
では実行。
ああ、やっちまった、、、、
では修正。
「設定」ボタンを押されたときに、jsonファイルが読み込まれるが、ここにファイルがないときの処理を新設する。
そしてファイルがないときには、AllSCN()のbegin_display()で求めた、jsonファイルがないときのOS別の初期値をSetSCNのパスとして表示させるのだ。
そのため、AllSCN()のbegin_display()で使っている変数pathは、self.init_pathに変更し、この下にあるSetSCNのパス表示の初期設定を廃止するのだ。
filelist.py
(省略ですわよ)
class AllSCN(Screen):
tv = ObjectProperty(None)
file_name = ObjectProperty(None)
loadfile = ObjectProperty(None)
text_input = ObjectProperty(None)
def msgOsErrorOk(self):
print('OKが押されました')
self.popup.dismiss()
sys.exit()
def begin_display(self, dt):
#
# SetSCNの最初期内容
#
self.init_path = ''
thisos = os.name
if thisos == 'posix':
self.init_path = os.environ.get('HOME')
elif thisos == 'nt':
self.init_path = os.environ.get('HOMEDRIVE') + os.environ.get('HOMEPATH')
else:
msg = '内部OS判定(os.name)が、"' + thisos + '”でした。\n'
msg += 'サポートしているOSは、UNIX系統と、Windowsです。\n'
msg += 'したがってこのOSはサポート外です。すみません。'
content = MsgboxOk \
(ok_button= self.msgOsErrorOk, \
message_text= msg)
self.popup = Popup(title='OSサポートエラー', content=content)
self.popup.open()
return
#self.manager.get_screen('set').begin_path_dsp.text = self.init_path
(省略ですってよ)
def setupButtonClicked(self):
#
# SetSCNへの画面遷移時の内容
#
try:
#raise OverflowError('やっちまったな')
with open(path_inf, 'r') as fd:
path_json = json.load(fd)
self.manager.get_screen('set').begin_path_dsp.text = path_json['begin_path']
except FileNotFoundError as err:
self.manager.get_screen('set').begin_path_dsp.text = self.init_path
sm.current = 'set'
(以下省略しますわよ)
これで実行しよう。起動したら「設定」ボタンで、、、
「左巻きなると」ディレクトリに移動。
「左巻きなると」パスが表示された。
これで、「読み込み」。
「OK」の後に、このfilelistを一旦終了。
変更したパスが、再度表示される。
これで初期表示画面ができた。
と、言いたいところだが、一つ罠があった。
それは、「開始パス」フィールドを手入力可能にしていたことだった。
変な値を入れると、変に動く。
どうしたらいいんだっ!
(続く)