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

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

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

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

Python

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

Q&A

解決済

1回答

837閲覧

縦スクロールバーの設定について

shinobuKouno

総合スコア31

Tkinter

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

Python

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

0グッド

1クリップ

投稿2022/10/29 08:53

前提

帳票を作っており、タイトルバー(表題)と内容(名称)があり、縦スクロールと横スクロールをつけたいです。

実現したいこと

縦スクロールではタイトルバーはスクロールせず内容の表だけスクロールし、
横スクロールではタイトルバーと内容の表が同じくスクロールする表を作りたい。
ここに実現したいことを箇条書きで書いてください。

発生している問題・エラーメッセージ

↓のコードだとキャンバスの内容が小さくなってしまいます。またスクロールしても横スクロールは問題なくても、縦スクロールはタイトルと
同じくスクロールし、下にスクロールするとタイトルが隠れてしまいます。

また、タイトルと内容を別のフレームに分けると縦の位置が合わないのと、横スクロールとずれるため、同じフレーム内にgridで配置しています

該当のソースコード

import tkinter as tk root = tk.Tk() root.title("test") root.geometry("1200x1200") frm_a = tk.Frame(root, width=900 ,height=900) frm_a.grid(row=0, column=0) cnv = tk.Canvas(frm_a,width=900,height=900,bg="blue",relief=tk.FLAT) cnv.grid(row=0,column=0) frm_b = tk.Frame(cnv, width=900 ,height=900) cnv.create_window(0, 0, window=frm_b, anchor=tk.NW) ybar = tk.Scrollbar(cnv,orient=tk.VERTICAL) xbar = tk.Scrollbar(cnv,orient=tk.HORIZONTAL) ybar.pack(side=tk.RIGHT, fill=tk.Y) xbar.pack(side=tk.BOTTOM, fill=tk.X) ybar.config(command=cnv.yview) xbar.config(command=cnv.xview) cnv.config(yscrollcommand=ybar.set, xscrollcommand=xbar.set) cnv.config(scrollregion=(0, 0, 1200, 4000)) # タイトル lbl_s = tk.Label(frm_b ,text='タイトル1',width=10,height=2) lbl_s.grid(row=1,column=1) lbl_t = tk.Label(frm_b,text='タイトル2',width=10,height=2) lbl_t.grid(row=1,column=3) lbl_u = tk.Label(frm_b,text='タイトル3',width=10,height=2) lbl_u.grid(row=1,column=5) lbl_v = tk.Label(frm_b,text='タイトル4',width=10,height=2) lbl_v.grid(row=1,column=7) # 内容 row_pos = 3 for i in range(1,30): lbl_aa = tk.Label(frm_b,width=10,height=2,text=str(i),relief=tk.FLAT) lbl_aa.grid(row=row_pos,column=1) txt_aa = tk.Entry(frm_b,width=10) txt_aa.grid(row=row_pos,column=3) lst_aa = tk.Listbox(frm_b,width=10,selectmode="single",height=2) lst_aa.grid(row=row_pos,column=5) txt_ac = tk.Entry(frm_b,width=10) txt_ac.grid(row=row_pos,column=7) row_pos += 2 # 罫線 for i in range(0,8,2): v_line = ttk.Separator(frm_b, orient="vertical", style="blue.TSeparator") v_line.grid(row=1, column=i, rowspan=120, sticky="nsew") for i in range(0,60,2): h_line = ttk.Separator(frm_b, orient="horizontal", style="blue.TSeparator") h_line.grid(row=i, column=1, columnspan=8, sticky="nsew") frm_c = tk.Frame(root,width=900,height=40,bg='blue') frm_c.grid(row=10, column=0) root.mainloop()

試したこと

cnv.grid(row=0,column=0)

cnv.pack(fill=tk.BOTH, expand=tk.YES)
に変えたり
ybar.pacなどをgridに変えましたが、表示が大きくなりません。

補足情報(FW/ツールのバージョンなど)

