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

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

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

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

Python

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

Q&A

解決済

1回答

3835閲覧

Python、Kivyを使用。pyファイル上でButtonを記述する際の書き方がわからない

garudo

総合スコア14

Kivy

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

Python

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

0グッド

0クリップ

投稿2018/11/07 09:10

編集2018/11/07 09:16

プログラム初心者です。

現在Pythonを用いてコードを書いているのですが、Buttonをクリックした時の処理を記述するときに上手く実行できません。Kivyを用いてGUIを作成中ですが、Buttonを動的に生成する必要があります。

そこでkvファイルにはButtonを記述せず、pyファイル上で記述したいのです。

Button自体は生成されるのですが、どうもon_pressの部分でエラーが出ます。

エラー文
AssertionError: None is not callable

どのように記述すれば良いのでしょうか?ご教授ください。
動的に生成するpyファイル

import os from kivy.uix.boxlayout import BoxLayout from kivy.uix.gridlayout import GridLayout from kivy.uix.popup import Popup from kivy.uix.label import Label from kivy.uix.button import Button from kivy.core.window import Window from kivy.uix.video import Video from kivy.uix.image import Image from kivy.uix.videoplayer import VideoPlayer import kivy.core.video import pyglet from kivy.factory import Factory from kivy.lang import Builder class MovieChoseWindow(BoxLayout): def __init__(self, **kwargs): super(MovieChoseWindow, self).__init__(**kwargs) self.title = '動画選び' video_file_name_list=os.listdir("./MovieChose/") for i in range(len(video_file_name_list)): videoPath = str(video_file_name_list[i]) self.ReadeMovieFile(video_file_name_list[i]) def ReadeMovieFile(self,videoPath): print("ReadeMovieFileを実行") layout = self.ids.boxlayout button = Factory.Button( id = str(videoPath), background_normal = './MovieChose/' + str(videoPath), on_press = self.buttonClicked(str(videoPath)) ) print(str(videoPath)) layout.add_widget(button) print("ReadeMovieFileでbuttonを追加") def buttonClicked(self,videoPath): print("buttonClickedを実行") self.PlayMovie(videoPath) def buttonClickedTest(self): print("buttonClickedを実行") videoPath = "testmove.png" self.PlayMovie(videoPath) def PlayMovie(self,videoPath): print("playMovieを実行") text = str(videoPath) window = pyglet.window.Window(width=960, height=540) videoPath = text.replace('png', 'mp4') if(videoPath is not None): print(videoPath) video = pyglet.media.load(str(videoPath)) player = pyglet.media.Player() player.queue(video) @window.event def on_draw(): try: player.get_texture().blit(0,0) except: window.close() player.play() try: pyglet.app.run() except: print("動画終了")

対応するkvファイル

<Window1@BoxLayout> 変更 <MovieChoseWindow> orientation: "vertical" ActionBar: ActionView: ActionPrevious: title: 'MovieChoseWindow' with_previous: False ActionButton: text: '切り替え' on_press: print("change disp window 1"); app.root.change_disp() BoxLayout: id: boxlayout

ちなみに、on_pressを記述しなければ問題なくButtonは生成されます。

また、
on_press = self.buttonClicked(str(videoPath))
の部分を
on_press = self.buttonClicked
と書き換えると実行はされますが、メソッドに引数を渡したいので本来望む動きではありません。

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

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

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

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

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

guest

回答1

0

ベストアンサー

on_press には callable を渡す必要がありますが、お試しいただいた

python

1on_press = self.buttonClicked(str(videoPath))

だと、その行で buttonClicked() が実行されてしまいその戻り値( None )が on_press に渡されます。その結果ボタンクリック時に該当のエラーが発生しているようです(エラー文「 None is not callable 」の None というのはおそらく buttonClicked() の戻り値のことです)。

解決策はいくつかあるかと思いますが、 lambda 式というのはご存知ですか?ご存知であれば lambda を使う形が最も手っ取り早いかと思います。

patch

1- on_press = self.buttonClicked(str(videoPath)) 2+ on_press = lambda x: self.buttonClicked(str(videoPath))

次のように書いてもよいかもしれません。

python

1on_press = lambda: self.buttonClicked(str(videoPath))

ぐぐると同様の質問・回答が Stack Overflow にあるのが見つかりました。そちらもご参考になるものと思います。

追記: (将来同じ問題にあたってこのページに来られた方のために)

上のポイントの他に以下の部分も変更されたら無事ご解決に至ったとのことでした。

patch

1- button = Factory.Button( 2+ button = Button(

投稿2018/11/07 14:05

編集2018/11/09 05:02
gh640

総合スコア1407

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

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

garudo

2018/11/08 02:27

ご回答ありがとうございます。 提示されたlamda式を試してみました。実行途中にエラーが発生することはなく、画面は正常に表示されました。しかし、Buttonを押してもon_pressに指定しているメソッドが走ってくれません。 on_press = lambda x: self.buttonClicked(str(videoPath))の前後で確認用のコードを記述しているのできちんと走っているようですが、buttonClicked()メソッド内での確認用の処理が動きていていないのです。 この問題について、理由など思い当たりますでしょうか??
gh640

2018/11/08 13:33

> この問題について、理由など思い当たりますでしょうか?? そうですね・・・ぱっと思い当たる理由がちょっとありません。 理由はわかりませんが、問題の切り分けとしては a) `on_press` が効いていないのか、それとも b) `buttonClicked()` が効いていないのか、を見極めると解決に向けて前進するのではないかと思います。例えば on_press = lambda x: print('clicked') とした場合に clicked が出力されるかどうかをお試しになるとよいかもしれません。 (リファレンスを見ずに言っています)あとはあくまでも勘ですが `Factory.Button` でボタンを生成する形が合っているのかな、どうなのかな、というのは少し気になりました。 `kivy.uix.button.Button` を使って生成するのとは挙動が違っていてあえてそれを使われているのですか?
garudo

2018/11/09 01:33

>(リファレンスを見ずに言っています)あとはあくまでも勘ですが `Factory.Button` でボタンを生成する形が合っているのかな、どうなのかな、というのは少し気になりました。 こちらの指摘に関しましては、私自身リファレンスを読み込めていませんでした。 uix.buttonのButton生成を使用したところ設計通りに動かすことができました!! 私の質問に丁寧に対応していただきありがとうございます。 とても助かりました!!
gh640

2018/11/09 05:04

そうでしたか!それはよかったです :) ご丁寧にご報告くださりありがとうございました。 (以後こちらのページに来られる方のために、教えてくださったポイントに関して回答の本文に追記をしました)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問