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

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

ただいまの
回答率

90.99%

  • Python

    5565questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    4117questions

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

Python Kivy | Screen内のidが取得できない

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 449

Kivyについてですが、タイトル通りの状態が続いています。
単純にkivyファイルにてidを設定後、クラスのルート位置にid名を設定し
pythonファイルで受け取れるようにしたのですが、やはりidが取得できません。

一応id以外の問題かなと確認をしてみたら、KivyファイルにてScreenManagerに設定されているScreenについてはidが取得できないことがわかりました。

海外サイトなどでもこの現象について検索してみましたが、バグの線が非常に高く、提供元の改善を待つしかないようなのだそうです。

念のためコードを張ります。

もし解決策がお分かりの方がいましたら
教えてください。

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout


kv = """
Root:
    LoginScreen:
    SignUpScreen:
    PassScreen:
    Search:

<test>:
    rv: rv
    RecycleView:
        id: rv
        scroll_type: ['bars', 'content']
        scroll_wheel_distance: dp(114)
        bar_width: dp(10)
        viewclass: 'Row'
        RecycleBoxLayout:
            default_size: None, dp(56)
            default_size_hint: 1, None
            size_hint_y: None
            height: self.minimum_height
            orientation: 'vertical'
            spacing: dp(2)


"""
Builder.load_string(kv)

class Test(Screen):
    def __init__(self, **kwargs):
        super(Search, self).__init__(**kwargs)
        self.rv.data.insert(2, {'value': '????'})

class Root(ScreenManager):
    pass

class MyApp(App):
    def build(self):
        return RootFile


if __name__ == '__main__':
    MyApp().run()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

checkベストアンサー

+2

絶対に動かない理由ですが、その前にKvLanguageのclass ruleとroot ruleの違いを説明させて下さい。

まずclass rule("<クラス名>:"で始まるもの)は

  • 型の定義であり、そこに書いた物はその型のインスタンス全てに影響を与えます(厳密には少し違いますが)。
  • そしてclass ruleを書いただけではインスタンスは作られません

それに対してroot rule("クラス名:"で始まるもの)は

  • 書いただけでインスタンスが一つ作られ、それがBuilder.load_string()の戻り値になります。
  • そしてroot ruleに書いた様々な定義はそのインスタンスのみの物で、他のインスタンスには影響を与えません。

上のコードにはRootクラスのroot ruleがある為、

Builder.load_string(kv)

の行でKivyはRootクラスのインスタンスを作ろうとします。でも失敗します。何故ならRootの基底クラスが分からないからです。原因は

class Root(ScreenManager):
    pass


をBuilder.load_string()の前に書いてないからで、そうしてあげればインスタンス化に成功します。

ただまだ問題があって、それはBuilder.load_string(kv)の戻り値を誰も受け取ってない事です。このままだとRootのインスタンスは作ってすぐ捨てている事になるので、

class MyApp(App):
    def build(self):
        return Builder.load_string(kv)

としてあげてください。そうすれば名前の通りRootのWidgetになります。

最後にですがTestクラスの基本クラスがScreenなのなら、おそらく

Root:
    LoginScreen:
    SignUpScreen:
    PassScreen:
    Search:
    Test:

<Test>:
    略

と、Root(ScreenManager)の子にしてやるのが希望の状態じゃないかと思います。

class ruleとroot ruleに関しては混乱すると思いますが、頑張ってください。また私はそれに関する記事も書いているので良かったら参考にしてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/09/15 12:11

    回答ありがとうございました。
    かなり詳しく記載していただきまして、大変参考になりました。

    キャンセル

  • 2017/09/16 22:12

    いえいえ

    キャンセル

+2

Screen内のidが取れるかどうかという話ですが結論から言うと取れます。

ただ、他の方も指摘されている通り今のコードだとそもそも起動しないかと思います。
なのでそちらのコードを修正して動くようにしてみました。
ただし「RecycleView」は修正が面倒だったのではずしました。

以下のコードを実行して、画面をクリックするとスライドが切り替わります。
最後のスライドで「TEST」というボタンと「TEST2」というところで、「TEST」ボタンを押すとラベルが「change」に変わるかと思います。

MyAppクラスのchange_labelメソッドを見てください。そこでidを取得してますのでご参考にしてください。

なおmanzyunさんが指摘されている
「self.root.get_screen('main').ids」
だとidsからたどるのは難しいです。
詳しい説明は省きますがget_screen()で取得できるのはwidgetの要素でこれだと、Widgetのサイズとかは取得できますが、idsからは辿れません。

Kvの書き方に関してはgottadiveintopyさんの質問が的確ですのでそちらを参考にしてみてください。

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
#from kivy.uix.boxlayout import BoxLayout

kv = """
Root:
    test:
    LoginScreen:
        name: "Login_screen"
        Button:
            text: 'Goto SignUpScreen'
            on_press: app.root.current  = 'SignUp_screen'

    SignUpScreen:
        name: "SignUp_screen"
        Button:
            text: 'Goto SignUpScreen'
            on_press: app.root.current  = 'Pass_screen'

    PassScreen:
        name: "Pass_screen"
        Button:
            text: 'Goto Search'
            on_press: app.root.current  = 'Search_screen'

    Search:
        name: "Search_screen"
        Button:
            text: 'Goto SignUpScreen'
            on_press: app.root.current  = 'Result_screen'

    Result:
        name: "Result_screen"
        id: result
        Test:
            id: result_x

<Test>:
    BoxLayout:
        orientation: 'vertical'
        Button:
            text: ' TEST'
            #on_press: root.click_tests()
            on_press: app.change_label()
        Label:
            id: test2
            text: ' TEST2'
"""
#Builder.load_string(kv)

class Root(ScreenManager):
    pass

class LoginScreen(Screen):
    pass

class SignUpScreen(Screen):
    pass

class PassScreen(Screen):
    pass

class Search(Screen):
    pass

class Result(Screen):
    def __init__(self, **kwargs):
        super(Result, self).__init__(**kwargs)


class Test(Screen):
    pass


class MyApp(App):
    def build(self):
        return Builder.load_string(kv)

    def change_label(self):
        self.root.ids['result_x'].ids['test2'].text = 'change'

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

idの取得云々の前にウィンドウがそもそも表示されていますか?
上のコードはかなりメチャクチャで、例え"RootFile"や"<test>"などのタイプミスを直した上で
LoginScreen:
SignUpScreen:
PassScreen:
Search:
など定義の確認できないWidget類を消したとしても、絶対に動かないコードになっています。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

Referencing ids within screenmanager object - Stackoverflow
を読む限りだと、 get_screen('スクリーン名').ids という命令がありますので、ScreenManagerで名前を付けてやればいいのではないかと想像しました。

kv = """
Root:
    LoginScreen:
        name: 'login'
    SignUpScreen:
        name: 'sign_up'
    PassScreen:
        name: 'pass'
    Search:
        namd: 'seach'

"""

### 中略 ###

def on_start(self):
    print(self.root.get_screen('main').ids)

とかでコンソール画面に何か表示されないでしょうか。

ぼやっとした回答で申し訳ありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.99%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    5565questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    4117questions

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