質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Kivy

Kivyは、Pythonを用いたNUI開発のためのオープンソースフレームワーク。マルチタッチなど多くの入力に対応したNUIアプリなどを開発することができます。多くの環境で動作するクロスプラットフォームです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

3444閲覧

kv言語で、Pythonコードからのデータの受け渡しができずに、悩んでいます。

退会済みユーザー

退会済みユーザー

総合スコア0

Kivy

Kivyは、Pythonを用いたNUI開発のためのオープンソースフレームワーク。マルチタッチなど多くの入力に対応したNUIアプリなどを開発することができます。多くの環境で動作するクロスプラットフォームです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/09/06 05:43

前提・実現したいこと

テスト用に、kivyで簡単な画面を作っています。
これは、各classごとに開発という手法をとっています。

Python3

1from kivy.app import App 2from kivy.lang import Builder 3from kivy.properties import ObjectProperty 4 5from kivy.uix.boxlayout import BoxLayout 6 7 8Builder.load_string(''' 9 10<TestSCN>: 11 tct_p: tct_v 12 13 BoxLayout: 14 OpeParts: 15 ResultParts: 16 Label: 17 id: tct_v 18 text: 'ZZZ' 19 20<OpeParts>: 21 Label: 22 text: 'AAA' 23 24<ResultParts>: 25 rcAdd_p: rcAdd_v 26 27 Label: 28 id: rcAdd_v 29 text: 'XXX' 30 31''') 32 33 34class OpeParts(BoxLayout): 35 pass 36 37 38class ResultParts(BoxLayout): 39 rcAdd_p = ObjectProperty() 40 41 def __init__(self,**kwargs): 42 super(ResultParts, self).__init__(**kwargs) 43 self.rcAdd_p.text = 'BBB' 44 45 46class TestSCN(BoxLayout): 47 tct_p = ObjectProperty() 48 49 def __init__(self,**kwargs): 50 super(TestSCN, self).__init__(**kwargs) 51 self.tct_p.text = 'CCC' 52 53 54class TestApp(App): 55 def build(self): 56 return TestSCN() 57 58 59if __name__ == '__main__': 60 TestApp().run() 61

さて、Pythonのコードからkvファイルを使って、値を表示させることを意図していますが、このようなエラーメッセージが出て、うまく動きません。

Traceback (most recent call last): File "/home/arakawa/MyApp/01_filelist/kv19e2.py", line 60, in <module> TestApp().run() File "/usr/lib/python3/dist-packages/kivy/app.py", line 800, in run root = self.build() File "/home/arakawa/MyApp/01_filelist/kv19e2.py", line 56, in build return TestSCN() File "/home/arakawa/MyApp/01_filelist/kv19e2.py", line 50, in __init__ super(TestSCN, self).__init__(**kwargs) File "/usr/lib/python3/dist-packages/kivy/uix/boxlayout.py", line 131, in __init__ super(BoxLayout, self).__init__(**kwargs) File "/usr/lib/python3/dist-packages/kivy/uix/layout.py", line 76, in __init__ super(Layout, self).__init__(**kwargs) File "/usr/lib/python3/dist-packages/kivy/uix/widget.py", line 348, in __init__ Builder.apply(self, ignored_consts=self._kwargs_applied_init) File "/usr/lib/python3/dist-packages/kivy/lang/builder.py", line 469, in apply self._apply_rule(widget, rule, rule, ignored_consts=ignored_consts) File "/usr/lib/python3/dist-packages/kivy/lang/builder.py", line 585, in _apply_rule self._apply_rule(child, crule, rootrule) File "/usr/lib/python3/dist-packages/kivy/lang/builder.py", line 582, in _apply_rule child = cls(__no_builder=True) File "/home/arakawa/MyApp/01_filelist/kv19e2.py", line 43, in __init__ self.rcAdd_p.text = 'BBB' AttributeError: 'NoneType' object has no attribute 'text' プロセスは終了コード 1 で完了しました

ResultPartsの'BBB'を表示させたいのですが、うまくいきません。

Python(kv言語)

1 BoxLayout: 2 OpeParts: 3 ResultParts:

という書き方をやめればうまくいくと思いますが、先ほども言ったようにclassごとに開発をしたいと思っていますので、できればこの書き方を堅持したいと思っています。
この状況で、中央のLabelを'BBB'と表示させるには、どうしたらよいのでしょうか?

よろしくお願いいたします。

開発環境
Python 3.5.2 + kivy 1.10.1 + Ubuntu16.04

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

