[解決済み] Tkinterでウィジェットグループにスクロールバーを追加する
質問
私はPythonを使ってログファイルからエントリを解析し、Tkinterを使ってエントリの内容を表示していますが、今のところ素晴らしいものです。出力はラベルウィジェットのグリッドですが、時々、画面上に表示できるよりも多くの行があります。私はスクロールバーを追加したいのですが、それは非常に簡単であるように見えますが、私はそれを理解することができません。
ドキュメントでは、リスト、テキストボックス、キャンバス、およびエントリの各ウィジェットのみがスクロールバーインターフェイスをサポートしていることが示唆されています。これらのどれも、ウィジェットのグリッドを表示するのに適していないように見えます。Canvas ウィジェットに任意のウィジェットを配置することは可能ですが、絶対座標を使用しなければならないようなので、グリッド レイアウト マネージャを使用することはできないでしょうか?
ウィジェットグリッドをフレームに入れようとしましたが、フレームはスクロールバーインターフェースをサポートしていないようなので、これはうまくいきません。
mainframe = Frame(root, yscrollcommand=scrollbar.set)
この制限を回避する方法をどなたか教えてください。スクロールバーを追加するためだけに、PyQtで書き直して、実行可能な画像のサイズを大きくするのは嫌なんです!
どのように解決するのですか?
概要
スクロールバーは一部のウィジェットにしか関連付けることができず、ルートウィジェットと
Frame
はそのウィジェットグループの一部ではありません。
これを行うには、少なくとも2つの方法があります。単純な垂直または水平方向のウィジェットグループが必要な場合、テキストウィジェットと
window_create
メソッドを使用してウィジェットを追加します。この方法はシンプルですが、ウィジェットを複雑にレイアウトすることはできません。
より一般的な汎用ソリューションは、canvas ウィジェットを作成し、スクロールバーをそのウィジェットに関連付けることです。次に、そのキャンバスに、ラベル ウィジェットを含むフレームを埋め込みます。フレームの幅と高さを決定し、それをキャンバスに入力します。
scrollregion
オプションに入力し、スクロール領域がフレームのサイズと正確に一致するようにします。
なぜウィジェットをキャンバスに直接ではなく、フレームに配置するのですか? canvas に添付されたスクロールバーは
create_
メソッドのいずれかで作成されたアイテムのみをスクロールできます。でキャンバスに追加されたアイテムはスクロールできません。
pack
,
place
または
grid
. フレームを使うことで、これらのメソッドをフレーム内で使用し、その後に
create_window
をフレームに対して一度だけ呼び出すことができます。
キャンバス上に直接テキスト項目を描画することはそれほど難しくないので、フレームに埋め込まれたキャンバスのソリューションがあまりに複雑に思える場合は、このアプローチを再考することをお勧めします。グリッドを作成しているので、各テキスト項目の座標は、特に各行の高さが同じであれば (単一のフォントを使用している場合はおそらくそうなります)、非常に簡単に計算できます。
キャンバスに直接描画する場合、使用しているフォントの行の高さを計算するだけです (そのためのコマンドもあります)。そして、各 y 座標は
row*(lineheight+spacing)
. x座標は、各列の最も幅の広い項目に基づいて固定された数値になります。すべてのものにその列のタグを与えれば、一つのコマンドで列内のすべてのアイテムのx座標と幅を調整することができます。
オブジェクト指向の解決策
オブジェクト指向のアプローチを使用した frame-embedded-in-canvas ソリューションの例です。
import tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=1)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
root=tk.Tk()
example = Example(root)
example.pack(side="top", fill="both", expand=True)
root.mainloop()
手続き的解決
クラスを使用しない解決策を紹介します。
import tkinter as tk
def populate(frame):
'''Put in some fake data'''
for row in range(100):
tk.Label(frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(frame, text=t).grid(row=row, column=1)
def onFrameConfigure(canvas):
'''Reset the scroll region to encompass the inner frame'''
canvas.configure(scrollregion=canvas.bbox("all"))
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0, background="#ffffff")
frame = tk.Frame(canvas, background="#ffffff")
vsb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
canvas.configure(yscrollcommand=vsb.set)
vsb.pack(side="right", fill="y")
canvas.pack(side="left", fill="both", expand=True)
canvas.create_window((4,4), window=frame, anchor="nw")
frame.bind("<Configure>", lambda event, canvas=canvas: onFrameConfigure(canvas))
populate(frame)
root.mainloop()
関連
-
[解決済み] Pandasのデータフレームでタプルの列を分割するにはどうしたらいいですか?
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] Django で全てのリクエストヘッダを取得するにはどうすれば良いですか?
-
[解決済み] Pandasを使って、既存のExcelファイルに新しいシートを保存する方法は?
-
[解決済み] if 節の終了方法
-
[解決済み] Pythonの検索パスを他のソースに展開する
-
[解決済み] Pythonでファイルの読み込みと上書きをする
-
[解決済み] Pythonの辞書にあるスレッドセーフについて
-
[解決済み] Django filter queryset __in for *every* item in list
-
[解決済み] Python の sorted() はどのようなアルゴリズムを使っているのですか?重複
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] DataFrameの文字列、dtypeがobjectの場合
-
[解決済み] Jupyterノートブックでenv変数を設定する方法
-
[解決済み] django.db.migrations.exceptions.InconsistentMigrationHistory
-
[解決済み] Pythonの要素別タプル演算(sumなど
-
[解決済み] Python 3でバイナリデータを標準出力に書き込むには?
-
[解決済み] Django 1.7で初期マイグレーションからマイグレートバックする方法は?
-
[解決済み] Ctrl-CでPythonスクリプトを終了できない
-
[解決済み] subprocess.run()の出力を抑制またはキャプチャするには?
-
[解決済み] PythonのRequestsモジュールを使ってWebサイトに "ログイン "するには?
-
[解決済み] 認証プラグイン 'caching_sha2_password' はサポートされていません。