Compact Frameworkで非矩形ウインドウ 2010
気がついたんだけど、Compact Frameworkで非矩形ウインドウで紹介していたShape.csはリンクが切れちゃってますね(´・ω・`)
っということで、同等品のソースをのせておきます(・∀・)
処理としてはDIBから矩形を作って、それをウインドウに適用する形になります。
っというわけで、まずはDIBを扱うクラスについて。
public struct DIBSection { // BITMAPFILEHEADER public int OffBits; // BITMAPINFOHEADER public int Width; public int Height; public int BitCount; public int scLine; public byte[] Data; public int GetPixel(int x, int y) { switch( BitCount ) { case 1: case 2: case 4: case 16: case 32: throw new NotSupportedException( "Supported only 8 or 24 bpp" ); case 8: return Data[( Height - y - 1 ) * scLine + x]; case 24: int pos = ( ( Height - y - 1 ) * scLine + x * 3 ); return ( Data[ pos ] << 16 ) + ( Data[ pos + 1 ] << 8 ) + ( Data[ pos + 2 ] ); default: throw new NotSupportedException( "Supported only 8 or 24 bpp" ); } } public static DIBSection GetDibData(Stream stream) { DIBSection data = new DIBSection(); BinaryReader reader = new BinaryReader( stream ); reader.BaseStream.Seek( 0, SeekOrigin.Begin ); if( reader.ReadByte() != 'B' || reader.ReadByte() != 'M' ) { throw new ArgumentException( "Invalid bitmap." ); } reader.BaseStream.Seek( 10, SeekOrigin.Begin ); data.OffBits = reader.ReadInt32(); reader.ReadInt32(); // biSize data.Width = reader.ReadInt32(); data.Height = reader.ReadInt32(); reader.ReadInt16(); // biPlanes data.BitCount = reader.ReadInt16(); reader.BaseStream.Seek( data.OffBits, SeekOrigin.Begin ); data.scLine = ( data.Width * ( data.BitCount >> 3 ) + 3 >> 2 ) << 2; data.Data = reader.ReadBytes( data.scLine * data.Height ); return data; } }
っで、次に使用するAPIの定義をしておきます。
internal static class NativeMethods { [DllImport( "coredll.dll", SetLastError = true )] internal static extern bool DeleteObject(IntPtr hObject); [DllImport( "coredll.dll", SetLastError = true )] internal static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); [DllImport( "coredll.dll", SetLastError = true )] internal static extern int CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RgnCombineMode fnCombineMode); [DllImport( "coredll.dll", SetLastError = true )] internal static extern int SetWindowRgn(IntPtr hWnd, IntPtr hRgn, int bRedraw); }
っということで、準備が出来たので矩形クラス。
public class Shape : IDisposable { private IntPtr hRgn; public IntPtr Region { get { return this.hRgn; } } public Shape(Stream stream) { RebuildRegion( stream, Color.Transparent ); } public Shape(Stream stream, Color color) { RebuildRegion( stream, color ); } ~Shape() { Dispose( false ); } public void Dispose() { Dispose( true ); GC.SuppressFinalize( this ); } public void Dispose(bool disposing) { if( this.hRgn != IntPtr.Zero ) { NativeMethods.DeleteObject( this.hRgn ); this.hRgn = IntPtr.Zero; } } private void RebuildRegion(Stream stream, Color color) { if( stream == null ) { throw new ArgumentNullException( "stream" ); } if( this.hRgn != IntPtr.Zero ) { NativeMethods.DeleteObject( this.hRgn ); } DIBSection data = DIBSection.GetDibData( stream ); if( data.BitCount != 24 ) { throw new NotSupportedException( "Supported only 24 bpp" ); } int mask; if( color == Color.Transparent ) { mask = data.GetPixel( 0, 0 ); } else { mask = ( color.B << 16 ) | ( color.G << 8 ) | color.R; } this.hRgn = NativeMethods.CreateRectRgn( 0, 0, 0, 0 ); for( int y = 0; y < data.Height; y ++ ) { for( int x = 0; x < data.Width; x++ ) { while( ( x < data.Width ) && ( data.GetPixel( x, y ) == mask ) ) { x++; } int left = x; while( ( x < data.Width ) && ( data.GetPixel( x, y ) != mask ) ) { x++; } if ( ( x - left ) > 0 ) { IntPtr hRgnRect = NativeMethods.CreateRectRgn( left, y, x, y + 1 ); NativeMethods.CombineRgn( this.hRgn, this.hRgn, hRgnRect, RgnCombineMode.RGN_OR ); NativeMethods.DeleteObject( hRgnRect ); } } } } public void Apply(Control c) { if( c == null ) { throw new ArgumentNullException( "c" ); } NativeMethods.SetWindowRgn( c.Handle, this.Region, 1 ); } }
やっていることはDIBの各Pixelから矩形をCombineRgn()して作成。
あとはApply()で対象のControlに対して矩形を適用します。
っということで、丸ボタンやマスコットはこれで出来ますね(・∀・)
Mix10での情報を待ちながら〜(´∀`)