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

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

ただいまの
回答率

89.25%

【Python】TKINTERによるオブジェクト指向でのコードの書き方

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 67

temtemtemtem

score 6

python3でオブジェクト指向の勉強をしています。
TKINTERを使ってアプリを作成したいのですが、FrameやNotebookを複数つかう際にClassの構造をどのように構築したらいいのかがわかりません。
未熟者なため書き方があっているかわかりませんが私のイメージでは下記の通りです。
tk.Tk()
→tk.Canvas()
→scrollbarを作成
→tk.Frame()
→tk.Canvasの上にtk.Frame()を配置
→ttk.Notebook(Frame)
→tk.Frameの上にnotebookを配置してタブを6つ追加
→各タブについてウィジェットを追加していくコードを書く

手続き型の作成はできているのですがオブジェクト指向で書くことが出来ません。
ご指導のほどよろしくお願いします。

手続き型では下記のように記入しました。

GUIの作成

import tkinter as tk
import tkinter.ttk as ttk

root = tk.Tk()
root.geometry('2000x1500')
root.title('テスト')

Canvas Widget を生成
canvas = tk.Canvas(root, width=2000, height=1500)

Scrollbar を生成して配置
bar_y = tk.Scrollbar(root, orient=tk.VERTICAL)
bar_y.pack(side=tk.RIGHT, fill=tk.Y)
bar_y.config(command=canvas.yview)

bar_x = tk.Scrollbar(root, orient=tk.HORIZONTAL)
bar_x.pack(side=tk.BOTTOM, fill=tk.X)
bar_x.config(command=canvas.xview)

Canvas Widget を配置
canvas.config(yscrollcommand=bar_y.set, xscrollcommand=bar_x.set)
canvas.config(scrollregion=(0, 0, 4000, 5000))  # スクロール範囲
canvas.pack(fill=tk.BOTH, expand=tk.YES)

Frame Widgetを 生成
frame = tk.Frame(canvas)

Frame Widgetを Canvas Widget上に配置
canvas.create_window((0, 0), window=frame, anchor=tk.NW, width=canvas.cget('width'))

notebook = ttk.Notebook(frame)

tab1 = tk.Frame(notebook)
tab2 = tk.Frame(notebook)
tab3 = tk.Frame(notebook)
tab4 = tk.Frame(notebook)
tab5 = tk.Frame(notebook)
tab6 = tk.Frame(notebook)

notebook.add(tab1, text='tab1')
notebook.add(tab2, text='tab2')
notebook.add(tab3, text='tab3')
notebook.add(tab4, text='tab4')
notebook.add(tab5, text='tab5')
notebook.add(tab6, text='tab6')
notebook.pack(expand=True, fill='both')

オブジェクト指向での記入

import tkinter as tk
import tkinter.ttk as ttk

class Application(tk.Canvas):
def init(self, master=None):
super().init(master, width=2000, height=1000)
self.master.title('CBD')

Scrollbar を生成して配置
self.bar_y = tk.Scrollbar(self, orient=tk.VERTICAL)
self.bar_y.pack(side=tk.RIGHT, fill=tk.Y)
self.bar_y.config(command=self.yview)

self.bar_x = tk.Scrollbar(self, orient=tk.HORIZONTAL)
self.bar_x.pack(side=tk.BOTTOM, fill=tk.X)
self.bar_x.config(command=self.xview)

self.config(yscrollcommand=self.bar_y.set, xscrollcommand=self.bar_x.set)
self.config(scrollregion=(0, 0, 4000, 5000))  スクロール範囲
self.pack(fill=tk.BOTH, expand=tk.YES)

self.frame = tk.Frame(self)
self.create_window((0, 0), window=self.frame, anchor=tk.NW, width=self.cget('width'))

nootebook = ttk.Notebook(self.frame)
Note(master=nootebook)

class Note(nootebook):

def init(self, master=None):
super().init(master)
self.master.title('window')

tab1 = tk.Frame(self.master)
self.add(tab1, text="tab1")
Tab1(master=tab1)

tab2 = tk.Frame(self.master)
self.add(tab2, text="tab2")
Tab2(master=tab2)

self._quit_outside_widget()
self.pack()

