Tkinterの使い方:スクロールバー(Scrollbar)の使い方

スクロールバーの作成方法解説ページアイキャッチ

このページにはプロモーションが含まれています

このページでは、Tkinter の「スクロールバー」ウィジェットの作成方法および設定方法について説明していきたいと思います。

スクロールバーとは

まずは、今回解説する「スクロールバー」がどのようなものであるかを簡単に説明していきます。

スクロールバーは表示領域を変化させるウィジェット

スクロールバーは、ウィジェットをスクロールさせて「表示領域」を変化させるためのウィジェットになります。

下の図は tkinter で作成したスクロールバー付きのキャンバスになります。

スクロールバーのスライダー(つまみ)を移動させることで、キャンバスの表示領域が変化し、最初見えなかった図形が見えるようになるのが確認できると思います。

キャンバスがスクロールされる様子

こんな感じで、小さなウィジェットであっても、スクロールバーを利用すれば大きなウィジェットのように扱うことが可能になります。

スポンサーリンク

スクロールバーと他のウィジェットとの大きな違い

スクロールバーのポイントは、スクロールバーのメイン機能の「スクロール」が他のウィジェットに作用するものである点です。

つまり、スクロールバー単体では意味のないウィジェットで、他のウィジェットをスクロールさせるようにすることで初めて意味のあるウィジェットになります。

ここが他のウィジェットとの決定的な違いになります。

そのため、このスクロールバーを作成していく上では、「いかにして他のウィジェットをスクロールさせるのか」という点がポイントになってきます。

ということで、このページでは単にスクロールバーを作成するものではなく、「スクロールバー付きのウィジェット」を作成するスクリプトを紹介し、そのスクリプトを確認しながらスクロールバーを作成するために必要な処理を解説していきたいと思います。

スクロール可能なウィジェット

スクロールバーがスクロールさせることができるウィジェットは(私が確認した限りでは)下記の5つになります。

  • キャンバス(Canvas
  • リストボックス(Listbox
  • エントリー(Entry)
  • スピンボックス(Spinbox)
  • テキストボックス(Text

まずは、「スクロールバー付きのキャンバス」を例に、スクロールバーの作成や配置、さらにはキャンバスをスクロールさせる方法について解説していきたいと思います。

その後、リストボックス・エントリー・スピンボックス・テキストボックスそれぞれに対するスクロールバーの作り方を、スクロールバー付きのウィジェットの作成(キャンバス以外)で解説していきたいと思います。

といっても、キャンバスとその他のウィジェットでは、スクロールバーの作り方は “ほぼ” 同じです。

ですので、重要な内容は全て、次の「スクロールバー付きのキャンバス」で解説し、その他のウィジェットにおけるスクロールバーの作成については、スクリプトの紹介のみを行う形で解説していきたいと思います。

スクロールバー付きのキャンバス

それでは、まずは「スクロールバー付きのキャンバス」を作成するスクリプトを紹介し、その中でスクロールバーの作成方法を解説していきたいと思います。

スクロールバーを作成する上でポイントになるのは下記の3つになります。

  • スクロールバーの作成
  • スクロールバーの配置
  • キャンバスをスクロールするための設定

この辺りに注目しながらスクリプトに目を通してみていただくと、スクロールバー作成に必要な処理が分かりやすくなると思います。

スポンサーリンク

スクロールバー付きのキャンバスのスクリプト

「スクロールバー付きのキャンバス」を作成するスクリプト例は下記のようになります。

スクロールバー付きのキャンバスの作成
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウの作成
app = tkinter.Tk()

# キャンバスの作成と配置
canvas = tkinter.Canvas(
	app,
	width=400,
	height=300,
	scrollregion=(-200, -100, 800, 600)
)
canvas.grid(row=0, column=0)

# 楕円をキャンバスからはみ出るように描画
canvas.create_oval(
	300, 250,
	500, 350,
	fill="blue"
)

# 楕円をキャンバスの外に描画
canvas.create_oval(
	700, 0,
	800, 200,
	fill="red"
)

# 長方形をキャンバスの外に描画
canvas.create_rectangle(
	600, 400,
	800, 500,
	fill="green"
)

# 長方形をキャンバスの外に描画
canvas.create_rectangle(
	-200, -100,
	0, 0,
	fill="purple"
)

# 水平方向のスクロールバーを作成
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
)

# 垂直方向のスクロールバーを作成
ybar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.VERTICAL,  # バーの方向
)

# キャンバスの下に水平方向のスクロールバーを配置
xbar.grid(
	row=1, column=0,  # キャンバスの下の位置を指定
	sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
)

# キャンバスの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=0, column=1,  # キャンバスの右の位置を指定
	sticky=tkinter.N + tkinter.S  # 上下いっぱいに引き伸ばす
)


# キャンバスをスクロールするための設定

# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=canvas.xview
)
ybar.config(
	command=canvas.yview
)


# キャンバススクロール時に実行する処理を設定
canvas.config(
	xscrollcommand=xbar.set
)
canvas.config(
	yscrollcommand=ybar.set
)


# メインループ
app.mainloop()

実行すると下の図のようにメインウィンドウの中に「スクロールバー付きのキャンバス」が表示されます。

スクロールバー付きのキャンバスが表示される様子

さらに、スクロールバーのスライダー(つまみ)をマウスでクリックしながら動かすと、今まで見えなかったキャンバス上の図形が見えるようになることが確認できると思います。

キャンバスがスクロールされる様子

上記のスクリプトの中で、「スクロールバー付きのキャンバス」を作るためにどのような処理を行なっているのかについて、ここから解説していきたいと思います。

メインウィンドウの作成とメインループ