Python 3.10.5
Tkinter 8.6

よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

キャンバス部分を大きく表示するには、
grid を使っているところを、pack を使い以下の様に配置します。

grid でも設定次第で可能ですが、
この場合は逆にgridの方が冗長になってしまいます。

cnv.pack(fill=tk.BOTH, expand=tk.YES) が効かなかった問題点は、
ウィジェットの配置が多重になっている為、その上の frm_a も伸縮可能にする必要があります。
cnv.pack(...) だけでは、伸縮できない frm_a 上に、伸縮可能の cnv が載っている状態でした。

また、同一フレーム上では grid/pack を混在できない点に注意してください。
frm_c も frm_a に合わせて pack での配置にします。

python

1frm_a.pack(fill=tk.BOTH, expand=tk.YES) 2frm_c.pack() 3 4cnv.pack(fill=tk.BOTH, expand=tk.YES) 5

縦スクロールはタイトルと同じくスクロールし、「下にスクロールするとタイトルが隠れてしまいます。」
また、タイトルと内容を「別のフレームに分けると縦の位置が合わない」のと、

これは、タイトルをスクロールしても表示しておきたいということだと思いますが、
残念ながら仕組み上両立は出来ません。
表示だけなら、ttk.Treeview ならヘッダ行を維持したスクロールは可能です。
(但し、Treeviewは編集に対応しておらず、編集機能は自分で実装する必要がある)

現状の構造を保ったまま実装するには、各カラム幅を所得して
スクロールの度にタイトル行を一番上に再描画するというような形になると思います。

表計算の様なウィジェットはtkinter では標準機能ではサポートされていないので、
不足している機能を独力で実装しないといけない場面は多いです。
他のライブラリを検討した方が良い場合もあります

  • 外部ライブラリに頼る (pandastable)
  • テーブルウィジェットのある他のGUIライブラリ(wx, qt)を使う

投稿2022/10/29 10:12

teamikl

総合スコア8664

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

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

shinobuKouno

2022/10/29 13:37

ご返信ありがとうございます。 同一のフレーム内でpackとgridは混同できな事は参考になりました そこで、# 内容 部分をPackで並べるは難しそうでしたので、gridで統一することにしました また、横スクロールをやめて、frm_aにタイトル、frm_b内のcnv内のfrm_cに内容部分を書きたいと思い ↓の様にしたのですが、スクロールが動きません。 正しい書き方を教えてくださいm(_ _)m また、Tkinterではfrm_aの"タイトル"とfrm_cの"内容"縦列がずれるのは仕方ないということですね? いずれは他のGUIも勉強したいと思います。 import tkinter as tk root = tk.Tk() root.title("test") root.geometry("400x900") # タイトル群 frm_a = tk.Frame(root,width=400,height=50) frm_a.grid(row=0,column=0) h_line = ttk.Separator(frm_a, orient="horizontal", style="blue.TSeparator") h_line.grid(row=0, column=0, columnspan=8, sticky="nsew") h_line = ttk.Separator(frm_a, orient="horizontal", style="blue.TSeparator") h_line.grid(row=3, column=0, columnspan=8, sticky="nsew") for i in range(0,9,2): v_line = ttk.Separator(frm_a, orient="vertical", style="blue.TSeparator") v_line.grid(row=0, column=i, rowspan=3, sticky="nsew") lbl_s = tk.Label(frm_a ,text='タイトル1',width=10,height=2) lbl_s.grid(row=1,column=1) lbl_t = tk.Label(frm_a,text='タイトル2',width=10,height=2) lbl_t.grid(row=1,column=3) lbl_u = tk.Label(frm_a,text='タイトル3',width=10,height=2) lbl_u.grid(row=1,column=5) lbl_v = tk.Label(frm_a,text='タイトル4',width=10,height=2) lbl_v.grid(row=1,column=7) # 内容群 frm_b = tk.Frame(root,width=400,height=600) frm_b.grid(row=1,column=0) # ,sticky=tk.W + tk.E + tk.N + tk.S) cnv = tk.Canvas(frm_b,width=400,height=600,bg="blue",relief=tk.FLAT) cnv.grid(row=0,column=0) #,sticky=tk.W + tk.E + tk.N + tk.S) frm_c = tk.Frame(cnv, width=400 ,height=600) frm_c.grid(row=0,column=0) #,sticky=tk.W + tk.E + tk.N + tk.S) ybar = tk.Scrollbar(cnv,orient=tk.VERTICAL) ybar.grid(row=0,column=1,sticky=tk.N + tk.S) ybar.config(command=cnv.yview) cnv.config(yscrollcommand=ybar.set) cnv.config(scrollregion=(0, 0, 0, 3000)) # 内容 row_pos = 0 for i in range(1,60): lbl_aa = tk.Label(frm_c,width=10,height=2,text=str(i),relief=tk.FLAT) lbl_aa.grid(row=row_pos,column=1) txt_aa = tk.Entry(frm_c,width=12) txt_aa.grid(row=row_pos,column=3) lst_aa = tk.Listbox(frm_c,width=12,selectmode="single",height=2) lst_aa.grid(row=row_pos,column=5) txt_ac = tk.Entry(frm_c,width=10) txt_ac.grid(row=row_pos,column=7) h_line = ttk.Separator(frm_c, orient="horizontal", style="blue.TSeparator") h_line.grid(row=row_pos+1,column=0,columnspan=8,sticky=tk.W + tk.E) row_pos += 2 for i in range(0,8,2): v_line = ttk.Separator(frm_c, orient="vertical", style="blue.TSeparator") v_line.grid(row=0,column=i,rowspan=100,sticky=tk.N + tk.S) frm_d = tk.Frame(root,width=900,height=40,bg='blue') frm_d.grid(row=2,column=0) root.mainloop()
teamikl

