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

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

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

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

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Python

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

Q&A

解決済

1回答

2873閲覧

Tkinterのウィンドウ全体をスクロールバーで操作したい

liv_0311

総合スコア2

Tkinter

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

スクロール

スクロールとは、ディスプレイスクリーン上において連続的にコンテンツが滑っていくことを指します。

Python

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

0グッド

0クリップ

投稿2022/10/21 15:36

編集2022/10/22 22:20

前提

Tkinterでアプリケーションを作成したのですが、データの数によってウィンドウの大きさが左右されるため、データが表示された範囲まで追えるように上下のスクロールバーで操作できるようにしたいと考えております。

実現したいこと

下記コードのアプリケーションのウィンドウにY軸のスクロールバーを追加して、データがウィンドウからはみ出した際に全て閲覧できるようにしたい。

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

該当のソースコード

Python

1from tkinter import * 2 3class Application(Frame): 4 def __init__(self, master): 5 super().__init__(master) 6 7 master.geometry('1000x850') 8 master.title('DAアルゴリズムによるマッチングアプリ') 9 master.resizable(False, True) 10 11 canvas = Canvas(master) 12 13 bar = Scrollbar(self.master, orient=VERTICAL) 14 bar.pack(side=RIGHT, fill=Y) 15 bar.config(command=canvas.yview) 16 17 canvas.config(yscrollcommand=bar.set) 18 canvas.config(scrollregion=(0, 0, 0, 10000)) 19 canvas.bind_all('<MouseWheel>', lambda eve: canvas.yview_scroll(int(-eve.delta/120), 'units')) 20 canvas.pack(side=LEFT, fill=BOTH, expand=True) 21 22 self.frame = Frame(canvas) 23 24 canvas.create_window((0, 0), window=self.frame, anchor=NW) 25 26 self.widget1() 27 self.label_lst = [] 28 self.entry_lst = [] 29 self.button_lst = [] 30 self.s_prefs = [] 31 self.c_prefs = [] 32 33 def widget1(self): 34 Label(self.frame, text='学生の人数を入力 >>').grid(row=0, column=0, pady=5) 35 self.f1 = IntVar(value='') 36 Entry1 = Entry(self.frame, textvariable=self.f1, width=5).grid(row=0, column=1, pady=5) 37 38 Label(self.frame, text='研究室の数を入力 >>').grid(row=0, column=2, pady=5) 39 self.f2 = IntVar(value='') 40 Entry2 = Entry(self.frame, textvariable=self.f2, width=5).grid(row=0, column=3, pady=5) 41 42 Button1 = Button(self.frame, text='OK', command=self.btn1_clicked, width=5).grid(row=0, column=4, pady=5) 43 44 def btn1_clicked(self): 45 S = self.f1.get() 46 C = self.f2.get() 47 48 for i in range(S): 49 label = Label(self.frame, text=['学生',i+1,'の希望順に研究室の番号をスペース区切りで入力 >>']).grid(row=i+1, column=0, pady=5) 50 self.f_s_pref = StringVar(value='') 51 self.s_prefs.append(self.f_s_pref) 52 entry = Entry(self.frame, textvariable=self.f_s_pref, width=40).grid(row=i+1, column=1, pady=5) 53 self.label_lst.append(label) 54 self.entry_lst.append(entry) 55 56 button = Button(self.frame, text='OK', command=self.btn2_clicked, width=5).grid(row=S, column=2, pady=5) 57 self.button_lst.append(button) 58 59 def btn2_clicked(self): 60 S = self.f1.get() 61 C = self.f2.get() 62 63 for i in range(C): 64 label = Label(self.frame, text=['研究室',i+1,'の希望順に学生の番号をスペース区切りで入力 >>']).grid(row=S+1+i, column=0, pady=5) 65 self.f_c_pref = StringVar(value='') 66 self.c_prefs.append(self.f_c_pref) 67 entry = Entry(self.frame, textvariable=self.f_c_pref, width=40).grid(row=S+1+i, column=1, pady=5) 68 self.label_lst.append(label) 69 self.entry_lst.append(entry) 70 71 button = Button(self.frame, text='OK', command=self.btn3_clicked, width=5).grid(row=S+1+i, column=2, pady=5) 72 self.button_lst.append(button) 73 74 def btn3_clicked(self): 75 S = self.f1.get() 76 C = self.f2.get() 77 78 label = Label(self.frame, text=['研究室1から順に定員をスペース区切りで入力 >>']).grid(row=S+C+1, column=0, pady=5) 79 self.f_capa = StringVar(value='') 80 entry = Entry(self.frame, textvariable=self.f_capa, width=20).grid(row=S+C+1, column=1, pady=5) 81 self.label_lst.append(label) 82 self.entry_lst.append(entry) 83 84 button = Button(self.frame, text='OK', command=self.btn4_clicked, width=5).grid(row=S+C+1, column=2, pady=5) 85 self.button_lst.append(button) 86 87 def btn4_clicked(self): 88 S = self.f1.get() 89 C = self.f2.get() 90 91 s_prefs = [i.get().split() for i in self.s_prefs] 92 for i in range(S): 93 for j in range(C): 94 s_prefs[i][j] = int(s_prefs[i][j]) 95 96 c_prefs = [i.get().split() for i in self.c_prefs] 97 for i in range(C): 98 for j in range(S): 99 c_prefs[i][j] = int(c_prefs[i][j]) 100 101 c_rank = [[0]*S for i in range(C)] 102 for i in range(C): 103 for j in range(S): 104 k = c_prefs[i][j] 105 c_rank[i][k-1] = j+1 106 107 capacity = [int(s) for s in self.f_capa.get().split()] 108 s_matched = [0]*(S+1) 109 c_matched = [[0]*(S+1) for i in range(C)] 110 num_match = 0 111 s_filled = [0]*(S+1) 112 c_filled = [0]*C 113 position = [0]*(S+1) 114 115 t = 1 116 while num_match < S: 117 for i in range(S): 118 if s_filled[i]==0: 119 j = s_prefs[i][position[i]]-1 120 if c_filled[j]<capacity[j]: 121 c_matched[j][i] = 1 122 s_matched[i] = j 123 s_filled[i] = 1 124 c_filled[j] += 1 125 num_match += 1 126 127 else: 128 temp = -1 129 rejected = S 130 for k in range(S): 131 if c_matched[j][k]==1: 132 if c_rank[j][i] < c_rank[j][k] and c_rank[j][k] > temp: 133 s_filled[rejected] = 1 134 position[rejected] -= 1 135 c_matched[j][rejected] = 1 136 s_matched[rejected] = j 137 s_filled[k] = 0 138 position[k] += 1 139 rejected = k 140 c_matched[j][k] = 0 141 temp = c_prefs[j][k] 142 143 if temp > -1: 144 c_matched[j][i] = 1 145 s_matched[i] = j 146 s_filled[i] = 1 147 else: 148 position[i] += 1 149 if position[i]==C: 150 s_matched[i] = -1 151 s_filled[i] = 1 152 num_match += 1 153 t += 1 154 155 Label(self.frame, text='マッチング結果').grid(row=S+C+2, column=0, pady=5) 156 for i in range(S): 157 if s_matched[i]==-1: 158 label = Label(self.frame, text='学生{0}:'.format(i+1)).grid(row=S+C+3+i, column=0, pady=5) 159 self.label_lst.append(label) 160 else: 161 label = Label(self.frame, text='学生{0}: 研究室{1}'.format(i+1, s_matched[i]+1)).grid(row=S+C+3+i, column=0, pady=5) 162 self.label_lst.append(label) 163 164 for j in range(C): 165 if c_filled[j]==0: 166 label = Label(self.frame, text=': 研究室{0}'.format(j+1)).grid(row=S+C+3+i, column=1, pady=5) 167 self.label_lst.apppend(label) 168 169def main(): 170 root = Tk() 171 app = Application(master = root) 172 app.mainloop() 173 174if __name__ == '__main__': 175 main()

