2007-3-18 Wince5.0自定义ToolBar
做WinCE的开发时,碰到一很头疼的事(Coolpad机器)。它的菜单很难看,字体很大,样式也太简单,就选用了 CF2.0中的ToolBar控件。用户使用后反应很大,普遍说是用不方便,因为Toolbar没有文本,只有图标。所以自定义一个Toolbar,这里不方便提供所有源码,只是讲述开发过程中碰到的几点问题(主要问题),相信对其他朋友有帮助。
自定工具条ToolBarEx,我是模仿vs2005的工具条做,增加了文本功能。
1. 高度25像素,图标16×16;
2. vs2005的工具条中,头部有4个点,我模仿做时,发现是8个方块(4*4像素),4个灰色方块,4个白色方块;白色方块向右下偏移1像素,这样画出来,就跟vs2005的工具条效果一致了;
3. 分隔线(Separator button)。v s2005的工具条,分隔线高度20像素,颜色我选用的是Gray;
4. 背景色选用渐变的颜色,CF2.0中没有提供渐变的GDI+方法,所以采取调用GDI的API函数实现,代码如下:
WinApi.DrawNiceRectangle(hdc, frame);
internal class WinApi
{
private const uint
GRADIENT_FILL_RECT_H = 0x00000000,
GRADIENT_FILL_RECT_V = 0x00000001,
GRADIENT_FILL_TRIANGLE = 0x00000002,
GRADIENT_FILL_OP_FLAG = 0x000000ff;
[DllImport("coredll")]
private static extern bool GradientFill(
IntPtr hdc, // handle to DC
TRIVERTEX[] pVertex, // array of vertices
uint dwNumVertex, // number of vertices
ref GRADIENT_RECT pMesh, // array of gradients
uint dwNumMesh, // size of gradient array
uint dwMode // gradient fill mode
);
internal static void DrawNiceRectangle(IntPtr graphPort, Rectangle Frame, Color a, Color b)
{
// Draw from whitish blue at the top, to a light blue at the bottom
//TRIVERTEX[] vert = new TRIVERTEX[]{
// new TRIVERTEX(Frame.Left,Frame.Top,0xff00,0xff00,0xffff,0xff00),
// new TRIVERTEX(Frame.Right,Frame.Bottom,0x0000,0x0000,0xff00,0xff00)};
TRIVERTEX[] vert = new TRIVERTEX[]{
new TRIVERTEX(Frame.Left,Frame.Top,ToColor16(a.R),ToColor16(a.G),ToColor16(a.B),(ushort)(0)),
new TRIVERTEX(Frame.Right,Frame.Bottom,ToColor16(b.R) ,ToColor16(b.G ),ToColor16(b.B) ,(ushort)(0))};
GRADIENT_RECT gRect =
new GRADIENT_RECT(0, 1);
WinApi.GradientFill(graphPort, vert, 2, ref gRect, 1, WinApi.GRADIENT_FILL_RECT_V);
}
private static ushort ToColor16(byte value)
{
return (ushort)((int)value << 8);
}
internal static void DrawNiceRectangle(IntPtr graphPort, Rectangle Frame)
{
Color a = Color.FromArgb(239, 239, 239);
Color b = Color.FromArgb(139, 139, 139);
DrawNiceRectangle(graphPort, Frame, a, b);
}
}
这里采取的是从上至下的渐变,因为渐变高度的问题,所以有些颜色可能看不到效果,测试时可以调整高度,会看到效果。
5. 点击ToolBarExButton时的效果,vs2005中的效果是深色的边框(border color)+比边框色浅一些的颜色,代码如下:
//我采取的border color
Color border = Color.FromArgb(0, 0, 128);
//计算填充色
Color fillColor = GetHighlightColor(border);
//原理就是将指定的Color淡化,请注意2个系数相加必须=1;用户可以自己调整系数,调节颜色的深度
private Color GetHighlightColor(Color cl)
{
int num1 = (int)(cl.R * 0.2);
int num4 = (int)(cl.G * 0.2);
int num7 = (int)(cl.B * 0.2);
int num2 = (int)(Color.White.R * 0.8);
int num5 = (int)(Color.White.G * 0.8);
int num8 = (int)(Color.White.B * 0.8);
return Color.FromArgb(num1 + num2, num4 + num5, num7 + num8);
}
6. 当Enabled=false时的效果,这个当初也是困扰我很久,如何灰显图标,因为我一直不愿意做个工具条,还用2套图标(正常和灰显);灰显图标的方法:
private static bool GrayImage(Bitmap b)
{
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - b.Width * 3;
byte red, green, blue;
for (int y = 0; y < b.Height; ++y)
{
for (int x = 0; x < b.Width; ++x)
{
blue = p[0];
green = p[1];
red = p[2];
p[0] = p[1] = p[2] = (byte)(.299 * red + .587 * green + .114 * blue);
p += 3;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return true; }
7. ToolBarExButtonClick事件,上面所做的都是绘制工具条,现在进入正题,如何触发按钮单击事件。我是计算鼠标按下时的位置,然后通过每个ToolBarExButton的Rect判断是否为某个button,是则抛出事件。
8. ToolBarEx代码层次,仅供参考。
ToolBarEx;
ToolBarExButton;
ToolBarExButtonClickEventArgs;
ToolBarExButtonCollection;
ToolBarExButtonStyle;
ToolBarExTextAlign;
ToolBarExDelegate;
9. 效果如下:(通过PDA抓得图,有点失真,不过大致效果还能看到)
(ToolBarEx效果) (CF2.0中 ToolBar效果)
题外话,大家可以看到上面有一pda地图的界面。近半年来一直在搞移动地图引擎的开发,希望和从事相关行业的朋友交流,特别是移动地图的效率问题,大地图文件时效率问题。