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

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

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

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

Python

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

Q&A

解決済

1回答

2230閲覧

クリックしたところにボタンを生成したい

hima-mura.

総合スコア42

Kivy

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

Python

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

0グッド

0クリップ

投稿2020/10/22 14:34

編集2020/10/27 11:02

クリック座標は取得できたが、それを利用できない。生成予定のボタンウィジェット(MakeButton)に初期値を与えてtouch_downイベントが起きたときにそこの座標(pos)の値を入れ込もうとしたが駄目だった。先ず初期値が設定できない(self.x=None,self.y=Noneでエラー吐く)、WidgetからMakeButtonへ参照できない。

from kivy.app import App from kivy.uix.floatlayout import FloatLayout from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.widget import Widget from kivy.factory import Factory from kivy.uix.boxlayout import BoxLayout class MyWidget(Widget): def on_touch_down(self,touch): # print(touch.pos) ??????.x=touch.pos[0] ??????.y=touch.pos[1] class MyBoxLayout(BoxLayout,FloatLayout): pass class MyLabel(Label,MyWidget): pass class MyButton(Button,MyWidget): pass class MakeButton(Button,MyWidget): def __init__(self,*kwargs): super(MakeButton,self).__init__(*kwargs) self.x=None #????????? self.y=None #????????? class P34App(App): def build(self): layout=MyBoxLayout() myl=MyLabel() myb=MyButton() layout.add_widget(myl) layout.add_widget(myb) return layout P34App().run() -----kivylanguage------ <MyBoxLayout>: orientation:"vertical" <MyLabel>: text:'Label' <MyButton>: text:'Button' <MakeButton>: text:'Success' 以下変更後のコードを追記します。(ちゃんと動きます。) from kivy.app import App from kivy.uix.floatlayout import FloatLayout from kivy.uix.label import Label from kivy.uix.button import Button class MyLayout(FloatLayout): def on_touch_down(self,touch): make_button=MakeButton() self.add_widget(make_button) make_button.pos=touch.pos class MyLabel(Label): pass class MyButton(Button): pass class MakeButton(Button): pass class TameshiApp(App): def build(self): layout=MyLayout() myl=MyLabel() myb=MyButton() layout.add_widget(myl) layout.add_widget(myb) return layout TameshiApp().run() ----------- <MyLabel>: text:'Label' pos:100,100 <MyButton>: text:'Button' pos:200,200 size_hint:[0.2,0.2] <MakeButton>: text:'Success' size_hint:[0.2,0.2]

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

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

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

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

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

guest

回答1

0

ベストアンサー

MakeButtonを定義するcodeはあっても作るcodeが何処にも無いです。作りたい時に以下のように作って参照を持っておいて

python

1 make_button = MakeButton(...) 2.add_widget(make_button)

その後

def on_touch_down(self, touch): make_button.pos = touch.pos

といった風に位置を設定してあげればいいです。(本当はここで座標変換もしておいたほうが変更に強いcodeになって良いのですが、話がややこしくなるのでしてません)。

それとwidgetの多重継承をしている理由は何ですか?class MyBoxLayout(BoxLayout,FloatLayout):は多分class MyBoxLayout(BoxLayout)と同じですし、MyWidgetに関しても他のwidgetと多重継承して使うのが目的ならMyWidget自体は何も継承しなくていいです。(class MyWidget:だけで良い。Kivyの慣例に従うならXXXBehaviorという名前にしておくと読み手にとって分かりやすいです)。

追記: widgetの派生classを作らないやり方

方法その1: Kv言語無し

python3

1from kivy.app import App 2 3 4class TameshiApp(App): 5 def build(self): 6 from kivy.factory import Factory as F 7 root = F.FloatLayout() 8 widget = F.Widget() 9 widget.bind(on_touch_down=lambda w, t: root.add_widget( 10 F.Button(text='Success', size_hint=(.2, .2, ), pos=t.pos))) 11 root.add_widget(widget) 12 root.add_widget(F.Label(text='Label', pos=(100, 100))) 13 root.add_widget(F.Button(text='Button', pos=(200, 200), size_hint=(.2, .2))) 14 return root 15 16TameshiApp().run()

方法その2: Kv言語有り

python3

1from kivy.app import App 2from kivy.lang import Builder 3 4 5KV_CODE = ''' 6#:import Button kivy.uix.button.Button 7 8FloatLayout: 9 Widget: 10 on_touch_down: root.add_widget(Button(text='Success', size_hint=(.2, .2, ), pos=args[1].pos)) 11 Label: 12 text: 'Label' 13 pos: 100, 100 14 Button: 15 text: 'Button' 16 pos: 200, 200 17 size_hint: .2, .2 18''' 19 20 21class TameshiApp(App): 22 def build(self): 23 return Builder.load_string(KV_CODE) 24 25TameshiApp().run()

投稿2020/10/24 03:43

編集2020/10/28 10:34
gottadiveintopy

総合スコア736

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

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

hima-mura.

2020/10/25 10:45

