いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

Windowのリサイズ時の描画のずれについて (GDI+, Control, ResizeRedraw, OnResize, Graphics, Ellipse)


Graphicsオブジェクトを用いて、直接描画を行った場合には以下の注意が必要となります。

ウィンドウがリサイズされた際には、新たに表示される領域のみに対してInvalidateが発生する。


つまり、リサイズされる前の領域は更新されません。
例外として、ウィンドウがHideもしくはRestoreされた際は復帰時に全体にInvalidateされます。


なので、リサイズされた際に、元の描画領域にも更新が必要な場合はその処理をかかなければなりません。


以下サンプルです。このプログラムを実行するとフォームの全体に楕円が描画されます。
ウィンドウを広げてみたりすると、元の領域はそのままで、新たに楕円が描画されます。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Gsf.Demo{
    
    public class DemoForm : Form{

        public DemoForm(){
            InitializeComponent();

            Paint += (s, e) => {

                using(Pen rectPen = new Pen(Color.Red, 5)){
                    e.Graphics.DrawEllipse(rectPen, new Rectangle(new Point(0, 0), ClientSize));
                }
            };
        }
        
        protected void InitializeComponent(){
            
            SuspendLayout();

            ResumeLayout();
        }

        [STAThread]
        static void Main(){
            Application.EnableVisualStyles();
            Application.Run(new DemoForm());
        }
    }

}

これを解決する最も簡単なやり方は、コントロール(Control)クラスの以下のプロパティを
trueにします。

ResizeRedraw = true;

みたままのプロパティですが、これでリサイズ時に再描画がかかるようになります。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Gsf.Demo{
    
    public class DemoForm : Form{

        public DemoForm(){
            InitializeComponent();

            Paint += (s, e) => {

                using(Pen rectPen = new Pen(Color.Red, 5)){
                    e.Graphics.DrawEllipse(rectPen, new Rectangle(new Point(0, 0), ClientSize));
                }
            };
        }
        
        protected void InitializeComponent(){
            
            SuspendLayout();

            ResizeRedraw = true;

            ResumeLayout();
        }

        [STAThread]
        static void Main(){
            Application.EnableVisualStyles();
            Application.Run(new DemoForm());
        }
    }

}

もう一つは、OnResizeメソッドをオーバーライドして自前で再描画を要求するやりかたです。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Gsf.Demo{
    
    public class DemoForm : Form{

        public DemoForm(){
            InitializeComponent();

            Paint += (s, e) => {

                using(Pen rectPen = new Pen(Color.Red, 5)){
                    e.Graphics.DrawEllipse(rectPen, new Rectangle(new Point(0, 0), ClientSize));
                }
            };
        }
        
        protected void InitializeComponent(){
            
            SuspendLayout();

            ResumeLayout();
        }

        protected override void OnResize(EventArgs e){
            base.OnResize(e);
            Invalidate(true);
        }
        
        [STAThread]
        static void Main(){
            Application.EnableVisualStyles();
            Application.Run(new DemoForm());
        }
    }

}


通常は、ResizeRedrawプロパティの方を良く使います。