kivy

kivy戦記(18-1) Windowsでの確認でドライブレターの問題が出る

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

いよいよメインのAllSCNのボタンに処理を割り付けることにする。

 

ここの仕様が曖昧だったので、こう決めておいた。

  • パス表示部分は、この内容を起点にして、下記のtree(現在は仮にシンカリオン云々となっている)で、ファイルの内容を表示させる。これを起点パスとする。
  • filelist起動時の起点パス表示部分は、jsonであらかじめ保存しておいた内容を表示させる。ないときは、環境設定から求める(すでにあります)
  • 起点パスは、次のようにして変更することが出来る。
    • 「・・・」ボタンは、変更したら、表示を変更させるだけにする。
    • 直接入力は、表示を変更させるだけにする。
  • 「実行」ボタンが押されたときに、内容チェックを行ってから、tree表示を行う(まだ実装しません)。
    • 内容に異常があったときは、エラーメッセージを出してから、起点パスを前の値に戻す。

 

こうして、ソースを下記のように変更した。

 

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 PathRead:
    def __init__(self, **kwargs):
        self.path_json = None
        self.notfound = False
        self.err = False
        try:
            #raise BaseException('やっちまったな')
            with open(path_inf, 'r') as fd:
                self.path_json = json.load(fd)
        except FileNotFoundError:
            self.notfound = True
        except PermissionError as err:
            self.msg = '保存データを読み込もうとしましたが、読み込み許可がありません。\n'
            self.msg += '読みこもうとしたパス・ファイルは、' + path_inf + 'です。\n'
            self.msg += '保存データの読み込み許可を確認するか、パス・ファイルが適当かを確認してください。\n\n'
            self.msg += str(err)
            content = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                message_text=self.msg)
            self.popup = Popup(title='読み込み許可エラー', content=content)
            self.popup.open()
            self.err = True
        except IOError as err:
            self.msg = '保存データを読み込もうとしましたが、読み込めません。\n'
            self.msg += '読み込み先機器に問題があるようです。\n'
            self.msg += '読み込み先機器の状態を確認してください。\n\n'
            self.msg += str(err)
            content = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                message_text=self.msg)
            self.popup = Popup(title='I/Oエラー', content=content)
            self.popup.open()
            self.err = True
        except BaseException as err:
            self.msg = '保存データを読み込もうとしましたが、何らかのエラーが起きました。\n\n'
            self.msg += str(err)
            content = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                message_text=self.msg)
            self.popup = Popup(title='その他のエラー', content=content)
            self.popup.open()
            self.err = True
    def btn_ok(self):
        self.popup.dismiss()
class PathWrite:
    def __init__(self, **kwargs):
        self.err = True
        path_inf_dict = kwargs['path_inf_dict']
        self.pd = {}
        self.pd['begin_path'] = path_inf_dict['begin_path']
        try:
            #raise BaseException('やっちまったな')
            with open(path_inf, 'w') as fd:
                json.dump(self.pd, fd)
                self.err = False
        except PermissionError as err:
            self.msg = '保存データを書き込もうとしましたが、書き込み許可がありません。\n'
            self.msg += 'パスは、' + self.pd['begin_path'] + 'です。\n'
            self.msg += '保存先の書き込み許可を確認するか、パスが適当かを確認してください。\n\n'
            self.msg += str(err)
            content = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                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 = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                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 = MsgboxOkWithPost ( \
                btn_ok=self.btn_ok, \
                btn_ok_post=kwargs['btn_ok_post'], \
                message_text=self.msg)
            self.popup = Popup(title='その他のエラー', content=content)
            self.popup.open()
    def btn_ok(self):
        pprint ('OKが押されました')
        self.popup.dismiss()
class MsgboxOk(BoxLayout):
    message_text = StringProperty()
    btn_ok = ObjectProperty(None)
class MsgboxOkWithPost(BoxLayout):
    message_text = StringProperty()
    btn_ok = ObjectProperty(None)
    btn_ok_post = ObjectProperty(None)