この原因はWidgetがKv言語上で他のWidgetの子になった場合そうでない場合の初期化のされ方の違いにあります。上記のコードだとTestSCN以外の全てのWidgetはKv言語上で別のWidgetの子として作られているので全て前者にあたります。前者だとどうなるのかというとKv言語で書かれた物が適用されるのが遅れます。今回の場合、前者であるResultsPartsのKv言語で書かれた物(rcAdd_p: rcAdd_v rcAdd_pプロパティのへの値の設定)が遅れてNoneになっている状態で.text = 'BBB'としたのでErrorになっています。

対策ですが

  • Clockを使ってKv言語適用後に行いたい処理を予約する
  • 無理やりResultParts後者にしてしまう
  • ResultsParts.on_rcAdd_p()を用意する

の3つが思いつきます。

1. Clockを使ってKv言語適用後に行いたい処理を予約する

python3

1 2from kivy.clock import Clock 3 4class ResultParts(BoxLayout): 5 rcAdd_p = ObjectProperty() 6 7 def __init__(self, **kwargs): 8 super(ResultParts, self).__init__(**kwargs) 9 Clock.schedule_once(self._after_kv_applied) 10 11 def _after_kv_applied(self, dt): 12 self.rcAdd_p.text = 'BBB'

式一つで済むのならlambdaでもいいと思います。

2. 無理やりResultPartsを後者にしてしまう

これは主さんの望まない方法かもしれませんが一応。

BoxLayout: OpeParts: ResultParts:

BoxLayout: OpeParts: RelativeLayout: id: parent_of_results_parts

として、

class TestSCN(BoxLayout): tct_p = ObjectProperty() def __init__(self,**kwargs): super(TestSCN, self).__init__(**kwargs) self.tct_p.text = 'CCC'

class TestSCN(BoxLayout): tct_p = ObjectProperty() def __init__(self,**kwargs): super(TestSCN, self).__init__(**kwargs) self.tct_p.text = 'CCC' self.ids.parent_of_results_parts.add_widget(ResultsParts())

とします。この場合ResultsPartsはKv言語上で別のWidgetの子になってないので後者にあたり、ResultsParts.__init__()内でrcAdd_pにアクセスできるようになります。

3 ResultsParts.on_rcAdd_p()を用意する

on_プロパティ名のMethodはプロパティが書き換えられた時に呼ばれるので、on_rcAdd_p()が呼ばれた時にはrcAdd_p: rcAdd_vが適用済みだと期待できます。

python

1class ResultParts(BoxLayout): 2 rcAdd_p = ObjectProperty() 3 4 def __init__(self, **kwargs): 5 super(ResultParts, self).__init__(**kwargs) 6 7 def on_rcAdd_p(self, __, value): 8 self.rcAdd_p.text = 'BBB'

でも今回の場合だと'BBB'で書き換えた後に'XXX'に上書きされてしまうので、さらにKv言語のtext: 'XXX'の部分を消す必要があります。

投稿2018/09/07 03:28

gottadiveintopy

総合スコア736

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/09/07 04:12

ありがとうございました。1番を採用して確認できました。 当方、kivyでこういった表現ができるのか疑心暗鬼で、ずいぶん資料を調べたり、デバッガーをいじったりしていました。 Clockを使う方法は知っていたのですが、こういうやり方は思いつきませんでした。 本当にありがとうございました。
guest

0

暫定的な回答です。
質問でのkv言語部分の

BoxLayout: OpeParts: ResultParts:

表記はあきらめています。

Python3

1from kivy.app import App 2from kivy.lang import Builder 3from kivy.properties import ObjectProperty 4 5from kivy.uix.boxlayout import BoxLayout 6 7 8Builder.load_string(''' 9 10<TestSCN>: 11 tct_p: tct_v 12 rcAdd_p: rcAdd_v 13 14 BoxLayout: 15 Label: 16 text: 'AAA' 17 Label: 18 id: rcAdd_v 19 text: 'XXX' 20 Label: 21 id: tct_v 22 text: 'ZZZ' 23 24''') 25 26class ResultParts(BoxLayout): 27 28 def __init__(self,**kwargs): 29 super(ResultParts, self).__init__(**kwargs) 30 self.rpv = 'BBB' 31 32 33class TestSCN(BoxLayout): 34 tct_p = ObjectProperty() 35 rcAdd_p = ObjectProperty() 36 37 def __init__(self,**kwargs): 38 super(TestSCN, self).__init__(**kwargs) 39 self.tct_p.text = 'CCC' 40 self.rcAdd_p.text = ResultParts().rpv 41 42 43class TestApp(App): 44 def build(self): 45 return TestSCN() 46 47 48if __name__ == '__main__': 49 TestApp().run() 50

私の理解力では、1画面1クラスルールで書かないと、うまくいきません。

考えてくださった方、どうもありがとうございした。

投稿2018/09/07 02:11

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問