この辺りは他のウィジェットと同様ですね!

まず、下記でメインウィンドウの作成及びメインループの実行を行なっています。

メインウィンドウの作成とメインループ
# -*- coding:utf-8 -*-
import tkinter

app = tkinter.Tk()

# 略

app.mainloop()

メインウィンドウが何かわからない方は、下記ページで解説していますのでコチラも読んでみてください。

メインウィンドウ作成解説ページのアイキャッチ Tkinterの使い方:メインウィンドウを作成する

また、メインループについては下記ページで解説しています。

tkinterのmainloopの解説ページのアイキャッチ 【Python】tkinterのmainloopについて解説

キャンバスの作成とキャンバスへの図形描画

続いて “スクロールバーなし” の状態のキャンバスを作成し、さらにメインウィンドウ上に配置していきます。

キャンバスの作成と配置

まず、キャンバスの作成と配置を行なっているのは下記部分になります。

キャンバスの作成と配置
# キャンバスの作成と配置
canvas = tkinter.Canvas(
	app,
	width=400,
	height=300,
	scrollregion=(-200, -100, 800, 600)
)
canvas.grid(row=0, column=0)

キャンバスの作成については下記ページで解説していますので、詳しく知りたい方はこちらを参考にしていただければと思います。

tkinterのキャンバスの作り方解説ページアイキャッチ Tkinterの使い方:キャンバスウィジェットの作り方

スクロールバー付きのキャンバスを作成する上でポイントになるのが scrollregion の設定です。

スクロールバーは、スクロールにより画面に表示されていない部分を表示できるようにするものです。

画面に表示されるキャンバスのサイズを指定するのが、widthheight になります。

一方で、画面に表示されていない部分のサイズを指定するのが、この scrollregion になります。要はスクロール可能なサイズですね!

キャンバスに対するscrollregion設定の説明図

scrollregion で指定するのは、キャンバスの左上の位置からの距離で、下の図のように4つのパラメータを指定します。

scrollregionの引数とスクロール可能領域の関係

この scrollregion の指定により、実際に表示されているキャンバスからどれだけスクロールできるかが決まります。

また、最初の2つ、つまり上の図における wn に負の値を設定すれば、キャンバスの左上方向にもスクロールできるようになります。

左上方向にもスクロールできるようにするためのscrollregionの設定

キャンバスへの図形の描画

キャンバスの作成と配置の後に行っているのが図形の描画です。これはスクロールバーの動作確認をするための処理で、スクロールバーを作成するための必須の処理ではないです。

図形の描画
# 楕円をキャンバスからはみ出るように描画
canvas.create_oval(
	300, 250,
	500, 350,
	fill="blue"
)

# 楕円をキャンバスの外に描画
canvas.create_oval(
	700, 0,
	800, 200,
	fill="red"
)

# 長方形をキャンバスの外に描画
canvas.create_rectangle(
	600, 400,
	800, 500,
	fill="green"
)

# 長方形をキャンバスの外に描画
canvas.create_rectangle(
	-200, -100,
	0, 0,
	fill="purple"
)

図形の描画に関しては下記ページで詳しく説明していますので、各メソッドや引数の意味を知りたい場合はこちらを読んでみてください。

tkinterキャンバスに図形を描画する方法解説ページのアイキャッチ Tkinterの使い方:Canvasクラスで図形を描画する

ここでのポイントは、キャンバスからはみ出るように、もしくはキャンバス外に各図形を描画してるところです。

図形の描画位置の説明図

このように描画しているので、このままでアプリを起動してもほとんど描画した図形が見れない状態です。

ただし、これらは前述の scrollregion 内に描画しているので、スクロールバーのスクロールにより図形が見えるようになります。

キャンバスがスクロールされる様子

スポンサーリンク

スクロールバーの作成

いよいよ本題のスクロールバーの作成について解説していきます。

実際にスクロールバーを作成しているのが下記になります。

水平方向のスクロール用のスクロールバー xbar と、垂直方向のスクロール用のスクロールバー ybar の2つを作成しています。

スクロールバーの作成
# 水平方向のスクロールバーを作成
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
)

# 垂直方向のスクロールバーを作成
ybar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.VERTICAL,  # バーの方向
)

スクロールバーは Scrollbar クラスのコンストラクタを実行することで作成することができます。

Scrollbarのコンストラクタ
tkinter.Scrollbar()

コンストラクタの第1引数で指定するのがスクロールバーを配置する親ウィジェットです。

今回はスクロールバーをメインウィンドウ上に配置するので、親ウィジェットにはメインウィンドウのオブジェクトである app を指定しています。

また、orient 引数で指定するのはスクロールバーの方向です。orient には、作成するスクロールバーの方向に応じて下記のどちらかを指定します。

  • tkinter.HORIZONTAL:水平方向のスクロールバー
  • tkinter.VERTICAL:垂直方向のスクロールバー

orient設定によるスクロールバーの方向の違い

スクロールバーの配置

スクロールバーも、他のウィジェット同様に配置を行う必要があります。

スクロールバーの場合、下の図のように、水平方向のスクロールバーはウィジェットの下側に、垂直方向のスクロールバーはウィジェットの右側に、ウィジェットにくっつく様に配置されるのが一般的だと思います。

スクロールバーの配置位置

さらに、これらのスクロールバーのサイズ(水平方向のスクロールバーであれば横方向のサイズ、垂直方向のスクロールバーであれば縦方向のサイズ)は、ウィジェットいっぱいに広がるように設定されているのが一般的だと思います。

スクロールバーの配置サイズ

ただし、tkinter でスクロールバーを上記のような配置を行うためには、プログラマーがこのような配置になるようにスクロールバーを配置するスクリプトを記述してやる必要があります(自動的に上記のような配置が行われるわけではない)。