class SetSCN(Screen):
    begin_path_dsp = ObjectProperty(None)
    def __init__(self, **kwargs):
        super(SetSCN, self).__init__(**kwargs)
    def setBeginPathCheck(self):
        if os.path.isdir(self.begin_path_dsp.text) == False:
            return False
        return True
    def setSelect(self):
        begin_path_result = self.setBeginPathCheck()
        if begin_path_result == True:
            self._popup = LstPOP(load=self.setSelectLoad, \
                                 cancel=self.setSelectCancel, \
                                 start_path=self.begin_path_dsp.text)
            self._popup.open()
        else:
            self.msg = '入力した開始パスが存在しません\n\n'
            self.msg += self.begin_path_dsp.text
            content = MsgboxOk (\
                 btn_ok=self.msgTestOk, \
                 message_text=self.msg)
            self.popup = Popup(title='入力エラー', content=content)
            self.popup.open()
            self.begin_path_dsp.text = sm.begin_path_previous
    def setSelectLoad (self, path, filename):
        self.begin_path_dsp.text = path
        sm.begin_path_previous = 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):
        begin_path_result = self.setBeginPathCheck()
        if begin_path_result == True:
            self.pd = {}
            self.pd['begin_path'] = self.begin_path_dsp.text
            pw = PathWrite( \
                path_inf_dict=self.pd, \
                btn_ok_post=self.pathwhite_ng)
            if pw.err == False:
                self.manager.get_screen('all').file_name.text = self.begin_path_dsp.text
                sm.current = 'all'
        else:
            self.msg = '入力した開始パスが存在しません\n\n'
            self.msg += self.begin_path_dsp.text
            content = MsgboxOk (\
                 btn_ok=self.msgTestOk, \
                 message_text=self.msg)
            self.popup = Popup(title='入力エラー', content=content)
            self.popup.open()
            self.begin_path_dsp.text = sm.begin_path_previous
    def selfCancel(self):
        sm.current = 'all'
    def pathwhite_ng(self):
        #
        # PathWhite()で異常だった時の処理
        #
        print('json書き込み 異常だで終了したがや')
        sys.exit()
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):
        self.popup.dismiss()
        sys.exit()
    def msgFileNameInputErrorOk(self):
        self.popup.dismiss()

    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 (\
                btn_ok=self.msgOsErrorOk, \
                message_text=msg)
            self.popup = Popup(title='OSサポートエラー', content=content)
            self.popup.open()
            return
        #
        # AllSCN用の初期設定 ファイルパス読み込み
        #
        pr = PathRead(btn_ok_post=self.pathread_ng)
        print('PathRead通過しました')
        if pr.path_json != None:
            #
            # PathRead()で正常だった時の処理
            #
            print('json読み込み 正常だがや')
            path_inf_begin = pr.path_json['begin_path']
            self.manager.get_screen('set').begin_path_dsp.text = path_inf_begin
            self.file_name.text = path_inf_begin
            sm.file_name_previous = path_inf_begin
            sm.begin_path_previous = path_inf_begin
        else:
            if pr.notfound == True:
                #
                # PathRead()で見つからなからった時の処理
                #
                print('jsonが見つからなからったがや')
                self.manager.get_screen('set').begin_path_dsp.text = self.init_path
                self.file_name.text = self.init_path
                sm.file_name_previous = self.init_path
                sm.begin_path_previous = self.init_path
        if pr.err == False:
            # AllSCNのtree処理
            self.tv.add_node(TreeViewLabel(text='シンカリオン E1 とき'))
            self.tv.add_node(TreeViewLabel(text='シンカリオン 0 ひかり'))
            self.tv.add_node(TreeViewLabel(text='シンカリオン キハ32 鉄道ホビートレイン'))
    def pathread_ng(self):
        #
        # PathRead()で異常だった時の処理
        #
        print('json読み込み 異常だで終了したがや')
        sys.exit()
    def setupButtonClicked(self):
        #
        # SetSCNへの画面遷移時の内容
        #
        sm.current = 'set'
    def allSelect(self):
        self._popup = LstPOP(load=self.allSelectLoad, \
                             cancel=self.allSelectCancel, \
                             start_path=self.file_name.text)
        self._popup.open()
    def allSelectLoad(self, path, filename):
        self.file_name.text = path
        sm.file_name_previous = path
        self._popup.dismiss()
    def allSelectCancel(self):
        self._popup.dismiss()
    def allFileNameCheck(self):
        if os.path.isdir(self.file_name.text) == False:
            return False
        return True
    def allExec(self):
        file_name_result = self.allFileNameCheck()
        if file_name_result == True:
            print('ファイルのチェック結果がOKだがや')
            sm.file_name_previous = self.file_name.text
        else:
            print('ファイルのチェック結果がNGだがや')
            self.msg = '入力した開始パスが存在しません\n\n'
            self.msg += self.file_name.text
            content = MsgboxOk (\
                 btn_ok=self.msgFileNameInputErrorOk, \
                 message_text=self.msg)
            self.popup = Popup(title='入力エラー', content=content)
            self.popup.open()
            self.file_name.text = sm.file_name_previous
    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.allSelect()
                Button:
                    size_hint_x: 0.1
                    text: '実行'
                    on_release: root.allExec()
        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: '了解'
            on_release:
                root.btn_ok()
