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

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

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

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

Python

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

Q&A

解決済

1回答

4357閲覧

TkInter: Treeview全体幅が可変してしまう事象を回避したい

saya24

総合スコア221

Tkinter

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

Python

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

0グッド

0クリップ

投稿2021/12/11 03:35

編集2021/12/18 04:14

ツリービュ全体幅の設定は現実的できでないとのアドバイスを頂き、簡素化したコードを作成し確認を進める流れとなりまして、今回簡易版かつ動作できるコードをご用意しました。
1
2
3

python

1import tkinter as tk 2import tkinter.ttk as ttk 3import math 4import os 5 6def resource_path(relative_path): 7 try: 8 base_path = sys._MEIPASS 9 except Exception: 10 base_path = os.path.abspath(".") 11 12 return os.path.join(base_path, relative_path) 13 14def adjust_windowsize1(root): 15 ww = root.winfo_screenwidth() 16 wh = root.winfo_screenheight() 17 18 lw = math.ceil(ww * 0.3208) 19 lh = math.ceil(wh * 0.477) 20 21 root.geometry(str(lw)+"x"+str(lh)+"+"+str(int(ww/2-lw/2))+"+"+str(int(wh/2-lh/2))) 22 23def generate_frame(root): 24 def change_frame(frame): 25 frame.tkraise() 26 27 def force_entrytree1(): 28 dict_columns = {'提供データ': ['固定値', '機器[A1]', '国名[B1]', '運送[C1]', '区分[D1]', '出荷[E1]', 'D/O[F1]', '顧客[G1]', '業者[H1]', '注番[I1]', '商品[J1]', 'サブ[K1]', 'ロケ[L1]', '数量[M1]', 'ロット[N1]', '有効期限[O1]']} 29 30 tree1.delete(*tree1.get_children()) 31 for p in dict_columns.keys(): 32 parent = tree1.insert("", tk.END, text=p,) 33 for m in dict_columns[p]: 34 child = tree1.insert(parent, tk.END, text=m,) 35 36 def force_entrytree3(): 37 dict_reccolumns = {'554347829': ['商品', 'J1', 'そのまま', '', '製品', '', 1], '608825980': ['商品', 'J1', '変換', 1, '品目コード', '', 2], '744751990': ['商品', 'J1', '変換', 2, '品名', '', 3], '832969584': ['ロット', 'N1', 'そのまま', '', 'ロット', '', 4], '929827175': ['有効期限', 'O1', 'そのまま', '', '使用期限', '', 5], '054158659': ['固定値', '', '', '', 'ラベル大', 'ごにょごにょ', 6], '824305845': ['固定値', '', '', '', 'ラベル小', 'ごにょごにょ', 7], '955828413': ['割当数', 'M1', 'そのまま', '', '入荷数量', '', 8], '432056575': ['固定値', '', '', '', 'ラベル枚数', 'ごにょごにょ', 9], '717725311': ['商品', 'J1', '変換', 3, '5', '', 10]} 38 39 lst_header = [] 40 for i in dict_reccolumns.keys(): 41 lst_header.append(i) 42 43 tree3["columns"] = lst_header 44 for i in tree3["columns"]: 45 tree3.heading(i, text="ABC") 46 47 val = [] 48 faddress = "" 49 ftype = "" 50 fconvno = "" 51 fvalue = "" 52 for i in dict_reccolumns.keys(): 53 if dict_reccolumns[i][1] == "": 54 faddress = "□" 55 else: 56 faddress = dict_reccolumns[i][1] 57 58 if dict_reccolumns[i][2] == "": 59 ftype = "□" 60 else: 61 ftype = str(dict_reccolumns[i][2]) 62 63 if dict_reccolumns[i][3] == "": 64 fconvno = "□" 65 else: 66 fconvno = str(dict_reccolumns[i][3]) 67 68 if dict_reccolumns[i][5] == "": 69 fvalue = "□" 70 else: 71 fvalue = dict_reccolumns[i][5] 72 73 val.append(faddress + "/" + ftype + "/" + fconvno + "/" + fvalue) 74 75 tree3.delete(*tree3.get_children()) 76 77 if len(dict_reccolumns.keys()) > 0: 78 tree3.insert("", tk.END, values=val) 79 for i in tree3["columns"]: 80 tree3.column(i, anchor=tk.CENTER) 81 82 style = ttk.Style() 83 style.theme_use('winnative') 84 style.configure("TButton", font=("Arial", 16)) 85 style.configure("A.TButton", font=("Arial", 12)) 86 style.configure("LTREE.Treeview", background="black", foreground="white", fieldbackground="black", rowheight=25,) 87 style.configure("UTREE.Treeview", background="white", foreground="black", fieldbackground="white", rowheight=25,) 88 89 style.configure("Treeview.Heading", background="green", foreground="white", rowheight=25,) 90 style.configure("INQ.Treeview.Heading", background="green", foreground="white", rowheight=25,) 91 # 92 frmMain = ttk.Frame(root, name="frmMain") 93 frmMain.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 94 95 btn_IOMenu = ttk.Button(frmMain, text = "あ", command=lambda: change_frame(frmIOMenu)) 96 btn_IOMenu.pack(fill = tk.BOTH, expand=True) 97 btn_IOMenu.bind('<Return>', lambda a: change_frame(frmIOMenu)) 98 99 btn_ConvMenu = ttk.Button(frmMain, text = "い") 100 btn_ConvMenu.pack(fill = tk.BOTH, expand=True) 101 102 btn_RunMenu = ttk.Button(frmMain, text = "う") 103 btn_RunMenu.pack(fill = tk.BOTH, expand=True) 104 105 btn_Close = ttk.Button(frmMain, text = "終了", command=root.destroy) 106 btn_Close.pack(fill = tk.BOTH, expand=True) 107 btn_Close.bind('<Return>', lambda a : root.destroy()) 108 109 # 110 frmIOMenu = ttk.Frame(root, name="frmIOMenu") 111 frmIOMenu.grid_rowconfigure([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], weight=1) 112 frmIOMenu.grid_columnconfigure([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], weight=1, minsize=40) 113 frmIOMenu.grid(row=0, column=0, sticky=tk.E + tk.W + tk.N + tk.S) 114 115 cmbox_RecNo = ttk.Combobox(frmIOMenu, height=3, justify=tk.CENTER) 116 cmbox_RecNo.grid(row=0, column=0, columnspan=2, sticky=tk.N + tk.S + tk.E + tk.W, pady=(10,0), padx=(10,0)) 117 118 ent_RecName = ttk.Entry(frmIOMenu, font=("Arial", 16)) 119 ent_RecName.grid(row=0, column=2, columnspan=8, sticky=tk.E + tk.W + tk.N + tk.S, pady=(10,0), padx=(0,10)) 120 121 btn_AssignInputFile = ttk.Button(frmIOMenu, text = "え", command=lambda : force_entrytree1()) 122 btn_AssignInputFile.grid(row=1, column=0, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=(10,0)) 123 124 ent_InputPath = ttk.Entry(frmIOMenu, font=("Arial", 16)) 125 ent_InputPath.grid(row=1, column=2, columnspan=8, sticky=tk.E + tk.W + tk.N + tk.S, padx=(0,10)) 126 127 btn_AssignOutputFile = ttk.Button(frmIOMenu, text = "お") 128 btn_AssignOutputFile.grid(row=2, column=0, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=(10,0)) 129 130 ent_OutputPath = ttk.Entry(frmIOMenu, font=("Arial", 16)) 131 ent_OutputPath.grid(row=2, column=2, columnspan=8, sticky=tk.E + tk.W + tk.N + tk.S, padx=(0,10)) 132 133 lab_ConvNo = ttk.Label(frmIOMenu, text="け", font=("Arial", 12)) 134 lab_ConvNo.grid(row=3, column=4, columnspan=2, sticky=tk.E + tk.N + tk.S) 135 136 ent_Sheet = ttk.Entry(frmIOMenu, font=("Arial", 16)) 137 ent_Sheet.grid(row=3, column=6, columnspan=4, sticky=tk.E + tk.W + tk.N + tk.S, padx=(0,10)) 138 139 tws = root.winfo_width() * 0.4594 140 tree1 = ttk.Treeview(frmIOMenu, show="tree", style="LTREE.Treeview") 141 tree1.grid(row=4, column=0, rowspan=4, columnspan=4, sticky=tk.E + tk.W + tk.N + tk.S, pady=(5,0), padx=(10,0)) 142 143 ybar1 = ttk.Scrollbar(frmIOMenu, orient=tk.VERTICAL, command=tree1.yview) 144 ybar1.grid(row=4, column=3, rowspan=4, sticky=tk.N + tk.S + tk.E, pady=(5,0), padx=(10,0)) 145 tree1.config(yscrollcommand=lambda f, l: ybar1.set(f, l)) 146 147 btn_AddColumn = ttk.Button(frmIOMenu, text = "→") 148 btn_AddColumn.grid(row=4, column=4, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S, pady=(5,0)) 149 150 lstbox = tk.Listbox(frmIOMenu, bg="black", exportselection=False, foreground="white", font=("Arial", 14)) 151 lstbox.grid(row=4, column=6, rowspan=4, columnspan=4, sticky=tk.E + tk.W + tk.N + tk.S, pady=(5,0), padx=(0,10)) 152 153 ybar2 = ttk.Scrollbar(frmIOMenu, orient=tk.VERTICAL, command=lstbox.yview) 154 ybar2.grid(row=4, column=9, rowspan=4, sticky=tk.N + tk.S + tk.E, pady=(5,0), padx=(0,10)) 155 lstbox.config(yscrollcommand=lambda f, l: ybar2.set(f, l)) 156 157 xbar2 = ttk.Scrollbar(frmIOMenu, orient=tk.HORIZONTAL, command=lstbox.xview) 158 xbar2.grid(row=7, column=6, columnspan=4, sticky=tk.S + tk.E + tk.W, padx=(0,10)) 159 lstbox.config(xscrollcommand=lambda f, l: xbar2.set(f, l)) 160 161 btn_Up = ttk.Button(frmIOMenu, text = "↑") 162 btn_Up.grid(row=5, column=4, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S) 163 164 btn_Down = ttk.Button(frmIOMenu, text = "↓") 165 btn_Down.grid(row=6, column=4, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S) 166 167 btn_Cancel = ttk.Button(frmIOMenu, text = "←") 168 btn_Cancel.grid(row=7, column=4, columnspan=2, sticky=tk.E + tk.W + tk.N+ tk.S) 169 170 lab_Type = ttk.Label(frmIOMenu, text="こ") 171 lab_Type.grid(row=8, column=0, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S, padx=(0,10)) 172 173 cmbox_Type = ttk.Combobox(frmIOMenu, height=3, font=("Arial", 16)) 174 cmbox_Type.grid(row=9, column=0, columnspan=2, sticky=tk.N + tk.S + tk.E + tk.W, padx=(10, 0)) 175 176 177 tree3 = ttk.Treeview(frmIOMenu, show="headings", height=1, style="UTREE.Treeview") 178 tree3.grid(row=10, column=0, columnspan=9, sticky=tk.E + tk.W, padx=(10,0), pady=(5,0)) 179 180 btn_Add = ttk.Button(frmIOMenu, text = "せ", command=lambda : force_entrytree3()) 181 btn_Add.grid(row=10, column=9, rowspan=2, sticky=tk.N + tk.S + tk.E+ tk.W, padx=(0,10), pady=(5,0)) 182 183 xbar3 = ttk.Scrollbar(frmIOMenu, orient=tk.HORIZONTAL, command=tree3.xview) 184 xbar3.grid(row=11, column=0, columnspan=9, sticky=tk.N + tk.S + tk.E + tk.W, padx=(10,0)) 185 tree3.config(xscrollcommand=lambda f, l: xbar3.set(f, l)) 186 187 188 189 btn_ReturnMenu = ttk.Button(frmIOMenu, text = "閉じる", command=lambda: change_frame(frmMain)) 190 btn_ReturnMenu.grid(row=12, column=8, columnspan=2, sticky=tk.E + tk.W + tk.N + tk.S, pady=(0,10), padx=(0,10)) 191 192 193 frmMain.tkraise() 194 195 196if __name__ == "__main__": 197 root = tk.Tk() 198 199 adjust_windowsize1(root) 200 root.title("ボタン小さくなる") 201 202 root.grid_columnconfigure([0,1, 2, 3, 4, 5, 6, 7, 8, 9], weight=1) 203 root.grid_rowconfigure([0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], weight=1) 204 205 root.resizable(0,0) 206 root.protocol('WM_DELETE_WINDOW', (lambda: 'pass')()) 207 208 root["cursor"] = "hand2" 209 210 generate_frame(root) 211 212 root.mainloop() 213

