Kivy 日本語の表示と日本語を入力する(Python Kivyの取説・使い方 第12回)
日本語表示と日本語入力をする方法
1)kvファイルに日本語を対応させる
2)日本語を表示させる
3)日本語を入力する
の順番で解説していきます。
1)kvファイルに日本語を対応させる
まずラベル、テキストボックス、ボタンを作ります。
# フル画面を解除して画面の幅と高さを設定 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) from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.widget import Widget class MainScreen(BoxLayout): pass class TestApp(App): def build(self): self.title = 'テスト' return MainScreen() if __name__ == '__main__': TestApp().run()
kvファイル(test.kv)
<MainScreen>: BoxLayout: orientation: "vertical" Label: text: "日本語" TextInput: Button: text: "ボタン"
実行してみると、、、エラーが出ます。
UnicodeDecodeError: 'cp932' codec can't decode byte 0x9e in position 109: illegal multibyte sequence
こちらのサイトを参考に(丸パクリ)させていただきました。対策まで載ってます。
「builder.py」を編集します。
C:\Program Files\Python37\Lib\site-packages\kivy\lang
のフォルダの中にありました。
エラーは出なくなりましたが文字化けしています。
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) from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.uix.widget import Widget from kivy.core.text import LabelBase, DEFAULT_FONT # 追加分 from kivy.resources import resource_add_path # 追加分 resource_add_path('c:/Windows/Fonts') # 追加分 LabelBase.register(DEFAULT_FONT, 'msgothic.ttc') # 追加分 class MainScreen(BoxLayout): pass class TestApp(App): def build(self): self.title = 'テスト' return MainScreen() if __name__ == '__main__': TestApp().run()
kvファイルはそのまま使います。
「♯ 追加分」の4行を追加します。パス名は環境によって変わる可能性があります。
日本語が表示できました。
3)日本語を入力する
テキストボックスに日本語を入力すると、入力中の文字が表示されません。また変な改行がされてしまいます。これでは使いにくいので日本語入力に対応させます。
# フル画面を解除して画面の幅と高さを設定 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): pass 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: "日本語" RelativeLayout: TextInputIME: id: textinput composition_window: cmp_window pos: root.pos size: root.size CompositionLabel: id: cmp_window textinput: textinput x: textinput.cursor_pos[0] y: textinput.cursor_pos[1] - self.height Button: text: "ボタン" <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
日本語入力できました。
解説
まずこちらの過去記事の解説で紹介させていただきたサイトから
「ime_operator.cpp」と「ime_operator.dll」を同じフォルダに保存します。
メインプログラムの前半部分(というかほとんどの部分)は「このままコピペしたら動くのでオッケー」ということで進めていきます。
class MainScreen(Widget):
ここの「Widget」が「BoxLayout」から変わっています。
kvファイルを見ていきます。
BoxLayout:
size: root.size
「size: root.size」を入れないとWidgetレイアウトの大きさが「100×100」になってしまいます。
RelativeLayout:
FloatLayoutだと全てのレイアウトの絶対座標になり、RelativeLayoutならこのレイアウトだけの相対座標になります。「size: root.size」で真ん中のテキストボックスいっぱいのサイズが指定できます。
苦労した点
「if composition_string != '\n\n':」
「if (entered_text != '\n\n' and self.is_openIME and self.old_composition != value):」
「'\n\n'」・・・「'¥n¥n'」の部分がなぜか「'/n/n'」になっていてなかなか気づけませんでした。
そのときのエラーがこちらです。(わかりやすく色は変えています)
まとめ
そのうちkivyのバージョンアップで日本語入力にも対応してくれると信じてますがそれまではこの方法で対応していきます。
次回はテキストボックスの読み込みと保存を作っていきます。
保存ファイル
lesson68.py
lesson69.py
test.kv
文責:Luke