Start_python’s diary

ふたり暮らし

アラフィフ夫婦のフリーランスプラン

Kivy テキストファイルの読み込みと保存(Python Kivyの取説・使い方 第13回)

はじめに

Kivyのテキストボックスの内容をtxtファイルへ保存する方法を調べるのに苦労しました。それもそのはずで保存はKivyモジュールは使わずPythonwrite関数を使うみたいです。最近KivyばかりやっていたのでなんでもKivyでしようとしてました。

 

f:id:Start_python:20191223173340g:plain

Pythonでファイルの読み込みと保存する方法

open関数とread関数、write関数を使います。

open関数

変数 = open(引数1, 引数2)

引数1:ファイル名(同じフォルダにないときはパス名にも注意)

引数2:モード。「r」と指定しない場合は読み込み、「w」で書き込みです。

read関数

変数 = 引数1.read()

引数1:読み込みモードで開いたファイル(の変数)

write関数

引数1.write(引数2)

引数1:書き込みモードで開いたファイル(の変数)

引数2:文字列(の変数)

 

class MainScreen(Widget):

    text = StringProperty()

    def __init__(self, **kwargs):

        super(MainScreen, self).__init__(**kwargs)

        self.ids.textinput.text = ' '
        self.ids.textinput.text = ''
        try:
            file = open('テスト.txt', 'r')
            self.ids.textinput.text = file.read()
            file.close()
            self.text = '「テスト.txt」を開きました'
        except:
            self.text = 'ファイルが見つかりません'

    def on_command(self, **kwargs):

        text = self.ids.textinput.text

        file = open('テスト.txt', 'w')
        file.write(text)
        file.close()
        self.text = '保存しました'

    def on_edit(self, **kwargs):
        self.text = ''
前回のclass MainScreen(Widget):の部分だけ変更しています。

解説

 try関数(except)

簡単に説明すると

「try:

     やってみる処理

 except:

     ダメだった場合の処理」

です。今回は開くファイルが見つからなかった場合のエラーを防ぐために使いました。

def on_command(self, **kwargs):

ボタンが押されたときの処理です。kvファイルで指定しています。

def on_edit(self, **kwargs):

テキストボックスが編集されたときの処理です。kvファイルで指定しています。

苦労した点(ごまかした点)

self.ids.textinput.text = ' '

self.ids.textinput.text = ''

この2行を入れないと、ラベルに「ファイルが見つかりません」を表示した後すぐにテキストボックスが編集されてしまい表示が消えてしまいます。 この2行で先にテキストボックスを編集させるとラベル表示の処理が後になってうまくいきました。

 

プログラムのコード

# フル画面を解除して画面の幅と高さを設定
from kivy.config import Config
Config.set('graphics', 'fullscreen', 0)
Config.set('graphics', 'width', 320)
Config.set('graphics', 'height', 568)
Config.set('graphics', 'resizable', 0)

import ctypes
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.resources import resource_add_path
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.utils import platform
from kivy.base import EventLoop
from kivy.properties import StringProperty, ObjectProperty
from kivy.utils import escape_markup


resource_add_path('c:/Windows/Fonts')
LabelBase.register(DEFAULT_FONT, 'msgothic.ttc')

dll = ctypes.cdll.LoadLibrary('./ime_operator.dll')
dll.getComposition.restype = ctypes.c_char_p
dll.getEnterdString.restype = ctypes.c_char_p