この配置を行なっているのは下記になります。

スクロールバーの配置
# キャンバスの下に水平方向のスクロールバーを配置
xbar.grid(
	row=1, column=0,  # キャンバスの下の位置を指定
	sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
)

# キャンバスの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=0, column=1,  # キャンバスの右の位置を指定
	sticky=tkinter.N + tkinter.S  # 上下いっぱいに引き伸ばす
)

スクロールバーをウィジェットの下、もしくはウィジェットの右に配置するのは grid メソッドで配置を行うのが簡単です。

キャンバスを配置しているのは下記の通り row=0column=0 の位置です。

キャンバスの配置位置
canvas.grid(row=0, column=0)

したがって、水平方向のスクロールバーを row=1column=0 の位置に grid で配置すればキャンバスの下側に、垂直方向のスクロールバーを row=0column=1 の位置に grid で配置すればキャンバスの右側にそれぞれ配置することができます。

gridによるスクロールバーの配置

さらに、スクロールバーをキャンバスのサイズに合わせて引き伸ばすために、grid メソッドの引数に sticky を指定しています。

stickygrid で分割された領域に対してどの方向に寄せて配置するかを指定する設定になります。

stickyの設定例1

この sticky に2つの方向を指定すれば、その2方向に対して目一杯に引き伸ばしたウィジェットを配置することができます。

stickyの設定例2

水平方向のスクロールバーは横方向に、垂直方向のスクロールバーは縦方向にそれぞれ目一杯に引き伸ばして配置するため、sticky には下記を指定するようにしています。

  • 水平方向のスクロールバー:tkinter.W+tkinter.E(左端から右端に引き伸ばす)
  • 垂直方向のスクロールバー:tkinter.N+tkinter.S(上端から下端に引き伸ばす)

以上のように grid で配置することで、最初にお見せした図のようにスクロールバーの配置を実現することができます。

「ウィジェットの配置」については下記ページで解説していますので、詳しく知りたい方はこちらのページ参考にしていただければと思います。上記の sticky についても解説しています。

ウィジェット配置方法解説ページのアイキャッチ Tkinterの使い方:ウィジェットの配置(pack・grid・place)

キャンバスをスクロールするための設定

ここまででウィジェットの作成と配置が完了し、見た目としてはスクロールバー付きのキャンバスが作成されたことになります。

ただし、見た目として出来上がっただけで、まだスクロールバーのスライダーの移動やキャンバスのスクロールができないので、これらができるように設定を行なっていきます。

具体的には下記の2つの設定を行います。

  • スクロールバーのスライダーが動かされた時に実行する処理を設定
  • キャンバススクロール時に実行する処理を設定

スクロールバーのスライダーが動かされた時に実行する処理を設定

まずは「スクロールバーのスライダーが動かされたときに実行する処理を設定」をしていきます。

より具体的には、スクロールバーのスライダーが動かされたときに、”キャンバスの表示領域を変化させる処理” が実行されるように設定を行います。

この設定は下記で行っています。ここで使用している config は、各ウィジェットに用意された “ウィジェットの設定を行うメソッド” になります。

スライダーが動かされた時の処理の設定
# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=canvas.xview
)
ybar.config(
	command=canvas.yview
)

スクロールバーの command を設定することにより、スクロールバーのスライダーが動かされたときに実行したい関数(メソッド)を設定することができます。

つまり、command に “キャンバスの表示領域を変化させるような関数 or メソッド” を指定してやれば、スクロールバーのスライダーが動かされた時に、キャンバスの表示領域が自動的に変化するようになります。

commandが実行されて表示領域が変化する様子

表示領域の変更を行うための関数やメソッドを自作するとなると難易度は高いですが、表示領域を変更するためのメソッドとして、いくつかのウィジェット(のクラス)には xviewyview があらかじめ用意されています。

  • xview:水平方向の表示領域を変化させるメソッド
  • yview:垂直方向の表示領域を変化させるメソッド

Canvas クラスにも、この xviewyview メソッドが用意されています。

ですので、作成したキャンバス canvascanvas.xviewcanvas.yview を、それぞれのスクロールバーの command に設定してやれば、スクロールバーが動いたときにキャンバスの “表示領域” が自動的に変更されるようになります。

キャンバススクロール時に実行する処理を設定

前述の「スクロールバーのスライダーが動かされた時に実行する処理を設定」により、キャンバスのスクロールが行えるようになったようにも思えますが、まだ不十分です。

実は、上記の設定だけだと、スクロールバーのスライダーがまだ動かせない状態です(実際に試してみるとこの様子が確認できると思います)。

このスライダーを動かすために行うのが、ここで説明する「キャンバススクロール時に実行する処理を設定」になります。

より具体的には、キャンバスがスクロールされた時に、つまりキャンバスの表示領域が変わったときに、その表示している領域に合わせて “スクロールバーのスライダーの位置を設定する処理” が実行されるように設定を行います。

これを行っているのは下記になります。

キャンバススクロール時の処理の設定
# キャンバススクロール時に実行する処理を設定
canvas.config(
	xscrollcommand=xbar.set
)
canvas.config(
	yscrollcommand=ybar.set
)

キャンバスの xscrollcommandyscrollcommand の指定により、キャンバスがスクロールされたとき(キャンバスの表示領域が変化したとき)に実行される処理を設定することができます。

前述の通り、キャンバスがスクロールされたときに実行されるようにしたいのは、キャンバスの表示領域に応じてスクロールバーのスライダーの位置を設定する処理です。