<MsgboxOkWithPost>
    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.btn_ok()
                root.btn_ok_post()
<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:

 

(それにしても、ソースがずいぶん長くなっちゃったな)

今回、旧ロジックであった、


    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()

は、思い切って廃止し、

「・・・」ボタンの処理は、allSelect()というメソッドを新設、


class AllSCN(Screen):
(省略だわ)
def allSelect(self): self._popup = LstPOP(load=self.allSelectLoad, \ cancel=self.allSelectCancel, \ start_path=self.file_name.text) self._popup.open() def allSelectLoad(self, path, filename): self.file_name.text = path sm.file_name_previous = path self._popup.dismiss() def allSelectCancel(self): self._popup.dismiss()

と、SetSCNのsetSelect()メソッドを参考にし、

 

「実行」ボタンの処理は、allExec()というメソッドを新設、


class AllSCN(Screen):
(省略したわ) def allFileNameCheck(self): if os.path.isdir(self.file_name.text) == False: return False return True def allExec(self): file_name_result = self.allFileNameCheck() if file_name_result == True: print('ファイルのチェック結果がOKだがや') sm.file_name_previous = self.file_name.text else: print('ファイルのチェック結果がNGだがや') self.msg = '入力した開始パスが存在しません\n\n' self.msg += self.file_name.text content = MsgboxOk (\ btn_ok=self.msgFileNameInputErrorOk, \ message_text=self.msg) self.popup = Popup(title='入力エラー', content=content) self.popup.open() self.file_name.text = sm.file_name_previous

 

それで、動かしてみると、

「・・・」ボタン押下で、

一方、起点パスフィールドに、存在しないパスを入力すると、

 

で、ここは終了した。

はずだった。

 

そういえば、Windowsのようにドライブレターがある環境ではまだテストしてないよね。

ゴゴゴゴゴゴゴゴゴゴゴゴ・・・・・

それは、悪魔のささやきとも知らず、Windows環境でテストしてみた。

(filelist.kvはshift-JIS化しています)

このドライブをEドライブに変更しよう。「・・・」ボタンを押下して、、、

あれ?Eドライブは、、、。念のためにC:\に移動しよう。

画像処理だらけで、よくわからないと思うが、FileChooser経由では他のドライブに行けないのだ。

とりあえず、入力フィールドを使えばでドライブ変更は出来ることは出来るのだが、、、

 

やはり納得は出来ない。

こうして、完成を目前にして、大きな問題が出てきてしまったのだ。

ふと頭の中に、

「百里の道を行くときは、九十九里をもって半ばとせよ」

と言った、佐渡酒造先生の言葉が、頭に浮かんだのであった。

 

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