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

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

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

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Tkinter

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

Q&A

解決済

1回答

4543閲覧

Canvasのサイズを自動的に変化させたい

yamatan

総合スコア8

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Tkinter

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

0グッド

0クリップ

投稿2021/10/13 09:24

実現したいこと

tkinterのCanvasを子とするgridで配置したFrameを適切なサイズにしたいです。言葉で説明するのが難しいので以下の画像を見て頂きたいです。

1つ目の画像(図1)ではメインウィンドウがgridで配置した4つのFrameで構成されています。左上、左下、右上にはTextウィジェットがwidth=80, height=30の同サイズで配置されています。右下のFrame(以下Canvasフレームと呼びます)はCanvasウィジェットをもつFrameとボタンウィジェットを持つFrameとの2つのFrameで構成されたFrameがgridで4つ配置されています。

図1の画像のウィンドウでは、どのTextウィジェットも同サイズで、Canvasフレームの大きさはそれらのTextウィジェットの大きさに合わせるようなサイズになっており、ボタンウィジェットもそれに応じてサイズが大きくなっています。しかし、Canvasのサイズが小さいのでウィンドウサイズ自体はこのサイズで固定して、Canvasをもつフレームの大きさを大きくしたいです。Canvasには一応fill=X, expand=Trueを設定したいますが、Canvasのサイズは大きくならずボタンのサイズが大きくなっています。

そこで、Canvasのサイズを指定せずに実行したところ2つ目の画像(図2)となりました。Canvasのサイズ自体は大きくなりましたが、その変化に引っ張られて左下のTextウィジェットのサイズが変化して、メインウィンドウのサイズが縦に長くなっています。

理想としては、ウィンドウのサイズは図1のままに、その中でCanvasの大きさを出来る限り大きくしたいです。
説明が分かりずらいかもしれません。
分かりずらい箇所はご指摘をお願いします。

イメージ説明
図1

イメージ説明
図2

該当のソースコード

ソースコードでは、rootにTextウィジェットを含むフレーム(左上、左下、右上)とCanvasを含むフレーム(右下)をgirdで配置しています。右下のフレームでは、Canvasを含むフレーム4つががgridで配置されています。

Python