def main():
root = tk.Tk()
app = Application(master=root)  # Inherit
app.mainloop()

if name == "main":
main()

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • teamikl

    2020/05/23 11:37

    コードのレイアウトが崩れてるので、
    markdown を使ってコードの編集をお願いします。
    バッククォート3つで囲みます

    ```python

    ここにコードを貼り付け

    ```

    また、コメントとコードが混在してるので、
    出来れば実行可能な形に直して下さい。

    キャンセル

回答 1

checkベストアンサー

0

nootebook = ttk.Notebook(self.frame)
Note(master=nootebook)

class Note(nootebook):

元コードの notebook の辺りがわからないので、
質問はその辺りについてかなと思いましたが、インデントが把握できないので、
一般的な、「クラスを使った書き方」として回答します。

質問の意図が、「オブジェクト指向を活かした設計」だった場合、
現状では ScrolledCanvas の再利用位しか恩恵はありません。
(関数で書いた場合とあまり替わりがない)


import tkinter as tk
from tkinter import ttk


def init_notebook(notebook):
    """
    クラス化しても良かったのですが、あまり再利用することがない処理のため関数にしました。

    無闇にクラス化すると、"self"をたくさん書かなくてはいけなくなったりします。
    """
    for num in [1, 2, 3, 4, 5, 6]:
        tab = ttk.Frame(notebook)
        name = "tab{}".format(num)
        notebook.add(tab, text=name)

    return notebook


class ScrolledCanvas(tk.Canvas):
    """
    スクロールバー付きのキャンバスは再利用の機会は高そうなので、個別のクラスに纏める。

    スクロールを付けるクラスの拡張方法は、他にもあり
    異なるアプローチですが ScrolledText のソース等も参考にしてみて下さい。
    """

    def __init__(self, master, *args, **kw):
        super().__init__(master, *args, **kw)

        bar_y = ttk.Scrollbar(self, orient=tk.VERTICAL)
        bar_y.pack(side=tk.RIGHT, fill=tk.Y)
        bar_y.config(command=self.yview)

        bar_x = ttk.Scrollbar(self, orient=tk.HORIZONTAL)
        bar_x.pack(side=tk.BOTTOM, fill=tk.X)
        bar_x.config(command=self.yview)

        self.config(
            yscrollcommand=bar_y.set,
            xscrollcommand=bar_x.set,
            scrollregion=self.bbox("all"),
        )
        # ※ ウィジェットをクラス化する際の注意点
        # ここでこのクラスのコンテナである canvas の pack()/grid() 等のレイアウトは呼びません。
        # 例えば grid() を呼び出すと、pack() では使えないクラスになってしまいます。


class MainWindow(ttk.Frame):
    def __init__(self, master):
        super().__init__(master)

        # XXX:
        # 例えば、ここで master.title() を呼び出すと、親にはToplevelしか取れなくなるので
        # クラス内では親のメソッドを呼び出すのは控えます。
        # そうすることで、Toplevel以外の親を持つことができ
        # このクラス自体を他のクラスの部品の一部として扱えるようになります。

        canvas = ScrolledCanvas(self, width=200, height=200)
        canvas.pack(fill=tk.BOTH, expand=True) # <- 配置は利用側で決める

        notebook = init_notebook(ttk.Notebook(self))
        notebook.pack(fill=tk.BOTH, expand=True)

        canvas.create_window((10, 10),
            window=notebook, anchor=tk.NW, width=canvas.cget('width'))

        self.canvas = canvas
        self.notebook = notebook


def main():
    root = tk.Tk()
    root.geometry("800x800")
    root.title("テスト")

    win = MainWindow(root)
    win.pack(fill=tk.BOTH, expand=True)

    root.mainloop()


if __name__ == '__main__':
    main()

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/23 23:25

    質問の表記に不備があり申し訳ありませんでした。
    また、不備がある中回答いただきありがとうございました。
    回答いただいた内容で私が達成したかったことが完全に表現されました。
    クラス化はプログラムを書く上で再利用する必要があるときのみにとどめておくことが良いのですね。全てのコメントが目から鱗で感動いたしました。本当にありがとうございます。

    キャンセル

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

  • ただいまの回答率 89.25%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる