C#制作不规则窗口 ( 24bit Color 以上适用 )
時間: 2004/3/17
作者: Robert
參考: http://www.codeproject.com/csharp/bmprgnform.asp?target=region
關鍵字: 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;
}
}
}