🐈‍⬛

Python + Kivy で作ってみた【Ⅱ】

2023/06/22に公開

canvasの謎

ヘッダーに画像がはみ出して表示される問題を考えていて
canvasの認識が違うのではないかと思い始めた

なぜかというと、画像の表示位置をを指定できるようにプロパティを追加して
表示位置をいろいろと設定してみると、フッターにはみ出して表示されることがない

widgetの範囲だけcanvasの内容が見えるものだと考えていたが、
どうやら違うようだ⚡

各widgetのcanvasはwindow全体が見える範囲となっている
ただし、widgetの階層構造に従って各widgetのcanvasの見える範囲が変わる
今、widgetの階層構造は下からヘッダー、表示部、フッターの順となっている
そのため

  • ヘッダーで指定したcanvasはヘッダーの範囲
  • 表示部で指定したcanvasはヘッダーと表示部の範囲
  • フッターで指定したcanvasはヘッダー、表示部、フッターの範囲

が見えることになる
ただし、\textcolor{blue}{\underbar{\text{canvasをベタ塗りしている場合で、塗ってなければ透けて見える}}}

階層構造変更

widgetの階層構造を次のように変更した

  • ヘッダー
  • 表示部
  • フッター
    ⬇️
  • 表示部
  • ヘッダー
  • フッター

kvファイル変更

<CtrlPanelWidget>:
    FloatLayout:

        ViewAreaWidget:
            size_hint:      None, None
            size:           self.parent.width, self.parent.height * 8 / 10
            x:              0
            y:              self.parent.height / 10

            canvas:
                Rectangle:
                    texture:        self.image_texture
                    size:           self.image_width, self.image_height
                    pos:            self.to_parent( self.image_x, self.image_y, relative = True )

        HeaderWidget:
            size_hint:      None, None
            size:           self.parent.width, self.parent.height / 10
            x:              0
            y:              self.parent.height * 9 / 10

            canvas.before:
                Color:
                    rgb:        [ 1, 1, 1 ]

                Rectangle:
                    size:       self.size
                    pos:        self.pos

        FooterWidget:
            size_hint:      None, None
            size:           self.parent.width, self.parent.height / 10
            x:              0
            y:              0

            canvas.before:
                Color:
                    rgb:        [ 1, 1, 1 ]

                Rectangle:
                    size:       self.size
                    pos:        self.pos

階層構造の順序は、kvファイルの記述順となる
それ故に、ViewAreaWidget、HeaderWidget、FooterWidgetと記述すると
表示部の下にヘッダーが表示されてしまう

そこで、CtrlPanelWidget内を任意の位置に配置できるFloatLayoutにする
そして、ViewAreaWidget、HeaderWidget、FooterWidget各widgetの
x,yプロパティを設定して表示位置を指定する(座標はwindow左下が原点)

なお、widgetのサイズを指定する場合は、
size_hint:  None, None
を必ず記述しないといけない

また、HeaderWidget、FooterWidgetのcanvasは
各widgetの位置とサイズ部分を忘れずにベタ塗りする

ViewAreaWidgetのcanvasにはPDF画像表示の仕込みを行う

\dagger{} canvasにPDF画像を表示する位置について
表示位置は便宜上ViewArewidgetの左下を原点として考える
一方、canvasはwindowの左下が原点となっている
そのため、PDF画像を描画するRectangleのposに
座標を変換する「to_parent」メソッドを使っている

pythonコード部変更

class ViewArea( Widget ) :
    image_texture   = ObjectProperty( None )
    image_x         = NumericProperty( 0 )
    image_y         = NumericProperty( 0 )
    image_width     = NumericProperty( 0 )
    image_height    = NumericProperty( 0 )

    def on_kv_post( self, base_widget ) :
        di_texture = pdf_to_texture( self.filename )
        self.image_x        = 0
        self.image_y        = self.height - di_texture.height
        self.image_width    = di_texture.width
        self.image_height   = di_texture.height
        self.image_texture  = di_texture


新たに表示位置を指定するimage_x、image_yプロパティを追加する

image_yには、PDF画像をその高さ分下へ動かしViewAreaWidgetの高さ分戻す
そんなイメージで値を設定すれば、左上から表示されるはず?

これで実行してみると…
PDF画像の大きさそのままで、表示部の左上から表示されるようになった
∩(´∀`)∩


次回は、マウスドラッグでPDF画像の表示位置を変えてみよう

Discussion