このスライダーの位置を設定するメソッドとして、Scrollbar クラスには set メソッドが用意されています。

setメソッドの説明図

ですので、xscrollcommandyscrollcommand それぞれに対して、水平方向のスクロールバーオブジェクトの set メソッドと垂直方向のスクロールバーオブジェクトの set メソッドを設定してやれば、キャンバスがスクロールされたときに表示領域に合わせて自動的にスライダーの位置が設定されるようになります。

setが実行されてスクロールバーの位置が変化する様子

2つの設定によりスクロールとスライドバーの位置設定が連動する

以上の2つの設定を行うことで、スクロールバーとキャンバスが関連付けられ、下記のように「キャンバスのスクロール」と「スクロールバーのスライダー」が “連動して” 動作するようになります。

  • ユーザーがスクロールバーのスライダーを動かす
  • スライダーが動いたので、スクロールバーの command に設定した xviewyview が実行される
  • キャンバスがスクロールされる(キャンバスの表示領域が変化する)
  • キャンバスがスクロールされたので、キャンバスの xscrollcommandyscrollcommand 実行される
  • スクロールバーのスライダーの位置がキャンバスのスクロール位置に合わせて設定される
MEMO

実はこの辺りの解説は、実際にソースコードを読んで確認したわけではなく、動作から推測したものになります…

もしかしたら動作の詳細が間違っている部分もあるかもしれませんが、とりあえずスクロールバー付きのキャンバスを作成するために下記の2つが必要なのは確かです

  • スクロールバーのスライダーが動かされた時に実行する処理を設定
  • キャンバススクロール時に実行する処理を設定

スポンサーリンク

スクロールバー付きのキャンバスの作り方のまとめ

特に最後の「キャンバスをスクロールするための設定」の仕組みは難しいかもしれませんが、要は下記を実行すれば、キャンバスをスクロールさせることができるようになります。

キャンバスをスクロールするための設定
# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=canvas.xview
)
ybar.config(
	command=canvas.yview
)


# キャンバススクロール時に実行する処理を設定
canvas.config(
	xscrollcommand=xbar.set
)
canvas.config(
	yscrollcommand=ybar.set
)

さらに、キャンバスの場合は、どこまでの領域をスクロールできるようにするかを、キャンバスに scrollregion で設定する必要があります。

スクロールする領域の設定
# キャンバスの作成と配置
canvas = tkinter.Canvas(
	# 略
	scrollregion=(-200, -100, 800, 600),
)

以上の設定により、スクロールバー付きのキャンバスを実現することができます。

また、見た目としてウィジェットにスクロールバーがくっついているようにする場合は、grid が便利です。

スクロールバーの配置
# キャンバスの下に水平方向のスクロールバーを配置
xbar.grid(
	row=1, column=0,  # キャンバスの下の位置を指定
	sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
)

# キャンバスの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=0, column=1,  # キャンバスの右の位置を指定
	sticky=tkinter.N + tkinter.S  # 上下いっぱいに引き伸ばす
)

キャンバス上の座標の扱いの注意点

スクロール可能なキャンバスを作成した際に注意点となるのが座標です。

スクロール可能なキャンバスを扱う際には、2つの種類の座標を区別して扱う必要があります。具体的には下記の2つです。

  • 表示されている領域の左上座標を原点とする座標
  • scrollregion(0, 0) 座標を原点とする座標

例えば、マウスイベントなどが発生した際にはマウスの現在座標を引数から取得することが可能ですが、その座標は前者の表示領域の左上座標を原点とする座標となります。

それに対し、キャンバスのメソッドに指定する必要があるのは後者の scrollregion(0, 0) 座標を原点とする座標となります。

ですのでマウスの現在座標をキャンバスのメソッドにそのまま指定してしまうと、本来指定すべき後者の座標ではなく、前者の座標を指定することになり、その結果アプリの動作がうまくいかない可能性があるので注意してください。

例えば下記は、マウスでクリックした位置に描画した正方形を移動させるスクリプトの良くない例になります。bind メソッドによりマウスクリック時に push 関数が実行されるよう設定されており、この push が実行された際には、マウスクリック時の座標を引数 event から得ることができます(event.x  と event.y)。

ただし、この座標は上記における前者の座標です。にも関わらず、得られた座標を利用してキャンバスのメソッド coords を実行しているため、スクロールバーでスクロールを行った後にマウスクリックをしても、クリックした位置に正方形が移動しません。

スクロール量を考慮しない場合
import tkinter

def push(event):

	x = event.x
	y = event.y

	canvas.coords(
		rect,
		x - 25, y - 25,
		x + 25, y + 25
	)

app = tkinter.Tk()

canvas = tkinter.Canvas(
	app,
	width=500, height=500,
	scrollregion=(-300, 0, 1000, 500),
	highlightthickness=0,
	bg="gray",
)
canvas.grid(row=0, column=0)

xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
)
xbar.grid(
	row=1, column=0,  # キャンバスの下の位置を指定
	sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
)

xbar.config(
	command=canvas.xview
)
canvas.config(
	xscrollcommand=xbar.set
)

rect = canvas.create_rectangle(
	0, 0, 50, 50,
	fill="blue",
)

canvas.bind("<ButtonPress>", push)

app.mainloop()

この例のように、スクロール可能なキャンバスを扱い、さらにキャンバスのメソッドに座標を指定する際には、下記の後者の座標を指定しないとアプリが意図した通りに動作してくれません。この点に注意が必要です。

  • 表示されている領域の左上座標を原点とする座標
  • scrollregion(0, 0) 座標を原点とする座標

もし、前者の座標から後者の座標に変換したい場合は、キャンバスの canvasx メソッドと canvasy メソッドを利用すると良いです。