試したこと

検索した上位のサイトからframeやcanvas, scrollbarを用いたコードを何個か書いてみて、そこから援用しようと試みたのですが、私の理解が浅いことで自分のコードに上手く落とし込めず理想の形にすることができませんでした。

参考: https://kuroro.blog/python/vgx53M7D1d6C0R8ejp0V/
https://qiita.com/shinno1993/items/3ea14ffd7f17d8214961
https://blog.teclado.com/tkinter-scrollable-frames/
https://daeudaeu.com/scrollbar/

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

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

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

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

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

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

guest

回答1

0

ベストアンサー

スクロールバーを取り付ける「目的を達成したい」のか「使い方の理解をしたい」かで対処が変わりますが、
前者であれば、既存のライブラリを利用するのはどうでしょう?


ttkwidgets というライブラリ(外部ライブラリなのでインストールは必要)に
ScrolledFrame というクラスが有り、このFrameを親にウィジェットを配置するだけで
対象の領域がスクロール可能になります。

Example ScrolledFrame

例えば、アプリケーション全体であれば `class Application(Frame)' の Frame 部分を
ScrolledFrame と差し替えるだけでスクロール可能になります。

特定箇所のみをスクロールの場合は、
現状のウィジェット構造だと1枚のFrame上に全てのウィジェットが載っている状態なので
スクロールしたい部分のみが共通の親を持つように、適切な構造に変更する必要があります。


スクロールバーの使い方の理解は、
単体での利用はできて現状のコードへの適応で躓いているとの事ですが、
どの部分で躓いているのか具体的な情報が必要です。
手順の確認から

フォーム部品のリストをスクロール可能にしたい場合は、
一旦 Frame 上に配置してから、Frame を スクロール設定したCanvas に配置します。

  1. スクロールする領域となる Canvas を配置
  2. Canvas を親に、スクロールする部品を乗せる Frame を配置
  3. Frame 上にウィジェットを配置
  4. スクロールバーの配置
  5. スクロールの設定

どの部分でつまずいているか、試したコードを掲載してください。

投稿2022/10/22 02:22

編集2022/10/22 02:49
teamikl

総合スコア8664

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

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

liv_0311

2022/10/22 21:53

ご返信ありがとうございます。 ライブラリを使用するよりは手順を理解してコードを書きたかったため、教示していただいた手順を確認し、他のページなども調べた結果スクロールバーを実装できました。 それを該当のソースコードに載せ直させてもらっているのですが、アプリの仕様上、マッチング結果が下の方にラベルされていくため、scrollregionを無限?に設定したいと考えています。 現状では(0, 0, 0, 10000)として大きく見積もった範囲を設定しています。 この部分の解決策がもしあればですが、よろしくお願いいたします。
teamikl

2022/10/23 05:41 編集

> scrollregionを無限?に設定したいと考えています。 実際に大きな値にしてしまうと、最初からスクロールバーが小さくなり使いづらくなってしまうので 現在の表示サイズ + α の値を設定しておき、スクロールの度に下に来たとき scrollregion を更新する事で 無限スクロールを実現できます。 注意点は、実際に無制限のデータを同時に生成するとリソースを食いつぶしてしまうので、 巨大なデータを表示させたい場合は、(画面サイズは有限なので) 表示領域のウィジェットは固定で用意しておき スクロールにより表示にデータのみを入れ替えるといった手法を取ります。 (データがサーバーからの応答だったりする場合は、キャッシュを設ける等の対策を取る) 無限スクロールではありませんが、 100万件のデータを必要最低限(表示されている10件分)のメモリでスクロールするサンプルコード https://replit.com/@MiKLTea/TkTableView#main.py 関連: tkinterのtreeviewにて、大量のデータを表示させる方法 https://teratail.com/questions/323794
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問