C#制作不规则窗口 ( 24bit Color 以上适用 )

类别:.NET开发 点击:0 评论:0 推荐:

C#制作不规则窗口 ( 24bit Color 以上适用 )
時間: 2004/3/17
作者: Robert
參考: http://www.codeproject.com/csharp/bmprgnform.asp?target=region
電郵: [email protected]
關鍵字: Region Gif 不規則 窗口 視窗 GraphicsPath 按鈕 圖片 Form Button
目的: 幫助受 C# 不規則窗口困擾的人
介紹
這篇文章說明怎麼製作圖片按鈕和窗體. Region 技術不但能做不規則窗口, 也能做不規則控件外觀, 比

如說不規則按鈕.
程序介紹
說明: 我修改程序介紹中的注釋, 不修改程序列表的說明. 畢竟 E 文我們看起來沒有中文舒服.
1. 主函數說明
下面的程序用倆個主函數產生 位圖區域 (bitmap regionss ), 源代碼放在 BitmapRegion.cs中, 你可

以直接導入這個類別, 使用裡面的函數.

// Create and apply the given bitmap region on the supplied control
// 產生支持位圖區域 ( bitmap region ) 控件
public static void CreateControlRegion(Control control, Bitmap bitmap)
{
    // 如果控件或者位圖不存在, 直接返回.
    if(control == null || bitmap == null)
        return;
           
    // 根據位圖大小設置控件尺寸
    control.Width = bitmap.Width;
    control.Height = bitmap.Height;

    // 處理 窗體 ( Form ) 類別
    if(control is System.Windows.Forms.Form)
    {
        // 強制轉換 control object 到 Form object
        Form form = (Form)control;

        // 由於我們的Form邊界類型 ( Form.FormBorderStyle ) 不是 None,
        // 所以我們的Form尺寸比位圖大一點
        form.Width += 15;
        form.Height += 35;
       
        // 設定 Form 邊界類型是 None
        form.FormBorderStyle = FormBorderStyle.None;

        // 設定 Form 背景圖片
        form.BackgroundImage = bitmap;

        // 計算圖片中不透明部分的邊界 (建議用 Gif 圖片 )
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

        // 建立區域 ( Region )
        form.Region = new Region(graphicsPath);
    }

    // 處理按鈕 ( button 類別 )
    else if(control is System.Windows.Forms.Button)
    {
        // control object 轉成 Button object 類別
        Button button = (Button)control;

        // 清除 Button 上面的文字
        button.Text = "";
               
        // 更改鼠標樣式是手狀鼠標
        button.Cursor = Cursors.Hand;

        // 設定背景圖樣
        button.BackgroundImage = bitmap;
               
        //計算圖片中不透明部分的邊界 (建議用 Gif 圖片 )
        GraphicsPath graphicsPath = CalculateControlGraphicsPath(bitmap);

        // 建立區域 ( Region )
        button.Region = new Region(graphicsPath);
    }
        // 這裡你可以模仿 Form 或者 Button 建立心的類別出歷程序, 比如Panel
}

// 計算圖片不透明區域 返回 GraphicsPath
private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
{
    // 建立GraphicsPath, 給我們的位圖路徑計算使用
    GraphicsPath graphicsPath = new GraphicsPath();

    // 使用左上角 (0,0) 點作為透明色
    // 如果這裡是紅色, 那麼我們計算是圖片中不包含紅色區域路徑
    Color colorTransparent = bitmap.GetPixel(0, 0);

    // 存儲第一個不透明點, 這個值決定我們開始檢查不透明區域.
    int colOpaquePixel = 0;

    // 檢查所有的行 ( Y axis )
    for(int row = 0; row < bitmap.Height; row ++)
    {
        // 重置 colOpaquePixel 值
        colOpaquePixel = 0;

        // 檢查所有的列 ( X axis )
        for(int col = 0; col < bitmap.Width; col ++)
        {
            // 如果是不透明點, 標記之後尋這個點之後的位置
            if(bitmap.GetPixel(col, row) != colorTransparent)
            {
                // 找到不透明點, 標記這個位置
                colOpaquePixel = col;

                // 建立新變量保存當前點位置
                int colNext = col;

                // 從找到的不透明點開始繼續搜索不透明點,
                //一直到找到透明點 或者 找到圖片寬度搜索完畢
                for(colNext=colOpaquePixel; colNext<bitmap.Width; colNext++)
                    if(bitmap.GetPixel(colNext, row) == colorTransparent)
                        break;

                // 把不透明區域加入我們的GraphicsPath
                graphicsPath.AddRectangle(new Rectangle(colOpaquePixel,
                                           row, colNext - colOpaquePixel, 1));

                // 找到之後不用搜索不透明點
                col = colNext;
            }
        }
    }

    // 返回計算出來的不透明圖片路徑
    return graphicsPath;
}
產生不規則窗體
下面這倆行代碼能產生不規則圖形. 你不必改變 Form.FormBorderStyle是None, 程序自己幫你做這件事