canvasx メソッドの引数に前者の x 座標を指定して実行すれば、後者の x 座標に変換した結果を得ることができます。canvasy メソッドも同様に、引数に前者の y 座標を指定して実行すれば、後者の y 座標に変換した結果を得ることができます。

例えば先程の例のスクリプトであれば、push 関数が実行された際に得られるマウスの座標(event.xevent.y)を canvasx メソッドと canvasy メソッドにより変換し、変換後の座標を利用してキャンバスのメソッド coords を実行するようにすることで、スクロール後もクリックした位置に正方形が移動するようにすることができます。

スクロール量を考慮する場合
import tkinter

def push(event):

	x = canvas.canvasx(event.x)
	y = canvas.canvasy(event.y)

	canvas.coords(
		rect,
		x - 25, y - 25,
		x + 25, y + 25
	)

今回の例だと縦方向のスクロールバーは付けていないので canvasy メソッドで変換しなくても良いといえば良いのですが、特にスクロールバーを利用する際は、マウスの座標をキャンバスのメソッドに指定する前には、canvasx と canvasy で座標の変換を行うようにした方が無難だと思います。

スクロールバー付きのウィジェットの作り方(キャンバス以外)

次は、キャンバス以外のスクロールバー付きのウィジェットの作り方について紹介していきたいと思います。

スポンサーリンク

作り方はキャンバスの時とほぼ同じ

結論を言うと、作り方は “ほぼ” キャンバスの時と同じです。

要は、作成したスクロールバーとウィジェットに対して下記を行えば良いです。

ウィジェットをスクロールするための設定
# widgetは各種ウィジェットのオブジェクト
# xbarは水平方向のスクロールバーオブジェクト
# ybarは垂直方向のスクロールバーオブジェクト

# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=widget.xview
)
ybar.config(
	command=widget.yview
)


# ウィジェットスクロール時に実行する処理を設定
widget.config(
	xscrollcommand=xbar.set
)
widget.config(
	yscrollcommand=ybar.set
)

また、スクロールバーの配置も同様に行うことができます。

スクロールバーの配置
# widgetは各種ウィジェットのオブジェクト
# xbarは水平方向のスクロールバーオブジェクト
# ybarは垂直方向のスクロールバーオブジェクト

# ウィジェットの配置(rとcは配置したい位置に応じて変更)
widget.grid(row=r, column=c)

# ウィジェットの下に水平方向のスクロールバーを配置
xbar.grid(
	row=r+1, column=c,  # ウィジェットの下の位置を指定
	sticky=tkinter.W + tkinter.E  # 左右いっぱいに引き伸ばす
)

# ウィジェットの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=r, column=c+1,  # ウィジェットの右の位置を指定
	sticky=tkinter.N + tkinter.S  # 上下いっぱいに引き伸ばす
)

ただし、キャンバスとは異なり、scrollregion の設定は不要です。

キャンバスの場合は scrollregion でスクロール可能な領域を設定する必要がありましたが、他のウィジェットに関しては、入力されている文字列(はみ出している文字列)からスクロール可能な領域を勝手に tkinter が判断してくれるようです。

xviewyview メソッドを持つウィジェット

で、上記の設定を行うためには、xview や yview メソッドが必要です。

つまり、基本的には、このメソッドが用意されているウィジェットにしかスクロールバーは付けることができません(付けたとしても連動して動作させることができません)。

これらのメソッドが用意されているウィジェットは、キャンバスを除くと私が知っているのは下記の4つになります。

  • リストボックス(Listbox
  • エントリー(Entry)
    • xview のみ
  • スピンボックス(Spinbox)
    • xview のみ
  • テキストボックス(Text

エントリーとスピンボックスに関しては、そもそも “1行分のテキストのみ” を入力するためのウィジェットなので、垂直方向のスクロールバーには対応していないようです(yview メソッドが用意されていない)。

また、これは他の環境では動作が異なるかもしれませんが、テキストボックスの場合は水平方向のスクロールバーを付けても動作はしませんでした(入力した文字列がテキストボックスの横方向のサイズを超える場合では、勝手に折り返される)。

以上を踏まえて、「スクロールバー付きのリストボックス」、「スクロールバー付きのエントリー」、「スクロールバー付きのスピンボックス」、「スクロールバー付きのテキストボックス」それぞれを作成するスクリプトを下記で紹介していきます。

スクロールバー付きのリストボックス

スクロールバー付きのリストボックスを作成するスクリプトの例は下記のようになります。

スクロールバー付きのリストボックス
# -*- coding:utf-8 -*-
import  tkinter

# メインウィンドウの作成
app = tkinter.Tk()

# リストボックスの作成と配置
N = 5

contents = (
	"abcdefghijklmnopqrstuvwxyz",
	"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
	"MondayTuesdayWednesday",
	"ThursdayFridaySaturdaySunday"
	"JanuaryFebruaryMarchAprilMayJune",
	"JulyAugustSeptemberOctoberNovemberDecember",
	"sin",
	"cos",
	"tan",
)

listbox = tkinter.Listbox(
	app,
	width=20,
	height=5,
	font=("", 40),
	listvariable=tkinter.StringVar(value=contents),
)
listbox.grid(row=0, column=0)

# 水平方向のスクロールバーを作成
xbar = tkinter.Scrollbar(
	app, # 親ウィジェット
	orient=tkinter.HORIZONTAL, # バーの方向
)

# 垂直方向のスクロールバーを作成
ybar = tkinter.Scrollbar(
	app, # 親ウィジェット
	orient=tkinter.VERTICAL, # バーの方向
)

# リストボックスの下に水平方向のスクロールバーを配置
xbar.grid(
	row=1, column=0, # リストボックスの下の位置を指定
	sticky=tkinter.W + tkinter.E # 左右いっぱいに引き伸ばす
)

# リストボックスの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=0, column=1, # リストボックスの右の位置を指定
	sticky=tkinter.N + tkinter.S # 上下いっぱいに引き伸ばす
)


# リストボックスをスクロールするための設定

# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=listbox.xview
)
ybar.config(
	command=listbox.yview
)


