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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

Q&A

1回答

2810閲覧

Python3 Tkinter ソースコードの書き方の質問

person

総合スコア224

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

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

0グッド

3クリップ

投稿2021/01/08 15:58

編集2021/01/10 02:20

次のアプリを作成しました。

起動するとウィンドウが出ます。
ウィンドウのOpenボタンを押すと、ポップアップウィンドウが表示されます。
ポップアップウィンドウにはテキストボックスがあり、Enterボタンを押すとテキストボックスの文字列を控えてポップアップを閉じます。
メインウィンドウのDispボタンを押すと、先程の文字列を表示します。

ソースコード

Python

1from tkinter import ttk 2import tkinter as tk 3 4 5class Main(tk.Tk): 6 def __init__(self): 7 self.str = "" 8 super().__init__() 9 self.geometry("400x300+0+0") 10 self.title("Main") 11 self.view_create() 12 13 def view_create(self): 14 self.button1 = ttk.Button(self, text="Open", command=self.open) 15 self.button1.grid() 16 self.button2 = ttk.Button(self, text="Disp", command=self.disp) 17 self.button2.grid() 18 19 def open(self): 20 self.tl = tk.Toplevel() 21 self.tl.geometry("200x100+0+0") 22 self.tl.title("toplevel") 23 self.tl.attributes("-topmost", True) 24 self.tl.resizable(False, False) 25 self.tl.grab_set() 26 self.tl.transient(self) 27 self.entry = ttk.Entry(self.tl) 28 self.entry.grid() 29 self.entry.insert("end", self.str) 30 self.button3 = ttk.Button(self.tl, text="Enter", command=self.enter) 31 self.button3.grid() 32 self.tl.protocol("WM_DELETE_WINDOW", self.close) 33 34 def disp(self): 35 str = self.str 36 if str != "": 37 print(str) 38 39 def close(self): 40 self.tl.grab_release() 41 self.tl.destroy() 42 43 def enter(self): 44 self.str = self.entry.get() 45 self.close() 46 47def main(): 48 app = Main() 49 app.mainloop() 50 51if __name__ == "__main__": 52 main()

以下質問です。

① 上のコードは、tkinterのイベントコールバック関数を全て インスタンスメソッド(self.***) にしていますが、実際そうしたほうがいいですか?それともインスタンスメソッドの中にメソッドを作るほうがいいですか?

Python

1def pushed(self): 2 def close(tl): 3 tl.destroy() 4 self.tl = tk.Toplevel() 5 self.tl.protocol("WM_DELETE_WINDOW", lambda:close(self.tl))

② 一番上のコードではボタンやエントリにself.をつけていますが、self.をむやみにいろんな変数につけない方が良いとかってありますか?self.を使わず引数で渡す手もありますが、引数の括弧の中がごちゃごちゃしているのって、個人的に見た目汚いようなイメージなので上のコードではself.を使いました。

③ メインウィンドウとポップアップウィンドウを同じクラスの中で処理していますが、実際このままでいいですか?それとも分けたほうがいいですか?

④ 配置するウィジェットが多いとウィジェット配置の記述(上のコードで言うview_create())が膨大になりますが、そういう場合はウィジェットのイベントアクション(上のコードで言うopen()、disp()、close()、enter())は別のクラスやファイルに記述したほうがいいですか?それとも、全部同じファイルまたは同じクラスに記述したほうがいいですか?

回答お願いします。

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

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

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

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

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

guest

回答1

0

厳しいかもしれませんが、率直な感想です。

Pythonの観点から

ソースコードの書き方は綺麗です。
ただ、PythonはC言語と違ってmain関数は必要としません。main関数を見ると、C言語になぜmain関数があるかを分かっていないのだろうなという印象を与えます。

オブジェクト指向の観点から

クラスというのは、複数のインスタンスの機能の共通化をはかるもので、それを使いやすくするために継承(インヘリタンス)があります。
Mainというクラスのインスタンスを複数作って利用するようには見えません。
、MainがTkから継承しているのはmainloopだけです。
ここでクラスを作る必然性はなにもありません。

また、オブジェクトには、内部情報を外部から保護して、余分なバグを発生させないという目的もありますが、全てをひとつのオブジェクトにしてしまうと、オブジェクト指向プログラミングの大きな利点の一つが全く生かされません。

クラスを作ればオブジェクト指向だとお考えのように見えますが、そうではありません。

GUIプログラミングの観点から

GUIでは処理ロジック(Model)と画面制御(View)を分離したコーディングが主流です。MVC(Model View Controller)とかMVP(Model View Presenter)とかMVVM(Model View ViewModel)とかはいずれも処理ロジックと画面制御を分離しています。

TKinterは、画面制御のライブラリとユーザ入力のライブラリの集まりですが、それらははっきりと区別されています。モデルは別に作ることを前提としています。
personさんのプログラムは、画面制御用のクラスであるTkの派生クラスを作ってその中に処理ロジックを入れ、ユーザ入力も入れてごちゃごちゃです。

使ってみた感想

なぜ、Displayを押したときコンソールに出力されるかが謎でした。

質問への回答

① 上のコードは、tkinterのイベントコールバック関数を全て インスタンスメソッド(self.***) にしていますが、実際そうしたほうがいいですか?それともインスタンスメソッドの中にメソッドを作るほうがいいですか?

インスタンスメソッドにする必然性はありません。

② 一番上のコードではボタンやエントリにself.をつけていますが、self.をむやみにいろんな変数につけない方が良いとかってありますか?

インスタンス変数にするしないかは、データ保護の観点で判断するものです。多い少ないで決めるものではありません。

③ メインウィンドウとポップアップウィンドウを同じクラスの中で処理していますが、実際このままでいいですか?それとも分けたほうがいいですか?

分けるべきです。

④ウィジェットのイベントアクション(上のコードで言うopen()、disp()、close()、enter())は別のクラスやファイルに記述したほうがいいですか?

クラスを作ることがオブジェクト指向プログラミングの本質ではありません。

今後に向けて

要素技術を学ぶのと平行して、オブジェクト指向プログラミングとかGUIプログラミングの本質について勉強することをお勧めします。

投稿2021/01/10 06:06

ppaul

総合スコア24670

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

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

person

2021/01/11 13:52 編集

回答ありがとうございます。 > クラスを作ればオブジェクト指向だとお考えのように見えますが、そうではありません。 申し訳ないです。そもそもクラス化した理由としては、別の関数でウィジェットを操作する際に引数に毎回変数を書くのが面倒だと感じたからです。self.をつければ、self以外の引数が必要ないので。完成したものがオブジェクト指向かどうかについては正直眼中になかったです。 > なぜ、Displayを押したときコンソールに出力されるかが謎でした。 Printのほうが良かったでしょうか?(名称の話?) あくまでサンプルとして作ったので動作自体に深い意味はありません。 >> ① > インスタンスメソッドにする必然性はありません。 必然性はないというのは、やっても問題はないと解釈してもいいですか? >> ② > インスタンス変数にするしないかは、データ保護の観点で判断するものです。多い少ないで決めるものではありません。 データの保護が必要ないというのは、何らかの処理をするための一時変数などがそれにあたりますか?またデータの保護が必要というのは、外部からその変数にアクセスするような場合ですか(ウィジェット操作など)? >> ③ > 分けるべきです。 分ける場合、それぞれのクラスでtk.Tkとtk.Toplevelを継承するような形にしますか?それとも特に継承は必要としませんか? >> ④ > クラスを作ることがオブジェクト指向プログラミングの本質ではありません。 オブジェクト指向のソースコードとかネットにあるやつを参考に考え直します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問