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

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

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

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

Python

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

Q&A

解決済

2回答

3714閲覧

Python (TkInter) PACKしたボタンを横いっぱいになるよう配置したいが、中央に配置されてしまっている

saya24

総合スコア222

Tkinter

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

Python

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

0グッド

0クリップ

投稿2020/06/01 01:00

編集2020/06/01 01:15

毎度毎度すみません、TkInterの画面デザインについてのご相談です。
こちらの記事にあるとおり、ボタンの配置を横いっぱいになるよう対処したいのですが、同じコードを適用しているはずも、目的が達成されません。
![絵
以下コードで★印のコメント部分が対応した部分ですが、その他の部分で 悪さをしているということでしょうか?

ご見解頂けたら 幸いです、よろしくお願いします。

Python

1from tkinter import * 2import tkinter.ttk as ttk 3import tkinter.scrolledtext as tksc 4import math 5 6class Apprication(ttk.Frame): 7 8 def __init__(self, app): 9 super().__init__(app) 10 self.pack() 11 12 btn1 = ttk.Button(self, text="Sub", command=self.openDialog) 13 btn1.bind('<Return>', self.openDialog) 14 btn1.pack(fill = 'x') #★横いっぱい(本当は縦いっぱいにも)にボタンを貼付けたい★ 15 btn1.focus_set() 16 17 btn2 = ttk.Button(self, text="Quit", command=app.quit) 18 btn2.bind('<Return>', lambda _: app.quit()) 19 btn2.pack(fill = 'x') #★横いっぱい(本当は縦いっぱいにも)にボタンを貼付けたい★ 20 21 self.menu() 22 23 24 25 def menu(self): 26 menu_top = Menu(app) 27 menu_file = Menu(menu_top, tearoff=False) 28 menu_open = Menu(menu_top, tearoff=False) 29 30 app.configure(menu=menu_top, bg="#F0FFFF") 31 32 menu_top.add_cascade (label='File(F)', menu=menu_file, underline=0) 33 34 menu_file.add_cascade(label='Open(O)', underline=0, menu=menu_open) 35 menu_open.add_command(label='Sub(S)', underline=0, command=self.openDialog) 36 menu_file.add_command(label='Quit(Q)',underline=0, command=app.quit) 37 38 39 40 41 42 # 子画面開く 43 def openDialog(self, event=None): 44 45 self.dialog = Toplevel(self) 46 self.dialog.title("Sub Menu") 47 48 #フォームサイズを実行端末から導き、ド真中に配置表示 49 lw = math.ceil(ww * 0.408) 50 lh = math.ceil(wh * 0.477) 51 self.dialog.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 52 53 self.dialog.configure(bg="#F0FFFF") 54 self.dialog.resizable(0,0) 55 self.dialog.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 56 57 58 # modalに 59 self.dialog.grab_set() 60 61 62 63 # 閉じるボタン 64 btn3 = Button(self.dialog, text='Quit', command=self.closeDialog, width=10, takefocus=1) 65 btn3.grid(row=5, column=10, pady=10, padx=(0,10)) 66 67 68 self.dialog.grid_rowconfigure(1, weight=1) 69 self.dialog.grid_rowconfigure(3, weight=1) 70 self.dialog.grid_columnconfigure(2, weight=1) 71 72 73 74 # 子画面閉じる 75 def closeDialog(self): 76 self.dialog.destroy() 77 78 79 80if __name__ == '__main__': 81 82 #世間でいうrootをappとしています 83 app = Tk() 84 85 #実行端末の画面サイズを取得 86 ww = app.winfo_screenwidth() 87 wh = app.winfo_screenheight() 88 89 app.update_idletasks() 90 91 #フォームサイズを実行端末から導き、ド真中に配置表示 92 lw = math.ceil(ww * 0.208) 93 lh = math.ceil(wh * 0.277) 94 app.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2)) ) 95 96 #タイトルを指定 97 app.title("Main Menu") 98 99 #フォームの最大化、×ボタン操作を無効化 100 app.resizable(0,0) 101 app.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 102 103 104 105 menu_top = Menu(app) 106 menu_file = Menu(menu_top, tearoff=False) 107 menu_open = Menu(menu_top, tearoff=False) 108 109 app.configure(menu=menu_top, bg="#F0FFFF") 110 111 menu_top.add_cascade (label='File(F)', menu=menu_file, underline=0) 112 113 menu_file.add_cascade(label='Open(O)', underline=0, menu=menu_open) 114 menu_open.add_command(label='Sub(S)', underline=0, command="app.openDialog") 115 menu_file.add_command(label='Quit(Q)',underline=0, command=app.quit) 116 117 118 # フレームを作成する 119 frame = Apprication(app) 120 # 格納したTkインスタンスのmainloopで画面を起こす 121 app.mainloop()

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

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

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

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

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

guest

回答2

0


今回のコード(必要な部分のみ抜き出したコード)

Toplevel(ウィンドウ) -> Frame -> Button

python

1import tkinter as tk 2from tkinter import ttk 3 4 5class Application(ttk.Frame): ## <-- Frameを継承 6 def __init__(self, master): 7 super().__init__(master) 8 self.pack(fill=tk.BOTH, expand=True) ## <-- 9 ttk.Button(self, text="button1").pack(fill=tk.BOTH, expand=True) 10 ttk.Button(self, text="button2").pack(fill=tk.BOTH, expand=True) 11 12 13if __name__ == '__main__': 14 root = tk.Tk() 15 root.geometry("400x400") 16 Application(root) 17 root.mainloop()

クラスを使わずに書くと以下のようになります。

Toplevel(ウィンドウ) -> Frame -> Button

python

1import tkinter as tk 2from tkinter import ttk 3 4 5if __name__ == '__main__': 6 root = tk.Tk() 7 root.geometry("400x400") 8 9 frame = ttk.Frame(root) 10 frame.pack(fill=tk.BOTH, expand=True) ## <-- ここが必要な理由について 11 12 ttk.Button(frame, text="button1").pack(fill=tk.BOTH, expand=True) 13 ttk.Button(frame, text="button2").pack(fill=tk.BOTH, expand=True) 14 15 root.mainloop()

継承したことにより、Frame の存在を忘れてしまってるように見受けられます。


tkinter.Tk を直接親とする場合。

Toplevel -> Button を直接配置。
恐らくこちらのコードのような動作を期待しているのでしょう

python

1import tkinter as tk 2from tkinter import ttk 3 4 5class Application(tk.Tk): ## <--- 継承元を直接ウィンドウにする 6 def __init__(self): 7 super().__init__() 8 ttk.Button(self, text="button1").pack(fill=tk.BOTH, expand=True) 9 ttk.Button(self, text="button2").pack(fill=tk.BOTH, expand=True) 10 11 12if __name__ == '__main__': 13 app = Application() 14 app.geometry("400x400") 15 app.mainloop()

まとめ: 下地という認識でいいのですが、

その下地の更に下にウィンドウという存在があり、
Frameもボタンと同様に、
その親となるウィジェットに拡張可能という事を伝える必要があります。

投稿2020/06/01 11:42

teamikl

総合スコア8664

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

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

saya24

2020/06/01 12:01

実に分かりやすい説明です!!今まで切り貼りでやってきても相応のものができてしまっていた為、構成を意識していなかったのですが 今回の説明で理解でき、問い合わせていた必要性についても十分納得できました。ありがとうごさいました。
teamikl

2020/06/02 05:18

フレームもしくは、ウィンドウの存在が要点だったみたいですね。 因みに余談ですが、コード量だけ見るとウィンドウを直接親にする方がシンプルに見えますが クラスの「再利用の観点」からは、双方とも課題があります。 - tkinter.Tk()を継承 -> 再利用の度に別のウィンドウが立ち上がる - クラス内で self.pack() -> packレイアウトでしか使えないクラスになる どちらも、再利用が不要であれば問題はありません が、 旨く設計し活用すると、コード量だけでなく時間・労力の節約にも繋がる部分です。 もし、このクラスを別の箇所でも流用したいみたいな事があれば、 以下の方法でクラスの再利用を検討して見て下さい。 >Frame を継承し、pack() や grid() は、クラス外・利用側に委ねる。
saya24

2020/06/02 05:56

今の私のレベルでは 正直価値あるアドバイスであっても 理解に苦しみ適用に躊躇してしまいますが、あとあと絶対に役に立つ情報に違いありません。無駄にしません、ありがとうございます!
guest

0

ベストアンサー

サンプルコード通りに横幅が広くならない原因:

親ウィジェットである Application(ttk.Frame) が self.pack() で、
広がる設定になってません。


解決策:

packのオプションでfill=BOTH を指定します。
縦にも広げる場合は追加で expand=True

python

1# Application class __init__ 内 2 3 for widget in [self, btn1, btn2]: 4 widget.pack(fill=BOTH, expand=True) 5

BOTH は from tkinter import * してる場合のコード例

イメージ説明

投稿2020/06/01 01:47

編集2020/06/01 01:48
teamikl

総合スコア8664

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

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

saya24

2020/06/01 04:04

いつもありがとうございます、目的が達成できました! 本当すみません
saya24

2020/06/01 05:52

目的は達成できておりますが、実はself.pack()までも fill=BOTH, expand=Trueにしなければいけない理由が分かりませんでした。 frameに貼りつけられるボタンwidgetは 貼り付けられる上では、という指定が功を奏すことが理解できrのですが.... selfは Applicationクラスのインスタンスということだけ認識していると、なんともイメージが湧きませんねぇ
teamikl

2020/06/01 10:41 編集

Tk() の変数も "app" としているので、そこもちょっと混同しそうですね。 app = Tk() frame = Application(app) self.pack()でもオプションが必要な理由は、 Frame を継承して Application クラスとしているのと、 pack()での幅拡張がデフォルトで有効なオプションではない為です。 ==== 一般的なtkinterのコードでは root = Tk() # もし Tk() が Application であれば pack()不要 frame = Frame(root) # 今回はここが Application相当 frame.pack(fill=BOTH, expand=True) root.mainloop()
saya24

2020/06/01 10:51

引き続きのご教示誠にありがとうございます。申し訳ありません、率直に言って理解に苦しんでいるのですが frameは 下地という考えでよろしいでしょうか? 私はその認識でいて その下地を 引き延ばすような設定がなぜ 必要なの?? ということで混乱してしまっています。 下地という認識が間違いでしょうか....
teamikl

2020/06/01 11:09 編集

下地という認識で良いのですが、返答は >幅拡張がデフォルトで有効なオプションではない為 例えば仮に、100x100 の範囲を下地とします。 その中に横幅一杯になるボタンを設置するとしましょう。 そのボタンの横幅は、下地の幅いっぱいとなる100 になります。 Frame に幅拡張の指定オプションがないと、広がる範囲はその枠内にとどまります。 もう一点、認識に違いがあるとしたら その下地(Frame)はウィンドウ(Toplevel)自体ではありません。 Tk() 内で暗黙的に作られる為、意識することはないかもしれませんが、 Frame は Toplevelウィンドウ内に作られている為、 Toplevel -> Frame -> Button という順にレイアウトの制限を受けます。 つまりこれが、button だけでなく、Frame も pack のオプションが必要な理由です。 もしボタンが Frame ではなく、ウィンドウに直接配置されていれば 恐らく想定されてるような動作で、self.pack()は不要になります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問