# リストボックススクロール時に実行する処理を設定
listbox.config(
	xscrollcommand=xbar.set
)
listbox.config(
	yscrollcommand=ybar.set
)


# メインループ
app.mainloop()

実行すると下のアニメーションのように、スクロールバーを動かすことでリストボックス内がスクロールされます。

スクロールバー付きのリストボックスの例

スポンサーリンク

スクロールバー付きのエントリー

スクロールバー付きのエントリーを作成するスクリプトの例は下記のようになります。

スクロールバー付きのエントリー
# -*- coding:utf-8 -*-
import  tkinter

# メインウィンドウの作成
app = tkinter.Tk()

# エントリーの作成と配置
entry = tkinter.Entry(
	app,
	width=10,
	font=("", 150)
)
entry.grid(row=0, column=0)

# 水平方向のスクロールバーを作成
xbar = tkinter.Scrollbar(
	app, # 親ウィジェット
	orient=tkinter.HORIZONTAL, # バーの方向
)


# エントリーの下に水平方向のスクロールバーを配置
xbar.grid(
	row=1, column=0, # エントリーの下の位置を指定
	sticky=tkinter.W + tkinter.E # 左右いっぱいに引き伸ばす
)


# エントリーをスクロールするための設定

# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
	command=entry.xview
)

# エントリースクロール時に実行する処理を設定
entry.config(
	xscrollcommand=xbar.set
)

# メインループ
app.mainloop()

実行すると下のアニメーションのように、スクロールバーを動かすことでエントリー内がスクロールされます。

スクロールバー付きのエントリーの例

スクロールバー付きのスピンボックス

スクロールバー付きのスピンボックスを作成するスクリプトの例は下記のようになります。

スクロールバー付きのスピンボックス
# -*- coding:utf-8 -*-
import tkinter

# メインウィンドウの作成
app = tkinter.Tk()

# スピンボックスの作成と配置
spinbox= tkinter.Spinbox(
    app,
    width=10,
    font=("", 150)
)
spinbox.grid(row=0, column=0)

# 水平方向のスクロールバーを作成
xbar = tkinter.Scrollbar(
    app, # 親ウィジェット
    orient=tkinter.HORIZONTAL, # バーの方向
)


# スピンボックスの下に水平方向のスクロールバーを配置
xbar.grid(
    row=1, column=0, # スピンボックスーの下の位置を指定
    sticky=tkinter.W + tkinter.E # 左右いっぱいに引き伸ばす
)


# スピンボックスをスクロールするための設定

# スクロールバーのスライダーが動かされた時に実行する処理を設定
xbar.config(
    command=spinbox.xview
)

# スピンボックススクロール時に実行する処理を設定
spinbox.config(
    xscrollcommand=xbar.set
)

# メインループ
app.mainloop()

実行すると下のアニメーションのように、スクロールバーを動かすことでスピンボックス内がスクロールされます。

スクロールバー付きのスピンボックスの例

スクロールバー付きのテキストボックス

スクロールバー付きのテキストボックスを作成するスクリプトの例は下記のようになります。

スクロールバー付きのテキストボックス
# -*- coding:utf-8 -*-
import  tkinter

# メインウィンドウの作成
app = tkinter.Tk()

# テキストボックスの作成と配置
textbox = tkinter.Text(
	app,
	width=10,
	height=5,
	font=("", 40)
)
textbox.grid(row=0, column=0)

# 垂直方向のスクロールバーを作成
ybar = tkinter.Scrollbar(
	app, # 親ウィジェット
	orient=tkinter.VERTICAL, # バーの方向
)

# テキストボックスの右に垂直方向のスクロールバーを配置
ybar.grid(
	row=0, column=1, # テキストの右の位置を指定
	sticky=tkinter.N + tkinter.S # 上下いっぱいに引き伸ばす
)


# テキストボックスをスクロールするための設定

# スクロールバーのスライダーが動かされた時に実行する処理を設定
ybar.config(
	command=textbox.yview
)


# テキストボックススクロール時に実行する処理を設定
textbox.config(
	yscrollcommand=ybar.set
)

# メインループ
app.mainloop()

実行すると下のアニメーションのように、スクロールバーを動かすことでテキストボックス内がスクロールされます。

スクロールバー付きのテキストボックスの例

スポンサーリンク

スクロールバーの設定

ここからはスクロールバーの作成時(tkinter.Scrollbar() 実行時)や config メソッド実行時にキーワード引数で指定する「スクロールバーの設定」について解説していきます。

設定できる全てのキーワードは下記により確認することができます。

設定可能なキーワード
# barはScrollbarのインスタンス
print(bar.keys())

ここでは私がよく使うもの・動作を理解しているものをピックアップして説明していきたいと思います。といっても、スクロールバーで特に重要な設定は下記の3つくらいだと思います。

  • orient
  • command
  • width
MEMO

私の下記環境での実行結果をもとに説明していますが、環境によっては動きが異なるかもしれません

実際にご自身の環境で実行結果を確認していただくと、より確実に設定の効果を理解することができると思います

  • OS:macOS Big Sur(11.2.3)
  • Python:3.8
  • Tkinter:8.6

orient