.
public class Form1 : System.Windows.Forms.Form
{
    // 導入背景圖片
    private Bitmap bmpFrmBack = new Bitmap(typeof(Form1), "back.bmp");

    public Form1()
    {
        InitializeComponent();

        // 讓你的床體透明吧
        BitmapRegion.CreateControlRegion(this, bmpFrmBack);
    }
}

產生不規則按鈕
和產生不規則窗體一樣產生不規則按鈕
public class Form1 : System.Windows.Forms.Form
{
    // 導入窗體背景圖片
    private Bitmap bmpFrmBack = new Bitmap(typeof(Form1), "back.bmp");
   
    // 導入按鈕背景圖片
    private Bitmap bmpBob = new Bitmap(typeof(Form1), "bob.bmp");

    public Form1()
    {
        InitializeComponent();

        // 產生不規則窗體
        BitmapRegion.CreateControlRegion(this, bmpFrmBack);
       
        // 產生不規則按鈕
        BitmapRegion.CreateControlRegion(button1, bmpBob);
    }
}
如果你想在鼠標盡入/離開按鈕的時候顯示不同不規則按鈕, 只需要在按鈕的 MouseLeave和MouseEnter

裡面寫上下面的代碼就可以了.
private void button1_MouseEnter(object sender, System.EventArgs e)
{
    // 產生不規則按鈕
    BitmapRegion.CreateControlRegion(button1, bmpBobSay);
}

private void button1_MouseLeave(object sender, System.EventArgs e)
{
    // 產生不規則按鈕
    BitmapRegion.CreateControlRegion(button1, bmpBob);
}
移動不規則窗口
因為不規則窗口沒有標題欄, 怎麼移動呢? 下面代碼給你答案, 代碼很簡單, 我就不做中文解釋了 ( 我

做中文的部分就是不規則窗體 )
private void Form1_MouseMove(object sender,
                                        System.Windows.Forms.MouseEventArgs e)
{
    // Check if dragging of the form has occurred
    if(e.Button == MouseButtons.Left)
    {
        // If this is the first mouse move event for left click dragging
        // of the form, store the current point clicked so that we can use
        // it to calculate the form's new location in subsequent mouse move
        // events due to left click dragging of the form
        if(isFirst == true)
        {
            // Store previous left click position
            prevLeftClick = new Point(e.X, e.Y);

            // Subsequent mouse move events will not be treated as first time,
            // until the left mouse click is released or other mouse click
            // occur
            isFirst = false;
        }

        // On subsequent mouse move events with left mouse click down.
        // (i.e. During dragging of form)
        else
        {
            // This flag here is to do alternate processing for the form
            // dragging because it causes serious flicking when u allow
            // every such events to change the form's location.
            // You can try commenting this out to see what i mean
            if(toBlock == false)
                this.Location = new Point(this.Location.X + e.X -
                    prevLeftClick.X, this.Location.Y + e.Y - prevLeftClick.Y);

            // Store new previous left click position
            prevLeftClick = new Point(e.X, e.Y);

            // Allow or deny next mouse move dragging event
            toBlock = !toBlock;
        }
    }

    // This is a new mouse move event so reset flag
    else
        isFirst = true;
}

