c#制作不规则窗口 ( 24bit color 以上适用 )
時間: 2004/3/17
作者: robert
參考: http://www.codeproject.com/csharp/bmprgnform.asp?target=region
電郵: zsc771120@yahoo.com.cn
關鍵字: 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 forms 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 forms 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 controls 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 forms size to be a little larger that the
bitmap just
// in case the forms 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 forms
// 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 forms 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;
}
}
}