orient キーワード引数により、そのスクロールバーを「水平方向のスクロールバー」か「垂直方向のスクロールバー」のどちらにするかをを設定することができます。

orient設定によるスクロールバーの方向の違い

具体的に orient に指定するパラメータは下記のようになります。

  • 水平方向のスクロールバー:tkinter.HORIZONTAL
  • 垂直方向のスクロールバー:tkinter.VERTICAL

orient を指定しなかった場合は、デフォルトの tkinter.VERTICAL が適用されます。

command

commandキーワード引数を指定することで、スクロールバーが動かされたときに実行される処理を設定することができます。

基本的には、この command に設定するパラメータは下記になります(widget は各ウィジェットのオブジェクト)。

  • 水平方向のスクロールバー:widget.xview
  • 垂直方向のスクロールバー:widget.yview

スクロールバー付きのキャンバスの作り方でも説明しましたが、これらを設定することにより、スクロールバーを動かしたときにウィジェットの表示領域が自動的に変化するようになります。

必ず xviewyview を設定しなければならないということもないですが、スクロールバーとウィジェットを連動させるためには、これらを指定するのが一般的だと思います。

スポンサーリンク

width

width キーワード引数を指定することで、スクロールバーの幅を設定することができます。どの方向に対する “幅” であるかは、スクロールバーの方向(orient 設定)によって変わります。

  • 水平方向のスクロールバー:縦方向の幅
  • 垂直方向のスクロールバー:横方向の幅

widthの説明図

width では、上記とは異なる方向の幅は設定できませんので、配置するときにサイズを調整するのが良いと思います。

例えばスクロールバー付きのキャンバスの作り方では、ウィジェットのサイズに合わせてスクロールバーを引き伸ばすために、grid メソッドに sticky を指定して配置を行うようにしています。

jump

jump キーワード引数を指定することで、ウィジェットのスクロールが行われるタイミングを変更することができます。

通常は、マウスでスライダーをクリックし、クリックしたままスライダーを動かすと、即座にスクロールが行われます。

一方で jump=1 を指定すれば、マウスのクリックを離したタイミングで、スライダーの位置に合わせてスクロールが行われるようになります。

デフォルト設定は jump=0 になります。 

repeatdelayrepeatinterval

スクロールバーでは、スライダー自身をマウスで動かすだけでなく、スライダーの周りの窪みをクリックすることでもスライダーを動かすことができます。

窪みをクリックしてスライドバーが移動する様子

この時、スライダーの周りの窪みをクリックし続けた(押し続けた)場合には、繰り返しクリックしたかのように、一定間隔でスライダーが動き続けます。

この時の間隔を設定するのが repeatdelayrepeatinterval になります。

クリックし続けて最初にスライダーが動作するまでの時間を repeatdelay で、その後スライダーが動作する間隔を repeatinterval で設定可能です。

repeatdelayとrepeatintervalの説明図

例えば下記のように設定した場合、

repeatdelayとrepeatinterval
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	repeatdelay=2000,
	repeatinterval=100
)

窪みをクリックし続けると、クリックし続けてから 2000 ms 経過したタイミングでスライダーが移動し、その後は 100 ms 間隔でスライダーが移動し続けます。

repeatdelayとrepeatintervalの設定例

実際に窪みをクリックし続けてスライダーを移動させた時の様子が下のアニメーションになります(ちょっとわかりにくいかな…)。

repeatdelayとrepeatintervalを設定した時のアプリの動作

スポンサーリンク

takefocus

takefocus キーワード引数を指定することで、タブキーによるフォーカスの有効無効を設定することができます。

フォーカスがあてられたスクロールバーは、水平方向のスクロールバーの場合は左右キーで、垂直方向のスクロールバーの場合は上下キーでスライダーを移動させることができるようになります。

このフォーカスをあてられるかどうかを、takefocus に下記のように指定すること設定することができます。

  • takefocus=0:フォーカスがあてられない
  • takefocus=1:フォーカスがあてられる

デフォルト設定は takefocus=1 になります。

bd(borderwidth)

bd(borderwidth) の指定により、スクロールバーの枠線の太さを設定することができます。

例えば下記のように bd を設定すれば、スクロールバーの枠線の太さが 20 px になります。

bd
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
	bd=20,
)

ただし、bd を大きくするとスクロールバーのスライダーの位置が若干狂うようでした。私の環境だけかもしれませんが、bd は大きく設定しない方が無難だと思います。

bg(background)

bg(background) の指定により、スクロールバーの枠線の色を設定することができます。

MEMO

これは私が試した環境での動作結果になります

もしかしたら環境によっては、bg の指定で色が変わるのは “スライダーの色” になるかもしれません

例えば下記のように bg を設定すれば、スクロールバーの枠線の色が "green" になります。

bg
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
	bd=20,
	bg="green",
)

上記で作成したスクロールバーを配置したアプリを起動すると下の図のような画面が表示されます。

bdとbgの設定例

スポンサーリンク

relief

relief の指定により、スクロールバーの見た目を設定することができます。

MEMO

これは私が試した環境での動作結果になります

もしかしたら環境によっては、relief の指定で見た目が変わるのは “スライダー” になるかもしれません

relief に指定できるのは下記の6つになります(デフォルトは tkinter.SUNKEN)。

  • tkinter.RAISED
  • tkinter.SUNKEN
  • tkinter.FLAT
  • tkinter.RIDGE
  • tkinter.GROOVE
  • tkinter.SOLID

例えば下記のように relief を設定すれば、スクロールバーが “浮き出る” ような見た目なります。

relief
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
	bd=20,
	bg="green",
	relief=tkinter.RAISED,
)

上記で作成したスクロールバーを配置したアプリを起動すると下の図のような画面が表示されます。

