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

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

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

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

タブ

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

Python

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

Q&A

解決済

2回答

5429閲覧

PYTHONでTkinterのタブで移動前後のタブIdを知りたい。又移動後元のタブに戻りたい

akiteru

総合スコア21

Tkinter

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

タブ

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

Python

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

0グッド

0クリップ

投稿2020/03/28 02:51

Pythonでプログラムしています。プログラムはメイン(parent.py)と2つの子(child1.py、child2.py)にしています。
(1)目標はタブ移動時に元のタブの入力項に入力が無い場合に移動選択した移動先タブに移動せず元のタブに
戻りたい。
(2)TkinterのNOTEBOOKでタブを作りNOTEBOOKの<<NotebookTabChanged>>にgetTabIdを設定。
このgetTabId内でタブのIdを入手し、移動元の入力項の入力有無を判断し条件により移動元のタブに
戻る。
移動元のタブIdを変数old_tab_idに代入して、この変数をchild2.py内の他の自作関数でも使う
(3)当該コードを実行するとフォームは表示されますが下記エラーメッセージが表示されます。
対策を教えて下さい。又child2.py中のdef getTabId(self):の記述内容は上記エラー
改善後動作するのでしょうか。
変数old_tab_idの値はその他の関数でも使おうと思っています、getTabId(self)内で受け取った値は
その後の利用で有効なのでしょうか。
(4)<<NotebookTabChanged>>はタブ移動後に動作するように思われます。移動元タブが表示されており、
移動先タブが表示される前に必須入力条件等を判断し元のタブにとどまる様な処理は無いのでしょうか

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

File "c:\PyPost\child2.py", line 12, in getTabId wd1 = str.strip(self.entry1.get()) AttributeError: 'Event' object has no attribute 'entry1'エラーメッセージ

該当のソースコード

# ******* 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 # ********* タブ移動時の旧タブId(初期値設定) self.old_tab_id = 1 #********画面作成 ch1.create_notebook(self) self.pack() def quit(self, event=None): # 終了時の処理 self.master.destroy() application = tk.Tk() application.geometry("1000x600") 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("<<NotebookTabChanged>>",ch2.getTabId) self.nb.pack(expand=1, fill='both') # 入力タブ内の画面 self.entry1 = tk.Entry(self.tab1,font=("",14),justify="center",width=15) self.entry1.pack(side="left") # 出力タブ内の画面 self.entry2 = tk.Entry(self.tab2,font=("",14),justify="center",width=15) self.entry2.pack(side="left") # **** child2.py import tkinter as tk import tkinter.ttk as ttk import child1 as ch1 # ******各種アクション集 def getTabId(self): # タブ1,2の入力値を取得 wd1 = str.strip(self.entry1.get()) wd2 = str.strip(self.entry2.get()) # 移動後のタブナンバー取得 new_tab_id = self.nb.index(self.nb.select()) # 移動前後のタブ番号を入れ替えた後、元のタブに戻る dummy = self.old_tab_id self.old_tab_id = new_tab_id self.nb.select(self.dummy) # 入れ替え後のタブナンバー表示 print(dummy,self.old_tab_id) ソースコード

試したこと

ここに問題に対して試したことを記載してください。

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

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

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

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

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

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

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

guest

回答2

0

メソッドをクラス外の別ファイルへ別ける際の注意点について self の扱い
(クラス設計関係なしに単純にメソッドを別ファイルに別ける場合の例です)

(A) メソッドを別ファイルの関数に別ける

# child1.py def create_notebook(win): print("create_notebook", win.value) # child2.py def getTabId(win): print("getTabId", win.value) # parent.py from child1 import create_notebook from child2 import getTabId class MainWindow: def __init__(self): self.value = 10 # デモとしてこの値に別ファイルの関数からアクセスします create_notebook(self) # <-- インスタンス(self) を引数に渡す必要あり # getTabId(self) # win = MainWindow() とインスタンスを生成した場合、 # クラス内部からは `self` でアクセス # 外からアクセスする場合は、`win` と読み替える。

関数にする場合(現状のコードでは上の様な構成になってます)は、
インスタンスメソッドと区別する為に引数名 self を使わない方が
混乱が少なく成るかもしれません。