コード含め 本文10,000文字がリミットの掲載なので 主旨が短文となってしまいました。すみません

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

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

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

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

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

teamikl

2021/12/20 12:22

コードは全文掲載ではなく「問題の再現に必要な部分」としましょう。 一部切抜きだと、問題が再現できず情報不足となりますが、質問に掲載するコードは 「コードをコピペして実行可能」「問題を再現できる」最少のコードというのを目途にして見て下さい。 ページ遷移他は、今回の問題には不要な部分ですので、 単一のフレームでレイアウトを組んでも、同じ問題が再現するはずです。
saya24

2021/12/21 01:01

以降気をつけます。 動作し事象が再現されることに固執し また何が悪さしているのか分からず 広範囲な掲載になってしまいました、申し訳ありません。
teamikl

2021/12/21 03:01

どの範囲まで必要かはケース次第になるので、判断が難しいですよね。 「問題の再現」は必須条件で、 問題の解決に必要な情報が含まれてないと解決できないので、 ここに関しては、最優先で問題ありません。 不要な部分の削除した最小限のコードにするというのは、 その次のステップ位に考えて下さい。 (今回は、字数制限に引っ掛かった事に対してのアドバイス) コード規模が大きくなってきた場合の、行数制限対策もありますが、 単純に、数百行のコードよりは、十数行のコードの方が容易になるので、 問題範囲を絞り込む事は、自身で問題解決する為にも必要なデバッグ作業です。
guest