完成程序列表
BitmapRegion.cs
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace BitmapRegionTest
{
 /// <summary>
 /// Summary description for BitmapRegion.
 /// </summary>
 public class BitmapRegion
 {
  public BitmapRegion()
  {}

  /// <summary>
  /// Create and apply the region on the supplied control
  /// </summary>
  /// <param name="control">The Control object to apply the region to</param>
  /// <param name="bitmap">The Bitmap object to create the region

from</param>
  public static void CreateControlRegion(Control control, Bitmap bitmap)
  {
   // Return if control and bitmap are null
   if(control == null || bitmap == null)
    return;
   
   // Set our control's size to be the same as the bitmap
   control.Width = bitmap.Width;
   control.Height = bitmap.Height;

   // Check if we are dealing with Form here
   if(control is System.Windows.Forms.Form)
   {
    // Cast to a Form object
    Form form = (Form)control;

    // Set our form's size to be a little larger that the

bitmap just
    // in case the form's border style is not set to none in

the first place
    form.Width += 15;
    form.Height += 35;

    // No border
    form.FormBorderStyle = FormBorderStyle.None;

    // Set bitmap as the background image
    form.BackgroundImage = bitmap;

    // Calculate the graphics path based on the bitmap supplied
    GraphicsPath graphicsPath =

CalculateControlGraphicsPath(bitmap);

    // Apply new region
    form.Region = new Region(graphicsPath);
   }

   // Check if we are dealing with Button here
   else if(control is System.Windows.Forms.Button)
   {
    // Cast to a button object
    Button button = (Button)control;

    // Do not show button text
    button.Text = "";
    
    // Change cursor to hand when over button
    button.Cursor = Cursors.Hand;

    // Set background image of button
    button.BackgroundImage = bitmap;
    
    // Calculate the graphics path based on the bitmap supplied
    GraphicsPath graphicsPath =

CalculateControlGraphicsPath(bitmap);

    // Apply new region
    button.Region = new Region(graphicsPath);
   }
  }

  /// <summary>
  /// Calculate the graphics path that representing the figure in the bitmap
  /// excluding the transparent color which is the top left pixel.
  /// </summary>
  /// <param name="bitmap">The Bitmap object to calculate our graphics path

from</param>
  /// <returns>Calculated graphics path</returns>
  private static GraphicsPath CalculateControlGraphicsPath(Bitmap bitmap)
  {
   // Create GraphicsPath for our bitmap calculation
   GraphicsPath graphicsPath = new GraphicsPath();

   // Use the top left pixel as our transparent color
   Color colorTransparent = bitmap.GetPixel(0, 0);

   // This is to store the column value where an opaque pixel is first

found.
   // This value will determine where we start scanning for trailing

opaque pixels.
   int colOpaquePixel = 0;

   // Go through all rows (Y axis)
   for(int row = 0; row < bitmap.Height; row ++)
   {
    // Reset value
    colOpaquePixel = 0;

    // Go through all columns (X axis)
    for(int col = 0; col < bitmap.Width; col ++)
    {
     // If this is an opaque pixel, mark it and search

for anymore trailing behind
     if(bitmap.GetPixel(col, row) != colorTransparent)
     {
      // Opaque pixel found, mark current

position
      colOpaquePixel = col;

      // Create another variable to set the

current pixel position
      int colNext = col;

      // Starting from current found opaque

pixel, search for anymore opaque pixels
      // trailing behind, until a transparent

pixel is found or minimum width is reached
      for(colNext = colOpaquePixel; colNext <

bitmap.Width; colNext ++)
       if(bitmap.GetPixel(colNext, row) ==

colorTransparent)
        break;

      // Form a rectangle for line of opaque

pixels found and add it to our graphics path
      graphicsPath.AddRectangle(new

Rectangle(colOpaquePixel, row, colNext - colOpaquePixel, 1));

      // No need to scan the line of opaque

pixels just found
      col = colNext;
     }
    }
   }

   // Return calculated graphics path
   return graphicsPath;
  }
 }
}
///////////////////////////////////////////////////////////////////////////////////////////

//////////
Form1.cs
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
//using System.Runtime.InteropServices;

namespace BitmapRegionTest
{
 /// <summary>
 /// Summary description for Form1.
 /// </summary>
 public class Form1 : System.Windows.Forms.Form
 {
//  [DllImport("user32.dll")]
//  private static extern bool PostMessage(IntPtr hWnd, int msg, long wParam,

long lParam);