2022/10/29 20:54 編集

># 内容 部分をPackで並べるは難しそうでしたので pack と grid が混在できないのは、同一フレーム上です ウィジェットが階層を持つ場合は全てを統一する必要はなく 親になるフレーム単位で pack/grid どちらかに統一します。 例 root  frameA.pack   button.grid <-- ここでのgridは別階層なので frameA.pack との混在には当たりません   button.grid   label.pack <--但し、packを混ぜると NG frameA 内に pack/grid が混在してしまう  frameB.pack <-- frameA.pack の場合ここで frameB.grid は使えない 格子状に配置しているのは frm_b の子要素なので frm_b はキャンバスに配置 (これは pack/grid 関係なし) frm_b の子要素はそのまま grid で配置可能です。 > 「Tkinterでは」frm_aの"タイトル"とfrm_cの"内容"縦列がずれるのは仕方ないということですね? 正確には、pack によるレイアウトの自動調整では、 別フレームのウィジェットの情報を持たないので、自動的には揃えられません。 これは、他のGUIライブラリでも同種のレイアウト機構では出来ない、仕組上の問題です。 揃える手段自体はあります、サイズ指定は可能なので。 具体的な方法は細かな要件次第です。 固定レイアウトなら同じ幅を指定するだけで済みますが、ウィンドウのリサイズ対応する場合 レイアウトマネージャが行ってくれる処理を自分で実装する事になります。
shinobuKouno

2022/10/30 07:32