回答1

0

ベストアンサー

Tkinter の文字を表示するウィジェットでの width は文字数で、height が行数だったりします。
(実際の画面上での長さは、フォントサイズの影響を受ける点は注意)

質問に掲載のコードでは、ピクセルでのサイズ計算なので、
仮に width が有効であったとしても、意図通りにはなりません。

Canvas や Frame での width, height はピクセル単位での指定なので、
Frame 内に Treeview を配置して、Frame に width を設定する事で幅設定自体はできますが、

リサイズされるのが問題なのであれば、Treeview のレイアウトを可変ではなくする事が問題の焦点です。
pack/grid での width/height 指定したウィジェットの配置は、
伸縮オプションが有効な場合、レイアウトの自動調整により上書きされてしまいます。

  • pack であれば、expand=False
  • grid であれば、grid_columnconfigure 及び、sticky の設定、等

Treeview の幅設定自体は、各 column に width を設定する方法を推奨します。

投稿2021/12/11 15:05

teamikl

総合スコア8664

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

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

saya24

2021/12/12 00:34 編集

いつもお世話になっております。teamiklさんに頼りっぱなしで申し訳ありません。 当該WIDGETの貼り付け元のFrameに grid_columnconfigureで weight=1を 全カラムに設定しています。それでも、伸縮可能になってしまったので あれれ と思い... なお、 ウィンドウのインスタンス(root)は スクリーンサイズから求めた一定の定数を乗じ、かつリサイズと×ボタンの無効化を施して どの端末で実行されようと 同じアプリケーションイメージになるよう工夫しています。 各column に width を設定する方法が 推奨される理由は Treeview自体の幅を設定することが 以外に難しいということですね?  たしかに print文で tree1.winfo_width() を tree1へ内容が格納される前・後で確認してみると 同じ数値が表示されてしまったのです、増減していない!!!
teamikl