1from tkinter import * 2import random 3 4def createWordList(cvs): 5 # word list 6 space = 10 7 size = 15 8 h = 0 9 w = 80 10 words = ['フリー', '緑色', '7年保存', 'ビスケット', '電卓', '災害備蓄用', '放送禁止用語', 'キャプテンアメリカザファーストアベンジャー', '日本初と', '史上最強'] 11 # ワードリスト設定 12 cnt = 0 13 for i in range(len(words)): 14 word = words[i] 15 new_word = word 16 if len(word) > 5: 17 new_word = '' 18 for j in range(len(word)): 19 cnt += 1 20 if cnt % 6 == 0: 21 new_word += '\n' 22 new_word += word[j] 23 cnt = 0 24 words[i] = new_word 25 words_list = [] 26 for i in range(10): 27 for word in words: 28 words_list.append(word) 29 words_list.append('last word') 30 N = len(words_list) 31 # テキストサイズの取得 32 bbox_h_list = [] 33 cnt = 0 34 for i in range(N): 35 id = cvs.create_text(0, 0, text=words_list[i], font=('', size)) 36 x0, y0, x1, y1 = cvs.bbox(id) 37 bbox_h_list.append(y1 - y0) 38 # キャンバスクリア 39 cvs.delete('all') 40 # テキスト描画 41 items = [] 42 pre_y = 0 43 pre_h = 0 44 cnt = 0 45 for i in range(N): 46 _h = bbox_h_list[i] 47 _y = space + _h / 2 + pre_y + pre_h / 2 48 cnt += 1 49 item = cvs.create_text(w, _y, text=words_list[i], font=('', size), tag=f'word:{words_list[i]}') 50 items.append(item) 51 pre_y = _y 52 pre_h = bbox_h_list[i] 53 x0, y0, x1, y1 = cvs.bbox(item) 54 # パラメータ 55 min_h = min(bbox_h_list) 56 rH = min_h * 1.0 57 xmax = 0 58 ymax = 0 59 for item in items: 60 x0, y0, x1, y1 = cvs.bbox(item) 61 if xmax < x1: 62 xmax = x1 63 if ymax < y1: 64 ymax = y1 65 # バー配置 66 BM = 100 67 tbx = 15 68 for i in range(N): 69 item = items[i] 70 x0, y0, x1, y1 = cvs.bbox(item) 71 p = random.random() 72 _h = y1 - y0 73 yc = y1 - (_h / 2) 74 rec = cvs.create_rectangle(xmax + tbx, yc - rH / 2, xmax + tbx + p * BM, yc + rH / 2, fill='red', tag='rec:') 75 items.append(rec) 76 # スクロール範囲 77 cvs.configure(scrollregion=(0,0, xmax + tbx + BM + 20, ymax + 20)) 78 return items 79 80def createWordListFrame(master, k): 81 wl_f = Frame(master) 82 wl_f.grid() 83 84 cvs_f = Frame(wl_f) 85 cvs_f.pack(side=TOP, fill=BOTH, expand=True) 86 87 cvs = Canvas(cvs_f, bg='#FFFFFF', scrollregion=(0,0,500,5000)) 88 hbar = Scrollbar(cvs_f, orient=HORIZONTAL) 89 hbar.pack(side=BOTTOM, fill=X) 90 hbar.config(command=cvs.xview) 91 vbar = Scrollbar(cvs_f, orient=VERTICAL) 92 vbar.pack(side=RIGHT, fill=Y) 93 vbar.config(command=cvs.yview) 94 # キャンバスサイズ 95 cvs.config(width=5, height=25) 96 cvs.config(xscrollcommand=hbar.set, yscrollcommand=vbar.set) 97 cvs.pack(side=TOP, expand=True, fill=BOTH) 98 items_list.append(createWordList(cvs)) 99 cvs.bind("<MouseWheel>", lambda event, cvs=cvs: mouseYScroll(event, cvs)) 100 cvs.bind('<1>', lambda event, cvs=cvs: click(event, cvs, k)) 101 102 bt_f = Frame(wl_f, bg='blue') 103 bt_f.pack(side=BOTTOM, fill=BOTH, expand=True) 104 bt = Button(bt_f, text='clear', command= lambda cvs=cvs: click2(cvs)) 105 bt.pack(side=TOP, anchor=CENTER, expand=True, fill=BOTH) 106 107 return wl_f, cvs 108 109def WLarrange(): 110 global WLframe 111 global wl_fs 112 global fN 113 row = 0 114 clm = 0 115 for i in range(fN): 116 wl_f = wl_fs[i] 117 wl_f.grid(row=row, column=clm, sticky=NSEW) 118 WLframe.grid_rowconfigure(row, weight=1) 119 WLframe.grid_columnconfigure(clm, weight=1) 120 clm += 1 121 if clm == fN // 2 + fN % 2: 122 row += 1 123 clm = 0 124 125def setText(f): 126 txt = Text(f, width=80, height=30) 127 txt.pack(side=TOP, expand=True, fill=BOTH) 128 129def mouseYScroll(event, cvs): 130 if event.delta > 0: 131 cvs.yview_scroll(-1, 'units') 132 elif event.delta < 0: 133 cvs.yview_scroll(1, 'units') 134 135def click(event, cvs, k): 136 global items_list 137 items = items_list[k] 138 x, y = cvs.canvasx(event.x), cvs.canvasy(event.y) 139 objs = [obj for obj in cvs.find_overlapping(x,y,x,y)] 140 tgs = [cvs.itemcget(obj, 'tags') for obj in objs] 141 if len(objs) > 0: 142 for item in items: 143 if 'word:' in cvs.itemcget(item, 'tags'): 144 cvs.itemconfig(item, fill='black') 145 cvs.itemconfig(item, font=('Helvetica', 15)) 146 for obj in objs: 147 if 'word:' in cvs.itemcget(item, 'tags'): 148 cvs.itemconfig(obj, fill='blue') 149 cvs.itemconfig(obj, font=('Helvetica', 15, 'bold')) 150 151def click2(cvs): 152 cvs.delete('all') 153 154root=Tk() 155 156BTFrame1 = Frame(root) 157BTFrame1.grid(row=0, column=0, sticky=NSEW) 158setText(BTFrame1) 159 160BTFrame2 = Frame(root) 161BTFrame2.grid(row=0, column=1, sticky=NSEW) 162setText(BTFrame2) 163 164BTFrame3 = Frame(root) 165setText(BTFrame3) 166BTFrame3.grid(row=1, column=0, sticky=NSEW) 167 168WLframe = Frame(root) 169WLframe.grid(row=1, column=1, sticky=NSEW) 170items_list = [] 171cvss = [] 172wl_fs = [] 173fN = 4 174for i in range(fN): 175 wl_f, cvs = createWordListFrame(WLframe, i) 176 wl_fs.append(wl_f) 177 cvss.append(cvs) 178WLarrange() 179 180root.grid_rowconfigure(0, weight=1) 181root.grid_rowconfigure(1, weight=1) 182root.grid_columnconfigure(0, weight=1) 183root.grid_columnconfigure(1, weight=1) 184 185root.mainloop()

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

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

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

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

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

guest

回答1

0

ベストアンサー

ボタンを配置するフレームが余分に作られているので、
ボタンに対するレイアウト指定は、そのフレーム内でしか有効になりません。

bt.pack(side=TOP, anchor=CENTER, expand=False) とすると
ボタンは意図通りの大きさになりますが、下地の青いフレームが見えてしまいます。

レイアウトを外側に伝搬させるには、親となるフレームを伸縮可能にする必要がありますが、
packやgridのオプション指定が複雑になる為、

不要なフレームを省いて、キャンバスを配置しているフレームに直接配置して見て下さい。

wl_f: Frame cvs_f: Frame cvs: Canvas hbar: Scrollbar vbar: Scrollbar bt_f: Frame <-- ここを省く bt: Button

diff

1- bt_f = Frame(wl_f, bg='blue') 2- bt_f.pack(side=BOTTOM, fill=BOTH, expand=True) 3 4- bt = Button(bt_f, text='clear', command= lambda cvs=cvs: click2(cvs)) 5- bt.pack(side=TOP, anchor=CENTER, expand=True, fill=BOTH) 6 7# 変更点2か所 Buttonの親ウィジェット, expand True -> False 8 9+ bt = Button(wl_f, text='clear', command= lambda cvs=cvs: click2(cvs)) 10+ bt.pack(side=TOP, anchor=CENTER, expand=False, fill=BOTH) 11 12 13

投稿2021/10/14 10:59

teamikl

総合スコア8760

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

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

yamatan

2021/11/14 05:20

上手くいきました。 ありがとうございます。 むやみにフレームを配置するのも気を付けなけらば行けませんね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問