(B) 別ファイルで定義した関数をインスタンスメソッドにする方法

# child1.py def create_notebook(self): print("create_notebook", self.value) # child2.py def getTabId(self): print("getTabId", self.value) # parent.py class Parent: # クラス内に関数を置くことでインスタンスメソッドになります from child1 import create_notebook from child2 import getTabId def __init__(self): self.value = 11 self.create_notebook() # <-- インスタンスメソッドとして呼び出し可

デメリット有: IDEで child1, child2 を編集中に、メソッド一覧を所得出来ない。

(C) 多重継承

多重継承は一般的に複雑になりがちなので、紹介に留めておきますが、
継承により複数のクラスのメソッドを使えるようにもできます。

# child1.py class Child1Mixin: def create_notebook(self): print("create_notebook", self.value) # child2.py class Child2Mixin: def getTabId(self): print("getTabId", self.value) # parent.py from child1 import Child1Mixin from child2 import Child2Mixin class Parent(Child1Mixin, Child2Mixin): def __init__(self): super().__init__() self.value = 12 self.create_notebook()

投稿2020/03/28 11:07

teamikl

総合スコア8760

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

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

akiteru

2020/03/29 07:48

ご指摘ありがとうございました。「SELF」の巡礼状態ではサンプルファイルは「何気なく」理解できたつもりなのですが、いざ白紙を目の前にするとグルグル目が回る状態です。参考にして再トライします。
guest

0

ベストアンサー

(3) エラー原因について

通常の関数とインスタンスメソッドの違い。

ch2.getTabId() は引数名にselfを用いていますが、
クラスに属していない為、ch2.getTabId として呼ぶ場合、これは通常の関数になります。

期待通りに動かすには、ch1.create_notebook(self)としているように、
明示的にインスタンス(この場合 self) を渡す必要があります。

もう一点、NotebookTabChanged はイベントオブジェクト(event) を登録された関数へ渡します。
def getTabId(self)は、MainWindowクラスのインスタンスを期待しているところ、
別のイベントオブジェクトが渡される為にこのエラーが起こってます。

diff

1- self.nb.bind("<<NotebookTabChanged>>",ch2.getTabId) 2+ self.nb.bind("<<NotebookTabChanged>>", lambda event: ch2.getTabId(self))

解決策: event を読み捨て、getTabIdにselfを渡すことで解消できるはずです。
修正して動作確認を試みましたが、他のエラー。

getTabId() 内で select() した後に、
NotebookTabChanged が再発動し、すっと同関数内をループするようになりました。

投稿2020/03/28 05:04

teamikl

総合スコア8760

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

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

akiteru

2020/03/28 06:10

動作しました、ご教授ありがとうございました。現在の私の実力では「何故」うまく動作するのか理解力不足ですが。関数内での無限ループは理解でき改善しました。<<NotebookTabBeforeChanged>>みたいなタブ移動の前に動作するものが有るとありがたいのですが。
teamikl

2020/03/28 08:15

ややこしくなっているのは、ファイルの分割方法が少し特殊なせいかな、 「インスタンス メソッド」(クラス内に定義する関数)と同じような感覚で ch1,ch2 の create_notebook、getTabId といった通常の「関数」を書かれているからかもしれません。 詳しい解説は、ドキュメントの「クラス」辺りに(https://docs.python.org/ja/3/tutorial/classes.html) 長くなるので譲りますが、今回の問題に関するところでは インスタンスメソッドは、呼び出し時に self を引数に与える必要はない。 関数の場合は明示的に与える必要がある。といった違いがあります。 >タブ移動の前に動作するもの ドキュメント見たところ他のイベントは載っていませんでした。 別アプローチとしては、必須項目を埋めるまで次のタブを押せなくする(state="disabled") 等思いつきましたが。他は、タブ部分のクリックイベントを事前に捕まえる等でしょうか。
akiteru

2020/03/28 08:38

サジェッションありがとうございます。独学の為ファイルの分割等が上級者と違うかと思います。独学法の 分割ルールはメイン、画面設定と種々のアクションの3ファイルに分割しようと思うのですが?(単に長大なプログラムをワンファイルにすると、どこに何があるかわからない為です)。又「self」には、まいっています。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問