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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python

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

Q&A

解決済

1回答

815閲覧

kivy add_widgetを使用しないでKV 言語に変数を渡したい

BlueBits

総合スコア57

Python 2.7

Python 2.7は2.xシリーズでは最後のメジャーバージョンです。Python3.1にある機能の多くが含まれています。

Python

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

0グッド

0クリップ

投稿2018/07/22 15:39

編集2018/07/24 04:33

コード

下記のコードでImage Widgetを追加しています。
(確認用コードのため、不要な流れがありますがご了承ください)

python

1# -*- coding: utf-8 -*- 2from kivy.app import App 3from kivy.uix.image import Image 4from kivy.uix.floatlayout import FloatLayout 5 6class MainImage(Image): 7 def __init__(self, **kwargs): 8 self.source = kwargs["image"] 9 super(MainImage, self).__init__(**kwargs) 10 11class MainFrame(FloatLayout): 12 def __init__(self, **kwargs): 13 super(MainFrame, self).__init__(**kwargs) 14 package = {"image": "./ss.png"} 15 self.add_widget(MainImage(**package)) 16 17class MainApp(App): 18 def __init__(self, **kwargs): 19 super(MainApp, self).__init__(**kwargs) 20 21 def build(self): 22 root = MainFrame() 23 return root 24 25if __name__ == '__main__': 26 MainApp().run() 27
#:kivy 1.10 #-*- coding: utf-8 -*- <MainFrame>: <Image>: allow_stretch:True keep_ratio: True nocache:True <MainImage>: pos_hint:{'center_x':.5,'y':0 } size_hint:None,0.95 width: self.height*self.image_ratio

上記のコードは、add_widget時にImage sourceを入れて表示します。
その際、横幅をsourceに合わせた比率で表示という処理をしています。

目的

add_widgetを外しつつ、package変数をMainImageクラス内で使用する方法を考えています。
可能な限り MainImage内で処理(コード変更1のように)をできたらいいなというのが今回のご質問の目的です。

コード変更1

下記のコードはMainImageにPackageデータが送られていないため、エラーが表示されます。

python

1# -*- coding: utf-8 -*- 2from kivy.app import App 3from kivy.uix.image import Image 4from kivy.uix.floatlayout import FloatLayout 5 6class MainImage(Image): 7 def __init__(self, **kwargs): 8 self.source = kwargs["image"] 9 super(MainImage, self).__init__(**kwargs) 10 11class MainFrame(FloatLayout): 12 def __init__(self, **kwargs): 13 super(MainFrame, self).__init__(**kwargs) 14 package = {"image": "./ss.png"} 15 #self.add_widget(MainImage(**package)) 16 17class MainApp(App): 18 def __init__(self, **kwargs): 19 super(MainApp, self).__init__(**kwargs) 20 21 def build(self): 22 root = MainFrame() 23 return root 24 25if __name__ == '__main__': 26 MainApp().run() 27
#:kivy 1.10 #-*- coding: utf-8 -*- <MainFrame>:  MainImage: #MainImage追加 <Image>: allow_stretch:True keep_ratio: True nocache:True <MainImage>: pos_hint:{'center_x':.5,'y':0 } size_hint:None,0.95 width: self.height*self.image_ratio

コード変更2(ObjectPropertyパターン)

add_widgetなしの目的は達成
一番目的に近いパターンです。
可能であればObjectPropertyなしでできないかというところです。

# -*- coding: utf-8 -*- from kivy.app import App from kivy.uix.image import Image from kivy.uix.floatlayout import FloatLayout from kivy.properties import ObjectProperty class MainImage(Image): def __init__(self, **kwargs): super(MainImage, self).__init__(**kwargs) def set(self,**package): self.source = package["image"] class MainFrame(FloatLayout): mainimage = ObjectProperty(None) def __init__(self, **kwargs): super(MainFrame, self).__init__(**kwargs) package = {"image": "./ss.png"} self.mainimage.set(**package) class MainApp(App): def __init__(self, **kwargs): super(MainApp, self).__init__(**kwargs) def build(self): root = MainFrame() return root if __name__ == '__main__': MainApp().run()
#:kivy 1.10 #-*- coding: utf-8 -*- <MainFrame>: mainimage:image1 MainImage: id:image1 <Image>: allow_stretch:True keep_ratio: True nocache:True <MainImage>: pos_hint:{'center_x':.5,'y':0 } size_hint:None,0.95 width: self.height*self.image_ratio

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

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

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

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

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

guest

回答1

0

ベストアンサー

Kv言語上で以下のように書くことができない理由は何かあるのですか?

text

1<MainFrame>:  2 MainImage: 3 source: '...' 4 pos_hint: {...}

それと、コード中にMainImage.source = "./ss.png"という代入文がありますが、こういった書き方は絶対にしてはいけないです。必ずInstance経由でPropertyに対して操作してください。(KivyのPropertyはInstance毎に存在していて、通常のPythonのClass属性のように共有されていません)

python

1image = MainImage(...) 2image.source = '...'

追記1

