ウィンドウコントロールでスクロールインした領域を描画する - C#
ウィンドウコントロールでスクロールインした領域を描画するコードを紹介します。
概要
こちらの記事ではウィンドウコントロールで描画された内容をスクロールするコードを紹介しましたが、
すでに描画された内容はスクロールしますが、画面の外側からスクロールインしたコンテンツは描画されません。
この記事では、画面の外側からスクロールインしたコンテンツを描画するコードを紹介します。
プログラム
Windows Formアプリケーションを作成します。
UI
下図のフォームを作成します。Panelコントロールを1つ、Buttonを4つ配置します。
コード
以下のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ScrollWindowDemo
{
public partial class FormSimpleScrollDraw : Form
{
public const uint SW_SCROLLCHILDREN = 0x0001;
public const uint SW_INVALIDATE = 0x0002;
public const uint SW_ERASE = 0x0004;
public const uint SW_SMOOTHSCROLL = 0x0010;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int _Left;
public int _Top;
public int _Right;
public int _Bottom;
}
//[DllImport("user32.dll")]
//static extern int ScrollWindowEx(IntPtr hWnd, int dx, int dy, IntPtr prcScroll, IntPtr prcClip, IntPtr hrgnUpdate, IntPtr prcUpdate, uint flags);
[DllImport("user32.dll")]
static extern int ScrollWindowEx(IntPtr hWnd, int dx, int dy, ref RECT prcScroll, ref RECT prcClip, IntPtr hrgnUpdate, out RECT prcUpdate, uint flags);
public Point sc = new Point(0,0);
public FormSimpleScrollDraw()
{
InitializeComponent();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
int rWidth = 64;
int rHeiht = 64;
Pen p = new Pen(Color.FromArgb(0x5d, 0x86, 0xba), 1);
SolidBrush b = new SolidBrush(Color.FromArgb(0xcd, 0xdc, 0xef));
Font f = new Font("MS UI Gothic", 10);
SolidBrush bs = new SolidBrush(Color.FromArgb(0x00, 0x44, 0x99));
int idx = 0;
for (int y = 0; y < 12; y++) {
for (int x = 0; x < 12; x++) {
Rectangle drawRect = new Rectangle(x * rWidth + sc.X, y * rHeiht + sc.Y, rWidth, rHeiht);
if (e.ClipRectangle.IntersectsWith(drawRect) == true) {
e.Graphics.FillRectangle(b, drawRect);
e.Graphics.DrawRectangle(p, drawRect);
e.Graphics.DrawString(Convert.ToString(idx), f, bs, new Point(x * rWidth + sc.X + 2, y * rHeiht + sc.Y + 2));
}
idx++;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
PanelScroll(0, -16);
}
private void button2_Click(object sender, EventArgs e)
{
PanelScroll(-16, 0);
}
private void button3_Click(object sender, EventArgs e)
{
PanelScroll(16, 0);
}
private void button4_Click(object sender, EventArgs e)
{
PanelScroll(0, 16);
}
private void PanelScroll(int x,int y)
{
RECT rect = new RECT();
rect._Left = 0;
rect._Top = 0;
rect._Right = panel1.Width;
rect._Bottom = panel1.Height;
RECT clip = new RECT();
clip._Left = 0;
clip._Top = 0;
clip._Right = panel1.Width;
clip._Bottom = panel1.Height;
RECT udaterect = new RECT();
ScrollWindowEx(panel1.Handle, x, y, ref rect, ref clip, (IntPtr)null, out udaterect, SW_SCROLLCHILDREN);
sc.X += x;
sc.Y += y;
panel1.Invalidate(new Rectangle(udaterect._Left, udaterect._Top, udaterect._Right - udaterect._Left, udaterect._Bottom - udaterect._Top));
}
}
}
解説
スクロール量を保持する変数を用意します。初期値は(0,0)とします。
public Point sc = new Point(0,0);
描画部分
描画はPanelのPaintイベントに実装します。64pxの正方形のマスを描画します。マスは縦12個、横12個描画します。
スクロールに対応するため、描画する位置にsc変数の値を加算し、スクロールした量だけスライドして描画します。
また、描画時には、
PaintEventArgs
オブジェクトの
ClipRectangle
プロパティの値と描画する領域が重なるかを
IntersectsWith()
メソッドで判定し、
描画が必要な領域に含まれる場合にのみ描画処理を実行します。
int rWidth = 64;
int rHeiht = 64;
Pen p = new Pen(Color.FromArgb(0x5d, 0x86, 0xba), 1);
SolidBrush b = new SolidBrush(Color.FromArgb(0xcd, 0xdc, 0xef));
Font f = new Font("MS UI Gothic", 10);
SolidBrush bs = new SolidBrush(Color.FromArgb(0x00, 0x44, 0x99));
int idx = 0;
for (int y = 0; y < 12; y++) {
for (int x = 0; x < 12; x++) {
Rectangle drawRect = new Rectangle(x * rWidth + sc.X, y * rHeiht + sc.Y, rWidth, rHeiht);
if (e.ClipRectangle.IntersectsWith(drawRect) == true) {
e.Graphics.FillRectangle(b, drawRect);
e.Graphics.DrawRectangle(p, drawRect);
e.Graphics.DrawString(Convert.ToString(idx), f, bs, new Point(x * rWidth + sc.X + 2, y * rHeiht + sc.Y + 2));
}
idx++;
}
}
スクロール部分
以下は描画内容をスクロールするコードです。スクロールの動作については
こちらの記事を参照してください。
スクロールしたのち、スクロール量を
sc
変数に設定します。
private void button1_Click(object sender, EventArgs e)
{
PanelScroll(0, -16);
}
private void button2_Click(object sender, EventArgs e)
{
PanelScroll(-16, 0);
}
private void button3_Click(object sender, EventArgs e)
{
PanelScroll(16, 0);
}
private void button4_Click(object sender, EventArgs e)
{
PanelScroll(0, 16);
}
private void PanelScroll(int x,int y)
{
RECT rect = new RECT();
rect._Left = 0;
rect._Top = 0;
rect._Right = panel1.Width;
rect._Bottom = panel1.Height;
RECT clip = new RECT();
clip._Left = 0;
clip._Top = 0;
clip._Right = panel1.Width;
clip._Bottom = panel1.Height;
RECT udaterect = new RECT();
ScrollWindowEx(panel1.Handle, x, y, ref rect, ref clip, (IntPtr)null, out udaterect, SW_SCROLLCHILDREN);
sc.X += x;
sc.Y += y;
panel1.Invalidate(new Rectangle(udaterect._Left, udaterect._Top, udaterect._Right - udaterect._Left, udaterect._Bottom - udaterect._Top));
}
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。
[button1]をクリックします。描画内容が上方向にスクロールします。画面外からスクロールインする部分も描画されます。
[button2]をクリックします。描画内容が左方向にスクロールします。
[button3]をクリックすると描画内容が右方向にスクロールします。
[button4]をクリックすると、下方向にスクロールします。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用