2021/12/12 03:26 編集

>当該WIDGETの貼り付け元のFrameに grid_columnconfigureで weight=1を 全カラムに設定しています。それでも、伸縮可能になってしまったので あれれ と思い... weight=1 は伸縮可能になります。weight=0 が伸縮しない設定です。 > スクリーンサイズから求めた一定の定数を乗じ、 ここは回答に書いたとおり、スクリーンサイズはピクセル単位での数値です、 tkinter の文字を扱うウィジェットは文字数単位での指定なので、単位が不一致です。 (実際のサイズは文字数 x フォントサイズの横幅) > 各column に width を設定する方法が 推奨される理由は Treeview自体の幅を設定することが 以外に難しいということですね?  まず、tkinter の文字を扱うウィジェットでは、width が文字数となっているのを念頭に、 Treeview は文字表示領域の他にも、ツリー表示時のアイコンや字下げが発生する為、 単純に文字数指定という訳にはいきません。 Frame に配置する方法では、不用意にウィジェットの構造が複雑化してしまいます。 (管理すべきウィジェットの数が増え・階層が深くなり、後々保守が面倒になる。 横幅が見切れる等、付随して起こる別の問題への対応も必要になってきます) 例外としては、grid レイアウト中で他のセルは可変にしたいけど、特定の行のみ固定にしたい場合 grid ではセル単位の設定は出来ずに row/column 単位ですので、中間のFrame を配置(Frameは可変) その中に伸縮を不可にした Treeview を配置する、というケースは考えられます。 実際の解決策は、ウィジェットの構造やレイアウト次第なので、 まずは、以下のような極力シンプルな構造のレイアウトで、質問用に提示するプログラムを作り、 同じ問題が再現するかどうかを試してみてください。 - 1行目: Label - 2行目: Treeview1 | Button | Treeview2 - 3行目: Button 閉じる
saya24

