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

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

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

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

タブ

コンテンツの上下左右に参照用のメニューを設けることで、複数の要素やページの表示を可能にするユーザーインターフェイスパターンのこと。メニューをクリックすると、一つの要素が可視化され、他の要素は見えなくなる。

Python

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

Q&A

解決済

1回答

1029閲覧

python TKinterでフォームアプリを作成中。タブ移動時に何らかの処理をさせるファイルを分割するとエラーとなる

akiteru

総合スコア18

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

タブ

コンテンツの上下左右に参照用のメニューを設けることで、複数の要素やページの表示を可能にするユーザーインターフェイスパターンのこと。メニューをクリックすると、一つの要素が可視化され、他の要素は見えなくなる。

Python

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

0グッド

0クリップ

投稿2020/04/02 05:43

前提・実現したいこと

Python,TKinterでフォームアプリを作成中です。タブ移動後に何らかの処理をするためにマウス左ボタンリリース時の<ButtonRelease-1>で動作するプログラム(onefile.py)を作りました。これは正常に動作します。
これを親子のparent.py,child1.py,child2.pyに分割したところ下記のエラーが発生します。対策をご教授ください。「self」、「event」は理解不足の状態です

ここに質問の内容を詳しく書いてください。
(例)PHP(CakePHP)で●●なシステムを作っています。
■■な機能を実装中に以下のエラーメッセージが発生しました。

発生している問題・エラーメッセージ

Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\akiteru\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__ return self.func(*args) TypeError: callback() missing 1 required positional argument: 'event'エラーメッセージ

該当のソースコード

正常に動作する一ファイルでの記述(onefile.py) # ******* onefile.py import tkinter as tk import tkinter.ttk as ttk class MainWindow(ttk.Frame): def __init__(self, parent): super(MainWindow, self).__init__(parent) self.parent = parent #********画面作成 self.create_notebook() self.pack() def create_notebook(self): self.nb = ttk.Notebook(self,width=800, height=400) # タブの作成 self.tab1 = tk.Frame(self.nb) self.tab2 = tk.Frame(self.nb) self.nb.add(self.tab1, text='入力', padding=3) self.nb.add(self.tab2, text='出力', padding=3) # ********タアブ移動時タブのId入手 self.nb.bind('<ButtonRelease-1> ',self.callback) self.nb.pack(expand=1, fill='both') def callback(self,event): # *******移動後のタブIDを表示 new_tab_id = self.nb.index(self.nb.select()) print(new_tab_id) def quit(self, event=None): # 終了時の処理 self.master.destroy() application = tk.Tk() application.geometry("500x500") application.title('PyPost') window = MainWindow(application) application.protocol('WM_DELETE_WINDOW', window.quit) application.mainloop() 親子に分割したファイル(parent.py、 child1.py、 cild2.py) # ******* parent.py import tkinter as tk import tkinter.ttk as ttk import child1 as ch1 import child2 as ch2 class MainWindow(ttk.Frame): def __init__(self, parent): super(MainWindow, self).__init__(parent) self.parent = parent #********画面作成 ch1.create_notebook(self) self.pack() def quit(self, event=None): # 終了時の処理 self.master.destroy() application = tk.Tk() application.geometry("500x500") application.title('PyPost') window = MainWindow(application) application.protocol('WM_DELETE_WINDOW', window.quit) application.mainloop() #**** child1.py import tkinter as tk import tkinter.ttk as ttk import child2 as ch2 # **********画面作成 def create_notebook(self): self.nb = ttk.Notebook(self,width=800, height=400) # タブの作成 self.tab1 = tk.Frame(self.nb) self.tab2 = tk.Frame(self.nb) self.nb.add(self.tab1, text='入力', padding=3) self.nb.add(self.tab2, text='出力', padding=3) # ********タアブ移動時タブのId入手 self.nb.bind('<ButtonRelease-1> ',ch2.callback) self.nb.pack(expand=1, fill='both') # **** child2.py import tkinter as tk import tkinter.ttk as ttk # ******各種アクション集 def callback(self,event): new_tab_id = self.nb.index(self.nb.select()) print(new_tab_id)

試したこと

ここに問題に対して試したことを記載してください。
child2.py内の【def callback(self,event):】のeventを削除し【「def callback(self):」】とすると下記エラーメッセージとなります

Traceback (most recent call last):
File "C:\Users\akiteru\AppData\Local\Programs\Python\Python38\lib\tkinter_init_.py", line 1883, in call
return self.func(*args)
File "c:\PyPost\child2.py", line 7, in callback
new_tab_id = self.nb.index(self.nb.select())
AttributeError: 'Event' object has no attribute 'nb'

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

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

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

guest

回答1

0

ベストアンサー

self の理解が重要です。

この分割方法の場合、create_notebook(), callbacxk() は
クラスの外側に置かれるので「通常の関数」になってしまいます。
(その為、呼び出し側では明示的に self を渡している)

クラス内で定義された関数は、「インスタンスメソッド」となり、
通常の関数とは呼び出す引数が異なります。
(ここのself が解り難いのだと思います)

まずは、単純な解決策
取り合えず現状のコードを動かす方法。

python

1self.nb.bind('<ButtonRelease-1> ', lambda event: ch2.callback(self,event))

callback 側は def callback(self,event): で受けます。

追記: 問題点について

  • メソッドをクラスの外に出し、通常の関数として使う場合、引数 self が必要
  • bind で登録した関数には、呼び出し時に引数 event が渡される

と、引数が一致しない為に起こっています。

lambda event: ch2.callback(self, event) は関数に直すと

def on_click(event): """ やっていることは、bindで呼び出された時の引数 (event) と、ch2.callback が必要とする引数 (self, evnent) の橋渡しです。 """ # self は外側のスコープから参照 return ch2.callback(self, event) self.nb.bind('<ButtonRelease-1> ', on_click)

という風に、def callback(self, event): に引数を合わせる為の式になります。

def を使ってますが、関数内で使って大丈夫です。
self.nb.bind の直前に、インデントは揃えて。


改善策: 分割方法について、

単一のファイルに書かれた状態から

  • create_notebook() を child1.py へ
  • callback() を child2.py に分ける とした場合
  • parent.py では

python

1 2class MainWindow(ttk.Frame): 3 4 from child1 import create_notebook 5 from child2 import callback 6

このようにクラス内部で import すると、
create_notebook, callback は「インスタンスメソッド」となり、
self を渡したりする所のコードを変えることなく、動きます。

※ クラス外でインポートしてから、クラス内の変数に代入でもいいです。
方法は前回・前々回の回答のコードを参照してください。

投稿2020/04/02 06:26

編集2020/04/02 09:28
teamikl

総合スコア8664

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

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

akiteru

2020/04/02 08:23

前回に続きフォローありがとうございます。前回の無限ループの矛盾から逃れるため、トリガーを変えたら本件の壁でした。又安易に第1案を採用し逃れることとしました。この安易が前回もあったlambda文のおまじないを理解せずの状態です。
teamikl

2020/04/02 09:26

記述はlambdaを使うと簡潔なのだけど、 やはり難しそうな感じになってしまいますよね。 lambda を使わない方法も追記しましたので、少しでも理解の助けになれば。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問