Androidアプリを作っている際にpythonでGUIを作成したいなと思ったので、kivyというライブラリを使ってGUIを作成することにしました!
今回はメモ代わりに書いているので、正直書いている項目に順番はありません。
また、今回はWidgetクラス
とウィジェット
を区別して書くことにします。カタカナでウィジェット
になっている場合は、ButtonやLabelなどのウィジェットだと思ってください。
開発環境
- Visual Studio Code 1.53.2
- MacOS Darwin x64 20.3.0
- python 3.7.7(anaconda)
参考記事
こちらの記事がわかりやすかったので、参考にさせていただきました。
Kivy 超入門(6):動的配置 – float レイアウト
Python: Kivy と Matplotlib でデータセットの確認ツールを書いてみる
Kv Languageを使ったKivyの動かし方
Kv言語の基本
Python: Kivy で Matplotlib のグラフをプロットする
Python3入門〜Kivy による GUI アプリケーション開発,サウンド入出力,ウェブスクレイピング〜
GUIを構築するためのプログラミング言語
まず、最初にAndroidアプリを作る時には、Androidアプリを作るための統合開発環境である、Android Studioというものが良く使われているみたいです。
しかし、これで作る場合は、言語はJavaかKotlinというもので作る必要があるのですが、自分はPythonで書く方が慣れているため、なんとかpythonで作る方法を探してみたところ、見つかったのが、このkivyというライブラリです。
kivyの役割
kivyライブラリを使って、GUIを作成する際は、
①pythonファイルだけを作成して、そこにkivyライブラリを読み込んで、GUIを作っていく方法
②pythonファイルとkvファイルの2つを作成して、pythonファイルには機能だけを、kvファイルにはレイアウトだけを加えていき、GUIを作成していく方法(この場合もpythonファイルにはkivyライブラリを読み込む)
②の場合は、HTMLとCSSのような書き方になっておりますね。
日本語表記するための最強のライブラリ
KV Languageを使って日本語表記を行おうと思っている方は多いと思います。
しかし、kvはデフォルトでは英語表記になっておりますので、日本語表記にするために色々面倒くさそうなことをしなければありません。
そこで活躍するのが、 japanize_kivy
になります!
!pip install japanize-kivy
import japanize_kivy
これを行うだけで、他には何もしなくても日本語で表示することが可能です。
Python: インポートするだけで Kivy が日本語を表示できるようになる japanize-kivy を作った
Widgetとは
まず、Kivyを勉強していて思ったのが、Widgetクラス
を親クラスとして継承して、Buttonなどを作っている人もいれば、継承せずに作っている人もいるという不思議。
どうやら、WidgetクラスとはButton
やLabel
などの総称のことではないかと自分は理解しました。
なので、Widgetクラスを継承しておけば、他を包括しているので、万能!みたいな感じかなと。
ルートウィジェットとは
ウィジェットのことは少しわかったのですが、次によくわからなかった部分が、ルートウィジェット
になります。
ズバリ結論から言いますと、ルートウィジェット
というのは、全てのウィジェットの1番基盤の部分になります。
少しわかりにくいと思いますので、具体例を見ながら確認していきましょう。
from kivy.app import App
from kivy.uix.widget import Widget
class MyWidget(Widget):
pass
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
こちらのpython
ファイルの方で、Widgetクラスを継承して、新しいMyWidgetクラス
を作成しています。
<MyWidget>:
BoxLayout:
orientation: 'vertical'
Label:
GridLayout:
rows:1
cols:4
Button:
Button:
Button:
Button:
上の場合ですと、ルートウィジェット
というのは、MyWidget
になります。
ルートウィジェット
というのはアプリケーションのなかに、必ず1つだけしか存在しないという特徴があります。
-
MyWidget
という1番大きなWidgetを定義する - その中に
BoxLayout
という2番目に大きなWidgetを定義する -
BoxLayout
の中に、Label
やGridLayout
やButton
などの細かいウィジェットが入っている
このような構造になっております。
MyWidget
が親だとすると、BoxLayout
は子ども、Label
やGridLayout
やButton
は孫みたいな感じになりますね。
selfとrootの違い
先程のコードのkvファイルのみを用いて説明をしたいと思います。
<MyWidget>:
BoxLayout:
orientation: 'vertical'
Label:
GridLayout:
rows:1
cols:4
Button:
Button:
Button:
Button:
まず、self
とは個々のウィジェット自身を指します。
GridLayoutの部分にself.
を書けば、GridLayout自身
を指しますし、Button
の部分に書けば、Button自身
を指します。
次にroot
ですね。
正直、rootに関してはあまり確信を持てていない状態です。
個人的な認識としては、rootウィジェット
を指していると考えております。
確信を持てていない理由
なぜ、確信を持てていないのかというと、例えば、下で説明するような画面の切り替えを行う場合に、rootは結局1番根っこのrootウィジェット
を指しているのか、それともrootウィジェットに追加されたウィジェット
を指しているのかわからないからです。
pos_hintとsize_hint
アプリケーションを作るということになった場合、PCとスマホで画面の大きさが違うという問題にぶち当たりますよね。
通常は、以下のように、ピクセル単位
で数字を指定していくのですが、これだと、PCの時は良いかもしれないが、スマホの時はサイズが合わないというふうになってしまいます。
pos: 20, 50
size: 500, 300
そこで、活躍してくれるのが、pos_hint
とsize_hint
というものになります。
pos_hint: {'x':0, 'top':1}
size_hint: 0.3, 0.4
のような形で、size_hint
は全画面に対してどれくらいの割合の大きさか、pos_hint
は画面の左下を(0,0)
として、どれくらいの割合の場所に位置するかというのを指定します。
pos_hintの変数
pos_hint
はx, y, right, topを変数として指定することができます。
xはウィジェットの左の部分の位置を指定
yはウィジェットの下部分の位置を指定
rightはウィジェットの右部分の位置を指定
topはウィジェットの上部分の位置を指定
を行うことができます。
root.sizeとhint_sizeはどう使い分ければ良い?
個人的によくわかりにくかったのが、この2つを使い分けることですね。
-
root.size
は1番大きい外枠のWidget
の大きさを基準にする -
hint_size
は今現在のWidget
の大きさを基準にする
少し文字だとわかりにくいので、具体例を使って説明していきたいと思います。
from kivy.app import App
from kivy.uix.widget import Widget
class MyWidget(Widget):
pass
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()
<MyWidget>:
BoxLayout:
orientation: 'vertical'
size: root.size
Label:
id: txt01
text: root.text
size_hint: 1, 0.1
BoxLayout
でまず、root.size
を使用しているのですが、これは、ルートウィジェット
の大きさまで大きくするという認識で考えております。
Label
の方で、size_hint
を使用していますが、こちらは、Label
より1つ外側のWidget(今回は、BoxLayout)の大きさを基準にして、調整する形になります。
もしも、Label
でroot.size
を使った場合は、MyWidget
の大きさのLabel
ができあがります。(間違っていたらすみません。)
つまづいた点
こちらは、GUIアプリを作っている際に、つまづいて、Teratailにも質問してみた内容です。
import japanize_kivy
import pandas_datareader.data as web
import numpy as np
import matplotlib.pyplot as plt
import datetime
import talib
import mplfinance as mpf
import time
import pandas as pd
import tensorflow as tf
import schedule
import traceback
import sys
from sklearn import preprocessing
from StockApp import *
from matplotlib import gridspec
from kivy.app import App
from kivy.config import Config
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import *
from kivy.resources import resource_add_path
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from kivy.graphics import *
from kivy.factory import Factory
# マルチタッチを無効化する => 右クリックしても赤い点が残らない
Config.set('input', 'mouse', 'mouse, disable_multitouch')
Config.set('modules', 'inspector', '')
Name = ['A', 'B']
# csvファイルを読み込む
Hello01 = pd.read_csv('graph01.csv')
Hello02 = pd.read_csv('graph02.csv')
Hello03 = pd.read_csv('graph03.csv')
Hello01['Date'] = pd.to_datetime(Hello01['Date'])
Hello02['Date'] = pd.to_datetime(Hello02['Date'])
Hello03['Date'] = pd.to_datetime(Hello03['Date'])
# DataFrameの状態では、インデックス番号で指定できないからnp.arrayで配列に変換する
A_Hello = np.array(Hello01).T
B_Hello = np.array(Hello02).T
C_Hello = np.array(Hello03).T
class FirstPage(BoxLayout):
text = StringProperty() # プロパティの追加
graph = NumericProperty(0)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.text = ' '
# リストに入れる
self.d_list = []
self.w_list = []
self.m_list = []
self.numbers = 0
with open('File01.txt', 'r', encoding='utf-8') as day:
self.day = day.readlines()
with open('File02.txt', 'r', encoding='utf-8') as week:
self.week = week.readlines()
with open('File03.txt', 'r', encoding='utf-8') as month:
self.month = month.readlines()
# ActionBarの次へボタンを押したら次の会社に行くようにする処理
def Next(self, index_num):
if 0 <= index_num < len(Name) - 1:
self.numbers = index_num
self.text = self.day[self.numbers]
# 月のグラフの表示を更新する処理
def update01(self):
self.text = self.month[self.numbers]
# 週のグラフの表示を更新する処理
def update02(self):
self.text = self.week[self.numbers]
# 日の表示を更新する処理
def update03(self):
self.text = self.day[self.numbers]
class GraphView(BoxLayout):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# データをrootウィジェットの方に呼び出すようにする => このクラスがインスタンス化された時に1番最初に呼び出される
self.A_Hello = A_Hello
self.B_Hello = B_Hello
self.C_Hello = C_Hello
self.d_data = Hello01
self.w_data = Hello02
self.m_data = Hello03
self.num = 0
# figとaxだけで表す必要あり
self.fig, self.ax = plt.subplots(2, 1,
gridspec_kw={
'height_ratios':[4,1]
})
self.Update(self.A_Hello[self.num+1], self.d_data[Name[self.num]], Hello['Date'])
self.add_widget(FigureCanvasKivyAgg(self.fig))
def Update(self, data, signal, times):
# 前にプロットされたグラフを消去する
self.ax[0].clear()
self.ax[1].clear()
period = 30
upper, middle, lower = talib.BBANDS(signal, timeperiod=period, nbdevup=1, nbdevdn=1, matype=0) # 引数としてHelloを取得するからselfをつける必要はない
rsi = talib.RSI(signal, timeperiod=period)
# 取得したデータを元にプロットする
self.ax[0].plot(times, data)
self.ax[0].set_ylabel('price', fontsize=15)
self.ax[0].plot(times, upper)
self.ax[0].plot(times, lower)
self.ax[0].legend([Name[self.num]])
self.ax[0].tick_params(labelsize=10)
self.ax[1].plot(times, rsi)
self.ax[1].set_xlabel('time', fontsize=20)
self.ax[1].set_ylabel('persentage', fontsize=15)
self.ax[1].legend(['RSI'])
self.ax[1].tick_params(labelsize=10)
# 再描画する
self.fig.canvas.draw()
self.fig.canvas.flush_events()
time.sleep(0.1) # 0.1秒だけ開ける
# ActionBarの次へボタンを押したら次に行くようにする処理
def Next(self, index_num):
if 0 <= index_num < len(Name) - 1:
self.num = index_num
A_Hello = self.A_Hello[self.num+1]
data = self.d_data[Name[self.num]]
self.Update(A_Hello, data, Hello['Date'])
# 月のグラフの表示を更新する処理
def update01(self):
C_Hello = self.C_Hello[self.num+1]
m_data = self.m_data[Name[self.num]]
self.Update(C_Hello, m_data, Hello03['Date']) # 上で変更された変数を元にしてメソッドが実行される
# 週のグラフの表示を更新する処理
def update02(self):
B_Hello = self.B_Hello[self.num+1]
w_data = self.w_data[Name[self.num]]
self.Update(B_Hello, w_data, Hello02['Date'])
# 日毎の表示を更新する処理
def update03(self):
A_Hello = self.A_Hello[self.num+1]
d_data = self.d_data[Name[self.num]]
self.Update(A_Hello, d_data, Hello['Date'])
class TextWidget(Widget):
sm = ScreenManager()
print(Name[0])
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def change_page(self):
self.clear_widgets()
self.add_widget(FirstPage())
def change_page2(self):
self.clear_widgets()
page2 = Factory.SecondPage()
self.add_widget(page2)
class CopyHelloApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'HelloWold' # ウィンドウの名前を変更する
def build(self):
return TextWidget()
if __name__ == '__main__':
CopyHelloApp().run()
#:kivy 2.0.0
# TextWidget rootウィジェットに指定されている
TextWidget:
<TextWidget>:
FirstPage:
id: page1
<page1>:
orientation: 'vertical'
size: root.size # BoxLayoutのサイズ rootウィジェット(TextWidget)の大きさに合わせる
# メニューバー
ActionBar:
ActionView:
ActionPrevious:
title: 'ページタイトル1'
with_previous: False # 戻るボタンを表示する
ActionButton:
text: '次のページ'
on_release: app.root.change_page2()
ActionGroup:
text: 'グループ名'
mode: 'spinner'
ActionButton:
text: 'A'
on_release: app.root.ids['graph_view'].Next(0)
on_release: app.root.ids['page1'].Next(0)
on_release: name.text = 'A'
ActionButton:
text: "B"
on_release: app.root.ids['graph_view'].Next(1)
on_release: app.root.ids['page1'].Next(1)
on_release: name.text = 'B'
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
id: name
text: 'A'
Label:
id: show
text: app.root.ids['page1'].text
# グラフをここで表示する
GraphView:
size_hint_y: 0.9
id: graph_view
GridLayout:
cols: 3
rows: 1
size_hint_y: 0.1
Button:
id: button11
text: '月'
font_size: 48
on_release: app.root.ids['graph_view'].update01()
on_release: app.root.ids['page1'].update01()
Button:
id: button12
text: '週'
font_size: 48
on_release: app.root.ids['graph_view'].update02()
on_release: app.root.ids['page1'].update02()
Button:
id: button13
text: '日'
font_size: 48
on_release: app.root.ids['graph_view'].update03()
on_release: app.root.ids['page1'].update03()
<GraphView>:
<SecondPage@BoxLayout>:
id: page2
size: root.size
orientation: 'horizontal'
# 画面の切り替えを行う
ActionBar:
ActionView:
ActionPrevious:
title: 'ページタイトル2'
with_previous: False # 戻るボタンを表示する
ActionButton:
text: '前のページ'
on_release: app.root.change_page()
MyLabel:
id: first_button
text: 'Hello'
MyLabel:
id: second_button
text: 'World'
<MyLabel@Label>:
font_size: 60
size_hint_y: 1
'''
このコードですと、なぜか画面が真っ暗になってしまったので、なんでかなと思いつつ、エラーになる前の状態から1つずつ機能を追加していきました。
import japanize_kivy
import pandas_datareader.data as web
import numpy as np
import matplotlib.pyplot as plt
import datetime
import talib
import mplfinance as mpf
import time
import pandas as pd
import tensorflow as tf
import schedule
import traceback
import sys
from sklearn import preprocessing
from StockApp import *
from matplotlib import gridspec
from kivy.app import App
from kivy.config import Config
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import *
from kivy.resources import resource_add_path
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.garden.matplotlib.backend_kivyagg import FigureCanvasKivyAgg
from kivy.graphics import *
from kivy.factory import Factory
# マルチタッチを無効化する => 右クリックしても赤い点が残らない
Config.set('input', 'mouse', 'mouse, disable_multitouch')
Config.set('modules', 'inspector', '')
Name = ['A', 'B']
# csvファイルを読み込む
Hello01 = pd.read_csv('graph01.csv')
Hello02 = pd.read_csv('graph02.csv')
Hello03 = pd.read_csv('graph03.csv')
Hello01['Date'] = pd.to_datetime(Hello01['Date'])
Hello02['Date'] = pd.to_datetime(Hello02['Date'])
Hello03['Date'] = pd.to_datetime(Hello03['Date'])
# DataFrameの状態では、インデックス番号で指定できないからnp.arrayで配列に変換する
A_Hello = np.array(Hello01).T
B_Hello = np.array(Hello02).T
C_Hello = np.array(Hello03).T
class FirstPage(BoxLayout):
text = StringProperty() # プロパティの追加
graph = NumericProperty(0)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.text = ' '
# リストに入れる
self.d_list = []
self.w_list = []
self.m_list = []
self.numbers = 0
with open('File01.txt', 'r', encoding='utf-8') as day:
self.day = day.readlines()
with open('File02.txt', 'r', encoding='utf-8') as week:
self.week = week.readlines()
with open('File03.txt', 'r', encoding='utf-8') as month:
self.month = month.readlines()
# ActionBarの次へボタンを押したら次の会社に行くようにする処理
def Next(self, index_num):
if 0 <= index_num < len(Name) - 1:
self.numbers = index_num
self.text = self.day[self.numbers]
# 月のグラフの表示を更新する処理
def update01(self):
self.text = self.month[self.numbers]
# 週のグラフの表示を更新する処理
def update02(self):
self.text = self.week[self.numbers]
# 日の表示を更新する処理
def update03(self):
self.text = self.day[self.numbers]
class GraphView(BoxLayout):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# データをrootウィジェットの方に呼び出すようにする => このクラスがインスタンス化された時に1番最初に呼び出される
self.A_Hello = A_Hello
self.B_Hello = B_Hello
self.C_Hello = C_Hello
self.d_data = Hello01
self.w_data = Hello02
self.m_data = Hello03
self.num = 0
# figとaxだけで表す必要あり
self.fig, self.ax = plt.subplots(2, 1,
gridspec_kw={
'height_ratios':[4,1]
})
self.Update(self.A_Hello[self.num+1], self.d_data[Name[self.num]], Hello['Date']) # グラフを初期化する => ここは日毎のデータにする
# ax[0].set_title('HelloPredict')
self.add_widget(FigureCanvasKivyAgg(self.fig))
def Update(self, data, signal, times):
# 前にプロットされたグラフを消去する
self.ax[0].clear()
self.ax[1].clear()
period = 30
upper, middle, lower = talib.BBANDS(signal, timeperiod=period, nbdevup=1, nbdevdn=1, matype=0) # 引数としてHelloを取得するからselfをつける必要はない
rsi = talib.RSI(signal, timeperiod=period)
# 取得したデータを元にプロットする
self.ax[0].plot(times, data)
self.ax[0].set_ylabel('price', fontsize=15)
self.ax[0].plot(times, upper)
self.ax[0].plot(times, lower)
self.ax[0].legend([Name[self.num]])
self.ax[0].tick_params(labelsize=10)
self.ax[1].plot(times, rsi)
self.ax[1].set_xlabel('time', fontsize=20)
self.ax[1].set_ylabel('persentage', fontsize=15)
self.ax[1].legend(['RSI'])
self.ax[1].tick_params(labelsize=10)
# 再描画する
self.fig.canvas.draw()
self.fig.canvas.flush_events()
time.sleep(0.1) # 0.1秒だけ開ける
# ActionBarの次へボタンを押したら次に行くようにする処理
def Next(self, index_num):
if 0 <= index_num < len(Name) - 1:
self.num = index_num
A_Hello = self.A_Hello[self.num+1]
data = self.d_data[Name[self.num]]
self.Update(A_Hello, data, Hello['Date'])
# 月のグラフの表示を更新する処理
def update01(self):
C_Hello = self.C_Hello[self.num+1]
m_data = self.m_data[Name[self.num]]
self.Update(C_Hello, m_data, Hello03['Date']) # 上で変更された変数を元にしてメソッドが実行される
# 週のグラフの表示を更新する処理
def update02(self):
B_Hello = self.B_Hello[self.num+1]
w_data = self.w_data[Name[self.num]]
self.Update(B_Hello, w_data, Hello02['Date'])
# 日毎の表示を更新する処理
def update03(self):
A_Hello = self.A_Hello[self.num+1]
d_data = self.d_data[Name[self.num]]
self.Update(A_Hello, d_data, Hello['Date'])
class DisplayCompany(BoxLayout):
pass
class TextWidget(BoxLayout):
sm = ScreenManager()
print(Name[0])
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.page1 = Factory.FirstPage()
self.page2 = Factory.SecondPage()
def change_page(self):
self.clear_widgets()
self.add_widget(self.page1)
def change_page2(self):
self.clear_widgets()
self.add_widget(self.page2)
class CopyHelloApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.title = 'HelloWold' # ウィンドウの名前を変更する
def build(self):
return TextWidget()
if __name__ == '__main__':
CopyHelloApp().run()
#:kivy 2.0.0
# TextWidget rootウィジェットに指定されている
TextWidget:
<TextWidget>:
PredictShow:
id: page1
<PredictShow>:
orientation: 'vertical'
size: root.size # BoxLayoutのサイズ rootウィジェット(TextWidget)の大きさに合わせる
# メニューバー
ActionBar:
ActionView:
ActionPrevious:
title: 'ページタイトル1'
with_previous: False # 戻るボタンを表示する
ActionButton:
text: '次のページ'
on_release: app.root.change_page2()
ActionGroup:
text: 'グループ名'
mode: 'spinner'
ActionButton:
text: 'A'
on_release: root.ids.graph_view.Next(0)
on_release: app.root.ids['page1'].Next(0)
on_release: name.text = 'A'
ActionButton:
text: "B"
on_release: root.ids.graph_view.Next(1)
on_release: app.root.ids['page1'].Next(1)
on_release: name.text = 'B'
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.1
Label:
id: name
text: 'A'
Label:
id: show
text: root.text
# グラフをここで表示する
GraphView:
size_hint_y: 0.9
id: graph_view
GridLayout:
cols: 3
rows: 1
size_hint_y: 0.1
Button:
id: button11
text: '月'
font_size: 48
on_release: root.ids.graph_view.update01()
on_release: app.root.ids['page1'].update01()
Button:
id: button12
text: '週'
font_size: 48
on_release: root.ids.graph_view.update02()
on_release: app.root.ids['page1'].update02()
Button:
id: button13
text: '日'
font_size: 48
on_release: root.ids.graph_view.update03()
on_release: app.root.ids['page1'].update03()
<GraphView>:
<DisplayCompany>:
id: page2
size: root.size
orientation: 'horizontal'
# 画面の切り替えを行う
ActionBar:
ActionView:
ActionPrevious:
title: 'ページタイトル2'
with_previous: False # 戻るボタンを表示する
ActionButton:
text: '前のページ'
on_release: app.root.change_page()
MyLabel:
id: first_button
text: 'Hello'
MyLabel:
id: second_button
text: 'World'
<MyLabel@Label>:
font_size: 60
size_hint_y: 1
変更点
・rootウィジェットである、TextWidgetの親クラスをBoxLayoutに変更。
・カスタムウィジェットであるの部分をに変更。
・Labelのtextをapp.root.ids['page1'].text
からroot.text
に変更
・TextWidgetクラス内で、__init__
メソッドを追加し、self.page1=Factory.FirstPage()
とself.page2=Factory.SecondPage()
を記述。
・rootウィジェット内にidを置いたウィジェット(今回ではFirstPage)のメソッドにアクセスする際に、app.root.ids['ID名'].メソッド名
を使用する
・rootウィジェットのメソッドにアクセスする際に、root.メソッド名
を使用する。
・rootウィジェットの下のウィジェットのメソッドにアクセスする際に、root.ids.ID名.メソッド名
を使用する。
わかった点(個人的に解釈しているだけで確証はない)
・画面を切り替えるときは、Widgetクラス
じゃなくて、BoxLayoutクラス
を継承する方が上手くいく。
・textやsizeなどイベントでは無い部分に対して、app.root
は使わない。root.size
やroot.text
という記述をする。
・TextWidgetクラスの初期化部分で、self.ページ名
を記述しておくと、別のページに移動しても元の画面の情報が失われない。
・rootウィジェットに追加したウィジェットのメソッドにアクセス→app.root.ids['ID名'].メソッド名
・rootウィジェットクラスのメソッドにアクセス→app.root.メソッド名
・rootウィジェットの下のウィジェットのメソッドにアクセス→root.ids.ID名.メソッド名
まとめ
Kivy
の記事は少ないとのことで、自分も理解するのが大変でした。
わかりやすい記事があって助かりました。
自分の記事も皆さんのお助けになればと思います。