  private System.Windows.Forms.Button button1;
  private System.Windows.Forms.Button button2;
  private System.Windows.Forms.Button button3;
  private System.Windows.Forms.Button button4;

  /// <summary>
  /// Required designer variable.
  /// </summary>
  private System.ComponentModel.Container components = null;

  // Load our bitmaps
  private Bitmap bmpFrmBack = new Bitmap(typeof(Form1), "back.bmp");
  private Bitmap bmpBob = new Bitmap(typeof(Form1), "bob.bmp");
  private Bitmap bmpBobSay = new Bitmap(typeof(Form1), "bobsay.bmp");
  private Bitmap bmpSmiles = new Bitmap(typeof(Form1), "smiles.bmp");
  private Bitmap bmpSmilesAngry = new Bitmap(typeof(Form1),

"smilesangry.bmp");
  private Bitmap bmpGreenBtnUp = new Bitmap(typeof(Form1), "greenbtnup.bmp");
  private Bitmap bmpGreenBtnDown = new Bitmap(typeof(Form1),

"greenbtndown.bmp");
  private Bitmap bmpX = new Bitmap(typeof(Form1), "x.bmp");
  private Bitmap bmpXSmile = new Bitmap(typeof(Form1), "xsmile.bmp");

  // To store the location of previous mouse left click in the form
  // so that we can use it to calculate the new form location during dragging
  private Point prevLeftClick;

  // To determine if it is the first time entry for every dragging of the

form
  private bool isFirst = true;

  // Acts like a gate to do allow or deny
  private bool toBlock = true;

  public Form1()
  {
   //
   // Required for Windows Form Designer support
   //
   InitializeComponent();

   // Make our bitmap region for the form
   BitmapRegion.CreateControlRegion(this, bmpFrmBack);

   // Make our bitmap regions for the buttons
   BitmapRegion.CreateControlRegion(button1, bmpBob);
   BitmapRegion.CreateControlRegion(button2, bmpSmiles);
   BitmapRegion.CreateControlRegion(button3, bmpGreenBtnUp);
   BitmapRegion.CreateControlRegion(button4, bmpX);
  }

  /// <summary>
  /// Clean up any resources being used.
  /// </summary>
  protected override void Dispose( bool disposing )
  {
   if( disposing )
   {
    if (components != null)
    {
     components.Dispose();
    }
   }
   base.Dispose( disposing );
  }

  #region Windows Form Designer generated code
  /// <summary>
  /// Required method for Designer support - do not modify
  /// the contents of this method with the code editor.
  /// </summary>
  private void InitializeComponent()
  {
   this.button1 = new System.Windows.Forms.Button();
   this.button2 = new System.Windows.Forms.Button();
   this.button3 = new System.Windows.Forms.Button();
   this.button4 = new System.Windows.Forms.Button();
   this.SuspendLayout();
   //
   // button1
   //
   this.button1.Location = new System.Drawing.Point(104, 88);
   this.button1.Name = "button1";
   this.button1.TabIndex = 0;
   this.button1.Text = "button1";
   this.button1.Click += new System.EventHandler(this.button1_Click);
   this.button1.MouseEnter += new

System.EventHandler(this.button1_MouseEnter);
   this.button1.MouseLeave += new

System.EventHandler(this.button1_MouseLeave);
   //
   // button2
   //
   this.button2.Location = new System.Drawing.Point(328, 80);
   this.button2.Name = "button2";
   this.button2.TabIndex = 1;
   this.button2.Text = "button2";
   this.button2.Click += new System.EventHandler(this.button2_Click);
   this.button2.MouseEnter += new

System.EventHandler(this.button2_MouseEnter);
   this.button2.MouseLeave += new

System.EventHandler(this.button2_MouseLeave);
   //
   // button3
   //
   this.button3.Location = new System.Drawing.Point(184, 200);
   this.button3.Name = "button3";
   this.button3.TabIndex = 2;
   this.button3.Text = "button3";
   this.button3.Click += new System.EventHandler(this.button3_Click);
   this.button3.MouseEnter += new

System.EventHandler(this.button3_MouseEnter);
   this.button3.MouseLeave += new

System.EventHandler(this.button3_MouseLeave);
   //
   // button4
   //
   this.button4.Location = new System.Drawing.Point(344, 232);
   this.button4.Name = "button4";
   this.button4.TabIndex = 3;
   this.button4.Text = "button4";
   this.button4.Click += new System.EventHandler(this.button4_Click);
   this.button4.MouseEnter += new

System.EventHandler(this.button4_MouseEnter);
   this.button4.MouseLeave += new

System.EventHandler(this.button4_MouseLeave);
   //
   // Form1
   //
   this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
   this.ClientSize = new System.Drawing.Size(432, 270);
   this.Controls.AddRange(new System.Windows.Forms.Control[] {
            

        this.button4,
            

        this.button3,
            

        this.button2,
            

        this.button1});
   this.Name = "Form1";
   this.Text = "Form1";
   this.MouseMove += new

System.Windows.Forms.MouseEventHandler(this.Form1_MouseMove);
   this.ResumeLayout(false);

  }
  #endregion