表示する要素(Image,Label)の大まかなものは決めて、package変数で詳細な(source,posなど)の要素は決めたいためです。

う〜ん例えばですが以下のようにする事でpackageという辞書の値を元にMainImageのPropertyが決まるようにはできます。

python

1# -*- coding: utf-8 -*- 2from kivy.app import App 3from kivy.lang import Builder 4from kivy.properties import DictProperty 5from kivy.factory import Factory # Factoryを使うとWidgetの種類毎にimport文を書かなくて済む 6 7 8Builder.load_string(r''' 9<MainFrame>: 10 MainImage: 11 package: 12 { 13 'image': 'data/logo/kivy-icon-512.png', # この画像は元からKivyが持っているので自分で用意する必要はない 14 } 15<MainImage>: 16 source: self.package['image'] 17''') 18 19 20class MainFrame(Factory.FloatLayout): 21 pass 22 23 24class MainImage(Factory.Image): 25 package = DictProperty(defaultvalue={ 26 'image': '', 27 }) 28 29 30class TestApp(App): 31 32 def build(self): 33 return MainFrame() 34 35 36if __name__ == '__main__': 37 TestApp().run()

ただ個人的にあまり利は感じないですが。

追記2

説明が足らなかったです。私は

python

1image = MainImage(...) 2image.source = '...'

とは書きましたが、このコードがそのまま使えるとは限らないです。このコードは単にKivyのPropertyをClass属性のように扱ってはいけない事を示したかっだけです。実際コード変更2(対応パターン)の修正後のコードはMainFrame.__init__()内でMainImageのInstanceを作ってすぐに捨てるという無意味な物になってます。

追記3

可能であればObjectPropertyなしでできないかというところです。

コード変更2(ObjectPropertyパターン)のコードを

python

1 2class MainFrame(FloatLayout): 3 4 def __init__(self, **kwargs): 5 super(MainFrame, self).__init__(**kwargs) 6 package = {"image": "./ss.png"} 7 self.ids.image1.set(**package)

text

1<MainFrame>: 2 MainImage: 3 id:image1

とすればできますよ。

投稿2018/07/23 21:19

編集2018/07/24 07:17
gottadiveintopy

総合スコア736

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

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

BlueBits

2018/07/23 23:43

>Instance経由 すみません。適当な書き方をしてしまいました。コードを修正いたしました。 >KV言語に直接書かない理由 イメージ的にテンプレートみたいな使い方でしょうか? 表示する要素(Image,Label)の大まかなものは決めて、package変数で詳細な(source,posなど)の要素は決めたいためです。実際は、使用するKV言語自体もpackage変数に含まれていて、そこからBuilderでKV言語を呼び出しています。
BlueBits

2018/07/24 03:45

ありがとうござます。 DictPropertyが一番近そうです。試してみます。 追記2の方は、確認もせず修正してしましました。おっしゃる通り見直したらひどいですね。 Propertyつかうところですね。
gottadiveintopy

2018/07/24 06:39 編集

> Propertyつかうところですね。 新しくInstanceを作ったのならadd_widget()でWidget階層に加えてあげないと表示されないですし、既にadd_widget()済みのInstanceを取得したのならPropertyに書き込むだけでいいですね。 幾つか教えて欲しいのですが packageは上のコードではリテラルで初期化されてますが、実際のプロジェクトではどのようにして中身が決まりますか? MainFrameは実際のプロジェクトでもrootのWidgetですか? MainImageはMainFrameの中に常に一つだけあって、他の場所では使う予定はないですか?
BlueBits

2018/07/24 06:40

コード2についてObjectProperty版に変更いたしました。こんな感じでしょうか。 1.実際はScreenManagerのScreen追加(add_widget)時にpackage変数を入れ込んでいます。 この場合は、add_widget(MainFrame (name="main", **package)) になる感じです。 2.MainFrameは実際はScreenWidget扱いになります。 3.基本的に各Screenに重複したClassは入れません。 こんな感じです。
gottadiveintopy

2018/07/24 07:31 編集

なるほど分かりました。 packageに入れる値の内MainImageに渡したい物は辞書を入れ子にするなりしてに分けた方がいいと思います。MainImageのposを指定したくて渡してしまうと、それがMainFrameのposの指定も兼ねる事になるので。
BlueBits

2018/07/24 10:34

>packageに入れる値の内MainImageに渡したい物は辞書を入れ子 そうですね、実際はそうなる形になるとおもいます。 また、DictPropertyについても試してみました。ある程度近い想像にはなりましたが一歩足りない形でした。 あとは問題ありそうな方法が、一番理想的な操作ができました。 glbal.py package ={} main.py import glbl ->glbl.packageで使う方法です。 コメント書いてる時点で色々と悩ましいです。 引用サイトより項目2.2 (http://www.albertgao.xyz/2017/05/06/how-to-share-variable-across-modules-in-python-or-kivy/)
gottadiveintopy

2018/07/24 22:44

正直私はまだBlueBitsさんのやりたい事を理解できてないのですが、解決したのなら良かったです。ではまた :-)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問