tkinter で スクロール可能なcanvasを作る

tkinter で スクロール可能なcanvasを作る

概要

tkinterでスクロール可能なcanvasのクラスScrollableCanvasを作ってみました。
ぶっちゃけ、あちこちにその手の記事はあるのですが、なんか自分のコーディングスタイルとあってないの気がしたので 微妙に書き換えてみました。

サンプルプログラム

さっそくサンプルプログラムを貼りつけておきます。

解説のようなもの

canvas を継承した ScrollableCanvas クラス

ネット上にある例では、Frameクラスを継承してその下にcanvasを貼り付けているものが多いですが、 なんとなく余分なウィジェットを作りたくない気分だったのでCanvasクラスを継承するようにしてみました。
また、コンストラクタ中でpackしている例が多かったですが、配置の自由度を上げるため上位側に任せるようにしました。

コンストラクタ

今回は縦スクロールのみ対応なので、canvasの幅はあらかじめ指定しておくようにしてあります。
また、表示するウィジェットを配置するためのフレーム(child_frame)は幅を自由に設定できるようにすると 親ウィジェットであるcanvasの幅まで大きくなりますが、これだとスクロールバーが見えなくなります。
そこで、child_frameの幅はcanvasの幅からスクロールバーの幅を差し引いたサイズを設定しています。

[!NOTE] 縦横スクロール可能にした場合は このあたり見直さないといけないかもしれない。

また、マウスドラッグによるスクロールをスムーズにするため、スクロール量(yscrollincrement)のデフォルトを1に設定しています。 これはScrollableCanvasクラスのインスタンスを生成する際に変更することができます。

ウィンドウイベント

"<Configure>" イベントをbindすることで、ウィンドウが移動されたり、リサイズされたりしたときに実行する処理を割り当てています。
"<Configure>" イベントはウィンドウのリサイズ等だけでなく、pack()等でFrameのサイズが変更されたときも通知されます。

ここではスクロール範囲の再設定を行っています。

マウスイベント

マウスイベントのbindは tkinter で 低層のウィジェットでイベントを検出する の方法を使用しています。

操作 処理
左クリック ドラッグ開始位置の設定
左クリック→マウス移動 縦方向の移動量に応じたスクロール
左ダブルクリック 子ウィジェットの追加
ホイール 縦方向スクロール
右クリック 子ウィジェットの全削除

実は…

右クリックで子ウィジェットを全削除した際、child_frameの高さは削除前の高さのままになっています。
つまり、なにもないフレームをスクロールできる状態になっています。
次に左ダブルクリックでウィジェットを追加したときに1ジェット1個分の高さに変更されます。
この仕様が気持ち悪くて色々試したのですが、うまくいきませんでした。
そこで、「cleard」と表示してchild_frameの高さを変更して誤魔化しています。
子ウィジェットの差し替えしかしないのであれば特に気にしなくても良い部分だと思います。