2021/12/13 11:05

画面下部の採用ボタンの幅が やはり 横のツリービューの格納内容次第で、狭くなってしまっていることに気がつきました。 いやぁ 頭が痛い…一体何が悪いんだか。 なかなかアドバイス通りのことを試せず、進展をえず申し訳ありません。
saya24

2021/12/19 05:58 編集

提示したコードの、tree3(下段のツリービュ)へ 内容格納する部分最後で for i in tree3["columns"]: tree3.column(i, width=100, stretch='no') の記述を行い カラム単位に幅を設定しても当該ツリービュ右横の "せ"ボタンの幅が縮んでしまうのです。このボタンの幅をどうにか固定になるようにしたいです。 当該ボタンに width=10と設定しても ボタン幅が変わってしまいました。一体どうすればボタンの幅を固定にできるのでしょうか
teamikl

2021/12/20 12:42 編集

再度確認ですが >weight=1を 全カラムに設定しています。それでも、伸縮可能になってしまったので weight=1 は伸縮可能な設定ですが、ここの認識は大丈夫ですか? >一体どうすればボタンの幅を固定にできるのでしょうか pack/grid を使う場合は、レイアウトが自動で計算されるので ウィジェット自体に対するサイズの直接指定 (width=10等) はできません。 「ウィジェットの幅」と、「レイアウトの表示可能領域の幅」があり、 調整可能な後者は、gridのオプションでサイズ等を制御します。 今回の場合であれば、レイアウトの表示可能領域を - 伸縮不可能にする weight=0 - 最小幅を設定する gridのminsize オプション といった対策が考えられます。 # 「せ」ボタン表示領域の最小幅を設定。数値は要調整。 frmIOMenu.grid_columnconfigure(9, minsize=130) 但し、レイアウトの設定は行列単位での設定ですので、 特定のセルのみを設定したい場合は、単一のgridでは難しいかもしれません。 フレームを入れ子にする等の工夫が必要になってきます。
saya24

2021/12/21 02:01

いつも大変お世話になっております。…神ってる対応、誠にありがとうございます。 ご提示のコードを早速試し なるほどと感触を掴んで、結局0カラムと9カラムめに、別のminimumサイズを設定しました。思いどおりTreeviewに内容格納されても、デザインを固定することができました。 お尋ねの weight=0と1の違いを認識しているかですが、伸縮可能か否かの設定であるも、ウィンドウのresizableオプションを0, 0にしている今回の取組みでは 関係しない話しに位置付けていました。 これ、間違いですかね? 毎回毎回すみません、極力同じ質問をしないよう 御見解を読み直して画面設計の開発に自信を持てるようになりたいと思います。 今は 本当苦手な意識があるのですが。HTML・CSSしかり… 重ねて一連のご支援ありがとうございました。
teamikl

2021/12/21 04:09 編集

> ウィンドウのresizableオプションを0, 0にしている今回の取組みでは 関係しない話しに位置付けていました。 後から何か表示要素を追加した場合等、 ウィンドウのリサイズ以外にも、ウィジェットのリサイズが発生する事はあります。 今回の件とは関係ありませんが、 resize オプションは、ユーザのウィンドウ・リサイズ操作を無効にするものなので、 中身のウィジェットのリサイズの結果、ウィンドウサイズが変わることもあります。 import tkinter as tk root = tk.Tk() root.resizable(0, 0) label = tk.Label(root) label.pack() # ボタンをクリックすると、追加された文字幅に合わせてラベルとウィンドウが伸縮 button = tk.Button(root, text="OK") button.config(command=lambda: label.config(text="LONG TEXT")) button.pack() root.mainloop() こういった場合であれば、tk.Label(root, width=10) の様な ウィジェットに対する width 指定(一定幅の確保)は有効です。 packは伸縮可能にしてないのにどうして大きくなるの?と思われるかもしれませんが、 恐らくこの辺りがレイアウトの難しい所で、 「ウィジェット自身のサイズ」と、レイアウトの管理する「伸縮可能領域のサイズ」の区別が重要になってきます。 ※ ラベルは「伸縮してない状態の最小幅」で表示されるが、 最初の状態が文字数0で字数が増えた為「ウィジェット自身のサイズ」は増える。 pack,grid による自動サイズ調整は、他のウィジェットにリサイズが発生した場合に、 レイアウトの幅調整で伸縮するかどうかを制御します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問