【技术备档】在WinCE5.0下实现透明背景按钮(.net C#)
问题:
需要在wince5.0下实现图形化界面,用于功能导航,用过GPS导航就知道了,类似的界面。众所周知gif,PNG等图片,都是可以实现透明背景的,在win下这应该不是个问题。但在ce5.0下,无论是透明背景的ICON、PNG、GIF都无法简单实现透明背景,alpha通道会丢失。网上搜索了些资料,当然也有办法解决,大家可以查一下,但性能较低。最终按微软SDK自带的一个计算器的源码思路解决了透明背景按钮问题。
要点:
- 如何画透明背景的BMP
- 如何画按钮并实现事件
思路及解决:
- 画按钮的思路:
ImageAttributes imageAttr=new ImageAttributes();
imageAttr.SetColorKey(Color.FromArgb(255, 0, 255),Color.FromArgb(255, 0, 255));
然后使用Graphics.DrawImage(,,,,,imageAttr)函数在指定的位置上画出透明的图片。
2. 事件驱动的思路:
事先定义好各按钮的指令
public enum Command {
cmd1 = 0,//无操作
cmd2,//第一项操作
cmd3,//第二项操作
cmd4,//可自己扩展
max
}
在创建按钮的同时明确以下几个参数 容器控件、资源存放的目录、X坐标、Y坐标、背景图片、按钮的标题、非激活时的文字颜色、激活时的文字颜色、触发的指令。创建窗口,针对窗体事件做如下定义
- 在Form_Load时生成按钮,
- 在Form_OnPaint时使用按钮自身的Render函数根据自己状态(有没有被点中)重画,
- 在MouseDown时判断点击位置是否在某个按钮的内部,如果是在它内部就改变它的状态,设置状态的同时调用窗口控件的Graphics局部重画这个按钮,
- 在Form_MouseUp时判断现在的位置是不是在按钮内部,如果按下了,抬起时又移出了范围则不处理。如果按下与抬起都是在同一个按钮的边界内部则执行这个按钮所设置的指令。
以下是我使用的资源,将作为按钮的图片需要透明的部分设置成RGB(255,0,255),那种非常刺眼的颜色。以下图片可以另存为BMP使用,设置的分辨是800*600的CE设备。
按钮未点击时背景:
按钮点中时背景:
窗体抬头的背景:
放置按钮的大背景:
第三步:代码实现
创建窗体名称ImageButton,设置窗体的Menu为空TopMost=true,Size=800,600,ControlBox=false,FormBorderStyle=None
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO; using System.Reflection; namespace DZB { public partial class ImageButton : Form { private IList<IButton> btnlist; private IButton capturedButton; private Font windowFont = new Font(FontFamily.GenericSansSerif, 12, FontStyle.Regular); private string CurrentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase); private Bitmap bg, title; public ImageButton() { InitializeComponent(); } private void ImageButton_Load(object sender, EventArgs e) { title = new Bitmap(CurrentPath + @"\Resources\title.bmp"); bg = new Bitmap(CurrentPath + @"\Resources\mainbg.bmp"); btnlist = new List<IButton>(); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 100, 100, "button.bmp", "按钮1", Color.White, Color.Blue, Command.cmd1)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 100, 200, "button.bmp", "按钮2", Color.White, Color.Blue, Command.cmd1)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 100, 300, "button.bmp", "按钮3", Color.White, Color.Blue, Command.cmd2)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 100, 400, "button.bmp", "按钮4", Color.White, Color.Blue, Command.cmd2)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 400, 100, "button.bmp", "按钮5", Color.White, Color.Blue, Command.cmd2)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 400, 200, "button.bmp", "按钮6", Color.White, Color.Blue, Command.cmd2)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 400, 300, "button.bmp", "按钮7", Color.White, Color.Blue, Command.cmd2)); btnlist.Add(new IButton(this, CurrentPath + @"\Resources\", 400, 400, "button.bmp", "按钮8", Color.White, Color.Blue, Command.cmd3)); } private void ImageButton_Paint(object sender, PaintEventArgs e) { // Buttons Graphics graphics; graphics = e.Graphics; graphics.DrawImage(title, 0, 0); graphics.DrawImage(bg, 0, 63); // Edit line foreach (IButton btn in btnlist) { btn.Render(graphics); } } protected override void OnPaintBackground(PaintEventArgs paintArgs) { //gr.DrawImage(img, 0, 0); base.OnPaintBackground(paintArgs); } ~ImageButton() { windowFont.Dispose(); } private void ImageButton_MouseDown(object sender, MouseEventArgs e) { foreach (IButton btn in btnlist) { if (btn.IsHit(e.X, e.Y)) { btn.IsSelected = true; capturedButton = btn; break; } } } private void ImageButton_MouseMove(object sender, MouseEventArgs e) { if (capturedButton != null) { capturedButton.IsSelected = capturedButton.IsHit(e.X, e.Y); } } private void ImageButton_MouseUp(object sender, MouseEventArgs e) { if (capturedButton != null) { if (capturedButton.IsHit(e.X, e.Y)) DoCommand(capturedButton.Cmd); try { capturedButton.IsSelected = false; capturedButton = null; } catch { } } } /// <summary> /// 执行指令 /// </summary> /// <param name="command"></param> private void DoCommand(Command command) { switch (command) { case Command.cmd1://0 // this.Close(); break; case Command.cmd2://1 MessageBox.Show("cmd2"); break; case Command.cmd3://2 this.Close(); break; case Command.cmd4://3 { Line nl = new Line(); nl.Show(); } break; default: break; } } } }
IButton.cs 类
//====================================================================== // // Copyright (C) 2008-2009 PCODE TEAM. All rights reserved. // // CLR Version: 2.0.50727.1433 // NameSpace: DZB FileName: IButton.Cs // // Created by Jy at 2009/9/10 22:07:34 // Email:jy@cjlu.edu.cn // //====================================================================== using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing; using System.Drawing.Imaging; namespace DZB { public class IButton { private Control MainForm; private Font sFont = new Font(FontFamily.GenericSansSerif,16, FontStyle.Bold); private Font sFont_ = new Font(FontFamily.GenericSansSerif, 16, FontStyle.Bold); private bool IsSelectedValue; private Command ButtonCommand; private Rectangle selfRec; private string _caption; private float _cx, _cy;//画标题的位置 private Bitmap btnbg, btnbg_; private string _CurrentPath; Color transpColor = Color.FromArgb(255, 0, 255);//资源文件的透明色 ImageAttributes imageAttr; Color _ncolor, _fcolor; Graphics g, g_; /// <summary> /// 初始化 /// </summary> /// <param name="form">容器名称</param> /// <param name="CurrentPath">当前程序路径</param> /// <param name="x">按钮位置X</param> /// <param name="y">按钮位置Y</param> /// <param name="bgfilename">按钮图片名称</param> /// <param name="caption">标题</param> /// <param name="nColor">正常颜色</param> /// <param name="fColor">激活颜色</param> /// <param name="cmd">指令</param> public IButton(Control form,string CurrentPath, int x, int y, string bgfilename,string caption,Color nColor,Color fColor, Command cmd) { MainForm = form; _ncolor = nColor; _fcolor = fColor; ButtonCommand = cmd; _caption = caption; _CurrentPath = CurrentPath; string bg = CurrentPath + bgfilename; string bg_ = CurrentPath +System.IO.Path.GetFileNameWithoutExtension(bg) + "_.bmp"; btnbg = new Bitmap(bg); selfRec = new Rectangle(x, y, btnbg.Width,btnbg.Height); g = Graphics.FromImage(btnbg); _cx = (219 - g.MeasureString(_caption, sFont).Width) / 2; _cy = (48 - g.MeasureString(_caption, sFont).Height) / 2; btnbg_= new Bitmap(bg_); g_ = Graphics.FromImage(btnbg_); imageAttr = new ImageAttributes(); imageAttr.SetColorKey(transpColor, transpColor); } public void Render(Graphics graphics) { if (IsSelectedValue) {//点下的状态 g_.DrawString(_caption, sFont_, new SolidBrush(_fcolor), _cx,_cy); graphics.DrawImage(btnbg_, selfRec, 0, 0, selfRec.Width, selfRec.Height, GraphicsUnit.Pixel, imageAttr); } else { g.DrawString(_caption, sFont, new SolidBrush(_ncolor),_cx, _cy); graphics.DrawImage(btnbg, selfRec, 0, 0, selfRec.Width, selfRec.Height, GraphicsUnit.Pixel, imageAttr); } } private static Color GetTransparentColor(Image image) { return ((Bitmap)image).GetPixel(image.Width - 1, image.Height - 1); } public bool IsHit(int x, int y) { return (x >= selfRec.X && x < selfRec.X +selfRec.Width && y >= selfRec.Y && y <selfRec.Y+selfRec.Height); } public bool IsSelected { get { return IsSelectedValue; } set { Graphics graphics; if (value != IsSelectedValue) { IsSelectedValue = value; // Redraw right away graphics = MainForm.CreateGraphics(); this.Render(graphics); graphics.Dispose(); } } } public Command Cmd { get { return (ButtonCommand); } } } }
最终效果:
透明背景的按钮实现成功
总结:
此方案的优点:
- 思路简单,实现过程没有特别复杂的技术环节
- 因是局部重画,即使在800*600这样的分辨率下也能达到不闪烁的效果
- 按钮可配置性高,更换资源文件即可实现对按钮及整体风格的改变
此方案的缺点:
- 按钮图片与背景间不能实现ALPHA的渐透明
- 按钮的驱动虽然实现,但没有很OO。(微软也是这么写代码的,所以也不算大问题)
- 资源图片要按像素级处理透明色,有些麻烦。(项目组有美工的话还好做些)
以下再列几个我自己做的风格给大家参考
山水皮肤
冬奥皮肤
希望我的综合对大家有帮助。