class TextInputIME(TextInput):

    composition_string = StringProperty()
    sdl_composition = StringProperty()
    composition_window = ObjectProperty()

    def __init__(self, **kwargs):

        super(TextInputIME, self).__init__(**kwargs)

        self.disable_on_textedit = (False, False)
        self.is_openIME = False
        self.old_cursor_color = self.cursor_color
        self.old_composition = ''

        EventLoop.window.bind(on_textedit=self._on_textedit)

    def _on_textedit(self, _, value):

        self.sdl_composition = value
        self.is_openIME = bool(dll.getIsOpenIME())

        try:
            entered_text = dll.getEnterdString().decode('cp932')
            composition_string = dll.getComposition().decode('cp932')
        except UnicodeError:
            print('failed to decode IME information')

        if composition_string != '\n\n':
            self.composition_string = composition_string
        else:
            self.composition_string = ''

        if (entered_text != '\n\n' and self.is_openIME and self.old_composition != value):
            index = self.cursor_index()
            self.text = self.text[:index - 1] + entered_text + self.text[index:]
            self.composition_string = ''
            self.old_composition = value
            return None

        self.old_composition = value

    def insert_text(self, substring, from_undo=False):

        if substring == self.sdl_composition:
            return None
        else:
            return super(TextInputIME, self).insert_text(substring, from_undo)

    def keyboard_on_key_down(self, window, keycode, text, modifiers, dt=0):

        cursor_operations = {'left', 'up', 'right', 'down', 'backspace', 'tab'}
        self.composition_cursor_index = len(self.composition_string)

        if keycode[1] == 'left':
            self.composition_cursor_index -= 1

        if keycode[1] == 'right':
            self.composition_cursor_index += 1

        if keycode[1] in cursor_operations and self.composition_string:
            return None

        return super(
            TextInputIME,
            self).keyboard_on_key_down(
            window,
            keycode,
            text,
            modifiers)

    def on_composition_string(self, _, value):

        if self.composition_string:
            self.cursor_color = (0, 0, 0, 0)
        else:
            self.cursor_color = self.old_cursor_color

        if not dll.getIsOpenIME():
            return

        self.composition_window.text = '[u]' + value + '[/u]'


class CompositionLabel(Label):

    textinput = ObjectProperty()

    def __init__(self, **kwargs):
        super(CompositionLabel, self).__init__(**kwargs)


class MainScreen(Widget):

    text = StringProperty()

    def __init__(self, **kwargs):

        super(MainScreen, self).__init__(**kwargs)

        self.ids.textinput.text = ' '
        self.ids.textinput.text = ''
        try:
            file = open('テスト.txt', 'r')
            self.ids.textinput.text = file.read()
            file.close()
            self.text = '「テスト.txt」を開きました'
        except:
            self.text = 'ファイルが見つかりません'

    def on_command(self, **kwargs):

        text = self.ids.textinput.text

        file = open('テスト.txt', 'w')
        file.write(text)
        file.close()
        self.text = '保存しました'

    def on_edit(self, **kwargs):
        self.text = ''

class TestApp(App):
    def build(self):
        self.title = 'テスト'
        return MainScreen()

if __name__ == '__main__':
    TestApp().run()

kvファイル(test.kv)

<MainScreen>:
    BoxLayout:
        size: root.size
        orientation: "vertical"

        Label:
            text: root.text

        RelativeLayout:
            TextInputIME:
                id: textinput
                composition_window: cmp_window
                pos: root.pos
                size: root.size
                on_text: root.on_edit()
            CompositionLabel:
                id: cmp_window
                textinput: textinput
                x: textinput.cursor_pos[0]
                y: textinput.cursor_pos[1] - self.height

        Button:
            text: "保存"
            on_press: root.on_command()


<CompositionLabel>:
    size_hint_x: None
    size_hint_y: None
    width: self.font_size * (len(self.text)-7)
    height: self.font_size
    color: 0,0,0,1
    markup: True
    canvas.before:
        Color:
            rgba: 1,1,1,len(self.text)-7
        Rectangle:
            pos: self.pos
            size: self.size

 

まとめ

テキストファイルの読み込みと書き込み自体はそんなに難しくなかったです。ただ思い込みでKivyでの保存方法を探してみたり、ラベルへの表示文字の部分などで時間がかかりました。

 

 

次回はテキストボックスを読み込むためのファイル選択ダイアログを作っていきます。

 

 

保存ファイル

lesson70.py

test.kv

 

 

文責:Luke