reliefの設定

スクロールバーの枠線が細いと(つまり bd の値が小さいと)、この relief の指定による見た目の変化がわかりにくいので注意してください。

highlightcolorhighlightbackgroundhighlightthickness

highlightcolorhighlightbackgroundhighlightthickness の指定により、スクロールバーにフォーカスがあてられた時&フォーカスが外れた時のスクロールバーの囲い線の設定が可能です。

  • highlightcolor:フォーカスがあてられた時の囲い線の色
  • highlightbackground:フォーカスが外れた時の囲い線の色
  • highlightthickness:囲い線の太さ(px)

下記はこれらのキーワードを指定する例になります。

hilight関連
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	orient=tkinter.HORIZONTAL,  # バーの方向
	highlightbackground="green",
	highlightthickness=10,
	highlightcolor="red",
)

上記で作成したスクロールバーを配置したアプリを起動すると下の図のような画面が表示されます。

hilight関連の設定例1

下側の水平方向のスクロールバーの緑色の線が、フォーカスに対する囲い線になります。この囲い線の太さが、highlightthickness で指定している 10 px になります。

また、現状このスクロールバーにフォーカスが当たっていないので、この囲い線の色は highlightbackground で指定している "green" になります。

この状態でタブキーを押してスクロールバーにフォーカスをあてると、今度はこの囲い線の色が highlightcolor で指定している "red" に変化します。

hilight関連の設定例2

cursor

cursor キーワード引数を指定することで、スクロールバー上でのマウスカーソルの見た目(アイコン)を変更することができます。

例えば私の環境では、"hand" を設定すれば、スクロールバー上にマウスカーソルを合わせるとカーソルの見た目が “手” に変わります。

cursor
xbar = tkinter.Scrollbar(
	app,  # 親ウィジェット
	cursor="hand", # カーソルのアイコンを変更
)

MacOSX の場合は、cursor に下記のようなパラメータを設定することが可能です。おそらく設定可能なパラメータは OS 等によって異なるので注意してください。

  • "hand"
  • "ibeam"
  • "wait"
  • "poof"

スポンサーリンク

Scrollbar クラスのメソッド

最後に Scrollbar クラスに用意されたメソッドについて紹介していきたいと思います。

全ウィジェットで共通のメソッドについては省略し、Scrollbar クラス特有のメソッドを紹介していきたいと思います。

get

get はスクロールバーのスライダーの現在位置を取得するメソッドになります。

get
# barはスクロールバーのオブジェクト
start, end = bar.get()

スライダーの位置は「開始位置」と「終了位置」の2つによって決まります。get メソッドの戻り値もこの2つになります。

setメソッドの説明図

また、この「開始位置」と「終了位置」は 01 の値になります。

この値の意味は、スクロールバーの左端(上端)を 0、右端(下端)を 1 とした時の、それぞれの相対的な位置になります。

スライダーの位置の表現

ちなみに、スライダーの幅(つまり 終了位置 - 開始位置 の値)は表示されている領域のサイズとスクロール可能な領域のサイズから自動的に tkinter によって設定されます。

set

set はスクロールバーのスライダーの位置を設定するメソッドになります。

set
# barはスクロールバーのオブジェクト
bar.set(start, end)

set メソッドの引数は下記の2つになります。

  • start:スライダーの開始位置(01
  • end:スライダーの終了位置(01

開始位置、終了位置ともに、get メソッド同様に、スクロールバーの左端(上端)を 0、右端(下端)を 1 とした時の、それぞれの相対的な位置を指定します。

setメソッドの説明図

スポンサーリンク

fraction

get メソッドの解説時にも説明しましたが、スクロールバー上の位置は左端(上端)を 0、右端(下端)を 1 とした 01 の値で表現されます。

fractionメソッドの説明図

fraction は、ピクセル単位の座標をこのスクロールバー上の位置に変換するメソッドです。

fraction
# barはスクロールバーのオブジェクト
pos = bar.fraction(x, y)

fraction メソッドの引数は下記の2つになります。

  • x:横方向の座標
  • y:縦方向の座標

delta

fraction が単なる座標をスクロールバー上の位置に変換するメソッドであるのに対し、delta はピクセル単位の横方向と縦方向それぞれの移動量を、スクロールバー上の位置で考えた時の移動量に変換するメソッドになります。

deletaメソッドの説明図

移動量なので、負の値の設定も可能であり、その場合は delta メソッドも負の値を返却します。負の値の場合は、水平方向のスクロールバーの場合は左方向に、垂直方向のスクロールバーの場合は上方向に移動したことを表します。

delta
# barはスクロールバーのオブジェクト
pos = bar.delta(dx, dy)

delta メソッドの引数は下記の2つになります。

  • dx:横方向の移動量
  • dy:縦方向の移動量

まとめ

このページでは、Tkinter でスクロールバーを作成する方法・設定の詳細・スクロールバーに用意されたメソッドについて解説しました。

スクロールバーのメイン機能は他のウィジェットをスクロールさせることです。

そのため、スクロールバーは単に作成するだけでなく、他のウィジェットをスクロールするための設定を行う必要があります。この辺りがスクロールバーウィジェット特有のポイントになります。

是非ご自身でスクロールバー付きのウィジェットを作成し、その動きを確認しながらスクロールバーウィジェットへの理解を深めてみてください!

オススメ参考書(PR)

Tkinter に興味がある方には下記のPythonでつくる ゲーム開発 入門講座がオススメです。

Tkinter をゲーム開発を通して「楽しく学ぶ」ことができます。Python 入門者、Tkinter 入門者の方にオススメです。

同じカテゴリのページ一覧を表示