  /// <summary>
  /// The main entry point for the application.
  /// </summary>
  [STAThread]
  static void Main()
  {
   Application.Run(new Form1());
  }

  private void button1_MouseEnter(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button1, bmpBobSay);
  }

  private void button1_MouseLeave(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button1, bmpBob);
  }

  private void button2_MouseEnter(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button2, bmpSmilesAngry);
  }

  private void button2_MouseLeave(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button2, bmpSmiles);
  }

  private void button3_MouseEnter(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button3, bmpGreenBtnDown);
  }

  private void button3_MouseLeave(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button3, bmpGreenBtnUp);
  }

  private void button4_MouseEnter(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button4, bmpXSmile);
  }

  private void button4_MouseLeave(object sender, System.EventArgs e)
  {
   // Make bitmap region for button
   BitmapRegion.CreateControlRegion(button4, bmpX);
  }

  private void button1_Click(object sender, System.EventArgs e)
  {
   MessageBox.Show("bob");
  }

  private void button2_Click(object sender, System.EventArgs e)
  {
   MessageBox.Show("smiles");
  }

  private void button3_Click(object sender, System.EventArgs e)
  {
   MessageBox.Show("green button");
  }

  private void button4_Click(object sender, System.EventArgs e)
  {
   MessageBox.Show("Exiting now...");
   Close();
  }
/*
  protected override void OnMouseDown(MouseEventArgs e)
  {
   if(e.Button == MouseButtons.Left)
   {
    const int HTCAPTION = 2;
    const int WM_NCLBUTTONDOWN = 161;
    
    int ix = e.X & 0xffff;
    int iy = e.Y & 0xffff;
    long ll = ix | iy << 16;

    PostMessage(this.Handle, WM_NCLBUTTONDOWN, HTCAPTION, ll);
   }
  }
*/
  private void Form1_MouseMove(object sender,

System.Windows.Forms.MouseEventArgs e)
  {
   // Check if dragging of the form has occurred
   if(e.Button == MouseButtons.Left)
   {
    // If this is the first mouse move event for left click

dragging of the form,
    // store the current point clicked so that we can use it to

calculate the form's
    // new location in subsequent mouse move events due to left

click dragging of the form
    if(isFirst == true)
    {
     // Store previous left click position
     prevLeftClick = new Point(e.X, e.Y);

     // Subsequent mouse move events will not be treated

as first time, until the
     // left mouse click is released or other mouse

click occur
     isFirst = false;
    }

    // On subsequent mouse move events with left mouse click

down. (During dragging of form)
    else
    {
     // This flag here is to allow alternate processing

for dragging the form because it
     // causes serious flicking when u allow every such

events to change the form's location.
     // You can try commenting this out to see what i

mean
     if(toBlock == false)
      this.Location = new Point(this.Location.X +

e.X - prevLeftClick.X, this.Location.Y + e.Y - prevLeftClick.Y);

     // Store new previous left click position
     prevLeftClick = new Point(e.X, e.Y);

     // Allow or deny next mouse move dragging event
     toBlock = !toBlock;
    }
   }

   // This is a new mouse move event so reset flag
   else
    isFirst = true;
  }
 }
}

本文地址:http://com.8s8s.com/it/it45019.htm