class P34Appの関数buildに(make_button=MakeButton(...))を付け加えましたが、__init__() takes 1 positional argument but 2 were givenのTypeErrorを吐きました。初期値はkvの方でtextしか与えていないのですが。 あとpos(座標)を使うときは勝手にFloatも必要と勘違いしておりました。ご指摘ありがとうございます。
gottadiveintopy

2020/10/26 03:40 編集

> __init__() takes 1 posi... *kwargs が間違いで正しくは **kwargs です。 > あとpos(座標)を使うときは... 使うというか任意の座標にwidgetを置きたいのならそのwidgetの親はFloatLayout(もちろんそのsub classも含む)が望ましいですね。上のcodeでいうなら 親.add_widget(make_button) の"親"がFloatLayout型。
hima-mura.

2020/10/26 08:11

class MyWidget: def on_touch_down(self,touch): make_button.pos=touch.pos class MyLayout(FloatLayout): pass class MyLabel(Label,MyWidget): pass class MyButton(Button,MyWidget): pass class MakeButton(Button,MyWidget): pass class TameshiApp(App): def build(self): layout=MyLayout() myl=MyLabel() myb=MyButton() make_button=MakeButton(...) layout.add_widget(myl) layout.add_widget(myb) layout.add_widget(make_button) return layout TameshiApp().run() ------------- <MyLabel>: text:'Label' pos:100,100 <MyButton>: text:'Button' pos:200,200 size_hint:[0.2,0.2] <MakeButton>: text:'Success' 上記はご指摘を受けて変更後のコードなんですが、make_button=MakeButton(...)のところで全く同じエラーが出ます。
hima-mura.

2020/10/26 08:13

クリックする以前に先ず立ち上げることができない状態です。
gottadiveintopy

2020/10/26 13:17 編集

MakeButton(...)の"..."は「初期化時に何の引数をhima-muraさんが与えたいのか私は知らないので省略します」という意味で書いたので特に与えたい引数が無いならMakeButton()としておいてください。後make_buttonはbuild()のlocal変数になっているのでon_touch_down()からは見えないです。
gottadiveintopy

2020/10/26 13:22

やりたい事はclickする度に新しくButtonを作ってclickした位置に置きたいというので合ってますか?だとしたらMakeButtonを作るのはon_touch_down()内であるべきですよ。それとMyWidgetの必要性が見えないので完全に無くしてMyLayoutにon_touch_down()を書いてみてください。
hima-mura.

2020/10/27 05:37

ご指摘通りにコーディングしたらできました。手間をかけさせてしまい申し訳ありません。ここまでお付き合いいただきありがとうございます。また機会がありましたらよろしくお願いします。
gottadiveintopy

2020/10/27 08:36

MyLayoutというclassは存在してなかったですね、ごめんなさい間違えました。 > ご指摘通りにコーディングしたらできました。 直した後のコードを追記できますか?コメント覧じゃなくて最初の投稿を編集する形で。(markdownを使ってほしいので)
hima-mura.

2020/10/27 11:04

最初の質問のところに追加する形で載せておきました。 再度よろしくお願いします。
gottadiveintopy

2020/10/28 10:37

良い感じですね。一応なんですがwidgetの派生を作らずに同じものを実装したらどうなるかを追記しました。知ってたらごめんなさい。
gottadiveintopy

2020/10/28 10:45

あ、hima-muraさんの書いた修正後のcodeなんですが、on_touch_down()を上書きしてるのでその上書きしたon_touch_down()内で最後にreturn super().on_touch_down(touch)としておいてください。on_touch_xxx()系のmethodを上書きした時は特に理由が無い限りそれが要るので。
hima-mura.

2020/10/29 11:08 編集

kv言語の方でprint(args)で中身を表示するとlist形式でオブジェクト情報が入っていたのでargs[1]は座標のvalueなんですね。argsをうまく使えば、gottadiveintopyさんみたいによりシンプルにコーディングできるのですね。kvなしのほうはFactoryを使うことで class XXXX:passをいちいちコーディングする必要がなくなるという認識であっていますか?こちらもシンプルで見やすいですね。重ね重ね質問してしまい申し訳ありません。大変勉強になりました。本当にありがとうございます。
gottadiveintopy

2020/10/29 11:37

Factoryはただimportの手間を省いているだけでclassの継承とは関係ないです。もし使わないと from kivy.uix.widget import Widget from kivy.uix.floatlayout import FloatLayout from kivy.uix.label import Label from kivy.uix.button import Button の4行を書くはめになるので。ただFactoryを使うとIDEが型が分からず入力補完をしてくれなくなるので、kivyに慣れるまでは薦めません。 argsにはeventに紐付けたcallback関数に渡った位置引数が入ってます。Kv言語無しの方のcodeでon_touch_downに紐付けているlambda関数の形式に直接対応していると考えて下さい。
hima-mura.

2020/10/29 12:47

そんな略仕方があるんですね。確かにあの長い常套句を省略できるのはいいですね。記憶の片隅に置いておきます。 正直に言うと勉強不足でlambda関数に対して明確なイメージを持てていないので理解できていない部分があるのですが、event毎にargsに引数が渡され(更新され)それをリスト形式で参照できるというイメージで留めておきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問