ありがとうございます。ようやく理解できました。 縦の幅は調節できるように、もう少し勉強いたします。 フレームとキャンバスを直したのですが↓の様に縦のスクロールとキャンバスが連動しなくなってしまいました。 よろしくお願いいたしますm(_ _)m root = tk.Tk() root.title("test") root.geometry("600x1000") # タイトル群 frm_a = tk.Frame(root,width=400,height=50) frm_a.pack(anchor=tk.NW) h_line = ttk.Separator(frm_a, orient="horizontal", style="blue.TSeparator") h_line.grid(row=0, column=0, columnspan=8, sticky="nsew") h_line = ttk.Separator(frm_a, orient="horizontal", style="blue.TSeparator") h_line.grid(row=3, column=0, columnspan=8, sticky="nsew") for i in range(0,9,2): v_line = ttk.Separator(frm_a, orient="vertical", style="blue.TSeparator") v_line.grid(row=0, column=i, rowspan=3, sticky="nsew") lbl_s = tk.Label(frm_a ,text='タイトル1',width=10,height=2) lbl_s.grid(row=1,column=1) lbl_t = tk.Label(frm_a,text='タイトル2',width=10,height=2) lbl_t.grid(row=1,column=3) lbl_u = tk.Label(frm_a,text='タイトル3',width=10,height=2) lbl_u.grid(row=1,column=5) lbl_v = tk.Label(frm_a,text='タイトル4',width=10,height=2) lbl_v.grid(row=1,column=7) # 内容群 frm_b = tk.Frame(root,width=400,height=700) frm_b.pack(anchor=tk.NW,fill=tk.Y, expand=tk.YES) cnv = tk.Canvas(frm_b,width=400,height=700,bg="blue",relief=tk.FLAT) cnv.pack(side=tk.LEFT,fill=tk.Y, expand=tk.YES) frm_c = tk.Frame(cnv, width=400 ,height=700) frm_c.pack(side=tk.LEFT,fill=tk.Y, expand=tk.YES) ybar = tk.Scrollbar(cnv,orient=tk.VERTICAL) ybar.pack(side=tk.RIGHT, fill=tk.Y) ybar.config(command=cnv.yview) cnv.config(yscrollcommand=ybar.set) cnv.config(scrollregion=(0, 0, 0, 2000)) # 内容 row_pos = 0 for i in range(1,60): lbl_aa = tk.Label(frm_c,width=10,height=2,text=str(i),relief=tk.FLAT) lbl_aa.grid(row=row_pos,column=1) txt_aa = tk.Entry(frm_c,width=12) txt_aa.grid(row=row_pos,column=3) lst_aa = tk.Listbox(frm_c,width=12,selectmode="single",height=2) lst_aa.grid(row=row_pos,column=5) txt_ac = tk.Entry(frm_c,width=12) txt_ac.grid(row=row_pos,column=7) h_line = ttk.Separator(frm_c, orient="horizontal", style="blue.TSeparator") h_line.grid(row=row_pos+1,column=0,columnspan=8,sticky=tk.W + tk.E) row_pos += 2 for i in range(0,9,2): v_line = ttk.Separator(frm_c, orient="vertical", style="blue.TSeparator") v_line.grid(row=0,column=i,rowspan=100,sticky=tk.N + tk.S) frm_d = tk.Frame(root,width=400,height=40,bg='green') frm_d.pack(anchor=tk.NW) root.mainloop()
teamikl

2022/10/30 11:44 編集

スクロールさせたい内容群は frm_c ですよね? スクロール対象はキャンバスなので、 スクロールさせたいウィジェットを、 pack ではなく cnv.create_window で配置する必要があります。 cnv.create_window(0, 0, window=frm_c, anchor=tk.NW)
shinobuKouno

2022/10/30 12:08

ありがとうございます。 frm_c.pack(side=tk.LEFT,fill=tk.Y, expand=tk.YES) を cnv.create_window(0,0,window=frm_c, anchor=tk.NW) に変えると内容群が消えてしまいます。
teamikl

2022/10/31 01:35 編集

他にも変更点あったのですね、実行確認してませんでしたすいません。 スクロールバーのレイアウトにより隠れてしまっているようです スクロールバーはキャンバス内ではなく、キャンバスの横なので キャンバスと共通の親のfrm_b に配置 ybar = tk.Scrollbar(frm_b,orient=tk.VERTICAL) root  frm_a.pack  frm_b.pack   cnv.pack    frm_c (create_windowでcnvに配置   yvar.pack
shinobuKouno

2022/10/31 07:36

ありがとうございます。思い通りの動きができるようになりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問