为MenuStrip增加一个渲染器
Office 2007 的菜单效果真的是绚丽,但在应该的专业领域的应用开发中大部分都不是很需要这效果,虽然很多的Ribbon能达到这效果,但同VS提供的可视化开发还是存在很大的差距,VS的可视化开发速度快,效率高,操作简单,容易上手。但有时为了更近人的界面,我们也可以给MenuStrip装饰一下。
MenuStrip是通过MenuStripRenderer来完成菜单的绘制效果的,Framework有三个渲染器,我们就继承其中一个,通过让重写其中的部分方法来达到不同的效果。
这里实现的功能有:为菜单或工具栏添加一个水印。菜单的图标或工具栏的图标做一个鼠标移进时加亮的效果(只需一张图片即可实现)。至于重给菜单或工具栏的底色,用户可以自己实现。
1.继承ToolStripProfessionalRenderer
ToolStripProfessionalRenderer就是从工具箱拖出ToolStrip的默认效果
属性:WatermarkImage 水印图片
属性:WatermarkTransparency 透明效果(0-255)
属性:WatermarkGrayEffect 是否使用灰度效果
属性:BrightValue 鼠标进入时图片增加亮度的效果
图片增亮和水印效果是数字图像处理技术,具体的算法,可以在网上查找,这里有个透明的效果是经过自己研究出来的。
重写OnRenderItemImage方法,判断菜单项的状态,把正常的图片或增亮的图片赋给Renderer。
重写OnRenderToolStripBackground方法,实现水印功能
代码片段:
/***************************************************************************************************************
* 文件名称:JWMenuStripRenderer.cs
*
* 功能描述:菜单 渲染器。更改鼠标进入时图片自动增亮的功能。
*
* 创建日期:2009-10-16
*
* 创 建 人:Lance Yang
*
* 修改:
* 2009-10-15 Lance Yang -修改内容。
*
* **************************************************************************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace LC.Client.Controls
{
/// <summary>
/// ToolStrip 渲染器。更改背景为过度显示和鼠标进入时图片自动增亮的功能。
/// </summary>
public class LCMenuStripRenderer : ToolStripProfessionalRenderer
{
List<EtyImageState> m_ImageList = new List<EtyImageState>();
public LCMenuStripRenderer()
{
this.RoundedEdges = false;
}
private int m_WatermarkTransparency = 255;
/// <summary>
/// 水印显示的透明度。
/// </summary>
///
public int WatermarkTransparency
{
get { return m_WatermarkTransparency; }
set
{
if (value > 255 || value < 0)
throw new Exception("请输入 0 - 255 之间的一个数值。");
m_WatermarkTransparency = value;
WatermarkImage = m_WatermarkImage;
}
}
private bool m_watermarkGrayEffect = false;
/// <summary>
/// 水印的灰度效果,默认为 false;
/// </summary>
///
public bool WatermarkGrayEffect
{
get { return m_watermarkGrayEffect; }
set
{
m_watermarkGrayEffect = value;
WatermarkImage = m_WatermarkImage;
}
}
private Bitmap m_WatermarkImage;
/// <summary>
/// 水印的图片。
/// </summary>
///
public Bitmap WatermarkImage
{
get { return m_WatermarkImage; }
set
{
m_WatermarkImage = value;
//制作水印
if (value != null)
{
Bitmap img = new Bitmap(value);
if (m_watermarkGrayEffect)
ImageTool.GrayByPixels(img);
if (m_WatermarkTransparency != 255)
ImageTool.WatermarkImage(img, m_WatermarkTransparency);
m_WatermarkImage = img;
}
else
m_WatermarkImage = null;
}
}
private int m_brightValue = 26;
/// <summary>
/// 鼠标进入时的图片增亮值。默认为 26
/// </summary>
public int BrightValue
{
get { return m_brightValue; }
set { m_brightValue = value; }
}
protected override void OnRenderItemImage(ToolStripItemImageRenderEventArgs e)
{
Bitmap img = e.Image as Bitmap;
if (img != null)
{
bool isEqualsInitImage = false;
EtyImageState ety = EtyImageState.GetEtyImageState(m_ImageList, img.GetHashCode(), out isEqualsInitImage);
if (ety == null)
{
ety = new EtyImageState();
ety.InitImage = img;
ety.LightImage = ImageTool.Brightness(img, m_brightValue);
m_ImageList.Add(ety);
}
if (e.Item.Selected)
e.Item.Image = ety.LightImage;
else
e.Item.Image = ety.InitImage;
}
base.OnRenderItemImage(e);
}
int borderPadding = 2;
/// <summary>
/// 水印的边距,默认为2
/// </summary>
public int WatermarkPadding
{
get { return borderPadding; }
set { borderPadding = value; }
}
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
{
base.OnRenderToolStripBackground(e);
if (e.ToolStrip is ToolStripDropDown) //过滤,根据需要可能还有更多的过滤
return;
////System.Diagnostics.Debug.WriteLine("显示水印");
//显示水印。
if (m_WatermarkImage != null)
{
Point position = Point.Empty;
int top = borderPadding;
int left = 0;
int width = 0;
int height = 0;
if (m_WatermarkImage.Height > e.ToolStrip.Height - borderPadding * 2)
{
//重新定义图片的显示宽高
double rate = (double)m_WatermarkImage.Width / (double)m_WatermarkImage.Height;
height = e.ToolStrip.Height - borderPadding * 2;
width = Convert.ToInt32(rate * height);
}
else
{
width = m_WatermarkImage.Width;
height = m_WatermarkImage.Height;
top = (e.ToolStrip.Height - height) / 2;
}
left = e.ToolStrip.Width - width - borderPadding * 2;
position = new Point(left, top);
Rectangle rect = new Rectangle(left, top, width, height);
e.Graphics.DrawImage(m_WatermarkImage, rect, new Rectangle(0, 0, m_WatermarkImage.Width, m_WatermarkImage.Height), GraphicsUnit.Pixel);
}
}
}
}
/// <summary>
/// 为保存图片的状态而设
/// </summary>
internal class EtyImageState
{
public int InitImageKey
{
get
{
if (m_InitImage == null)
return -1;
else
return m_InitImage.GetHashCode();
}
}
private Image m_InitImage;
public Image InitImage
{
get { return m_InitImage; }
set { m_InitImage = value; }
}
public int LightImageKey
{
get
{
if (m_LightImage == null)
return -1;
else
return m_LightImage.GetHashCode();
}
}
private Image m_LightImage;
public Image LightImage
{
get { return m_LightImage; }
set { m_LightImage = value; }
}
/// <summary>
/// 从集合
/// </summary>
/// <param name="list"></param>
/// <param name="key"></param>
/// <returns></returns>
public static EtyImageState GetEtyImageState(List<EtyImageState> list, int key, out bool isEqualsInitImage)
{
isEqualsInitImage = false;
EtyImageState retEty = null;
foreach (EtyImageState ety in list)
{
if (ety.InitImageKey == key)
{
isEqualsInitImage = true;
retEty = ety;
break;
}
else if (ety.LightImageKey == key)
{
retEty = ety;
break;
}
}
return retEty;
}
}
数字处理算法类:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
namespace LC.Client.Controls
{
public static class ImageTool
{
/// <summary>
/// 根据字符串生成图片。
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static Bitmap DeserializeFromBase64(string data)
{
// Decode the string and create a memory stream
// on the decoded string data.
MemoryStream stream =
new MemoryStream(Convert.FromBase64String(data));
// Create a new bitmap from the stream.
Bitmap b = new Bitmap(stream);
return b;
}
//图片 转为 base64编码的文本
public static string ImgToBase64String(Image bmp)
{
MemoryStream ms = new MemoryStream();
bmp.Save(ms, bmp.RawFormat);
byte[] arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(arr, 0, (int)ms.Length);
ms.Close();
String strbase64 = Convert.ToBase64String(arr);
return strbase64;
}
/// <summary>
/// 图片增亮。
/// </summary>
/// <param name="img"></param>
/// <returns></returns>
public static Image Brightness(Image img, int brightValue)
{
int percent = brightValue;
Single v = 0.006F * percent;
Single[][] matrix = {
new Single[] { 1, 0, 0, 0, 0 },
new Single[] { 0, 1, 0, 0, 0 },
new Single[] { 0, 0, 1, 0, 0 },
new Single[] { 0, 0, 0, 1, 0 },
new Single[] { v, v, v, 0, 1 }
};
System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix);
System.Drawing.Imaging.ImageAttributes attr = new System.Drawing.Imaging.ImageAttributes();
attr.SetColorMatrix(cm);
//Image tmp
//Image tmp = (Image)img.Clone();
Bitmap tmp = new Bitmap(img);
Graphics g = Graphics.FromImage(tmp);
try
{
Rectangle destRect = new Rectangle(0, 0, img.Width, img.Height);
g.DrawImage(tmp, destRect, 0, 0, tmp.Width, tmp.Height, GraphicsUnit.Pixel, attr);
}
finally
{
g.Dispose();
}
return tmp;
}
//处理不了透明的背景
/// <summary>
/// 制作水印图片
/// </summary>
/// <param name="iTheImage">要制作水印的图片</param>
/// <param name="width">制作水印的宽</param>
/// <param name="height">制作水印的高</param>
/// <returns></returns>
public static Bitmap WatermarkImage(Bitmap iTheImage, int width, int height)
{
//Bitmap watermark = new Bitmap(width, height,
// PixelFormat.Format24bppRgb);
Bitmap watermark = new Bitmap(iTheImage);
Graphics g = Graphics.FromImage(watermark);
g.Clear(Color.White);
//g.Clear(iTheImage.GetPixel(0,0));
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.High;
ImageAttributes imageAttributes = new ImageAttributes();
ColorMap colorMap = new ColorMap();
colorMap.OldColor = Color.FromArgb(255, 0, 255, 0);
colorMap.NewColor = Color.FromArgb(0, 0, 0, 0);
ColorMap[] remapTable = { colorMap };
imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
float[][] colorMatrixElements = {
new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, 0.3f, 0.0f},
new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
};
ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);
imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
#region 保留学习
////int WatermarkWidth = 0;
////int WatermarkHeight = 0;
////double bl = 1d;
//////计算水印图片的比率
//////取背景的1/4宽度来比较
////if ((width > watermark.Width * 4) && (height > watermark.Height * 4))
////{
//// bl = 1;
////}
////else if ((width > watermark.Width * 4) && (height < watermark.Height * 4))
////{
//// bl = Convert.ToDouble(height / 4) / Convert.ToDouble(watermark.Height);
////}
////else if ((width < watermark.Width * 4) && (height > watermark.Height * 4))
////{
//// bl = Convert.ToDouble(width / 4) / Convert.ToDouble(watermark.Width);
////}
////else
////{
//// if ((width * watermark.Height) > (height * watermark.Width))
//// {
//// bl = Convert.ToDouble(height / 4) / Convert.ToDouble(watermark.Height);
//// }
//// else
//// {
//// bl = Convert.ToDouble(width / 4) / Convert.ToDouble(watermark.Width);
//// }
////}
////WatermarkWidth = Convert.ToInt32(watermark.Width * bl);
////WatermarkHeight = Convert.ToInt32(watermark.Height * bl);
////switch (_watermarkPosition)
////{
//// case "WM_TOP_LEFT":
//// xpos = 10;
//// ypos = 10;
//// break;
//// case "WM_TOP_RIGHT":
//// xpos = _width - WatermarkWidth - 10;
//// ypos = 10;
//// break;
//// case "WM_BOTTOM_RIGHT":
//// xpos = _width - WatermarkWidth - 10;
//// ypos = _height - WatermarkHeight - 10;
//// break;
//// case "WM_BOTTOM_LEFT":
//// xpos = 10;
//// ypos = _height - WatermarkHeight - 10;
//// break;
////}
#endregion
try
{
Rectangle destRect = new Rectangle(0, 0, watermark.Width, watermark.Height);
g.DrawImage(iTheImage, destRect, 0, 0, watermark.Width, watermark.Height,
GraphicsUnit.Pixel,
imageAttributes);
}
finally
{
imageAttributes.Dispose();
g.Dispose();
}
return watermark;
}
/// <summary>
/// 制作透明的图片。对透明背景保留原来的样子。
/// </summary>
/// <param name="bmpobj"></param>
/// <param name="transValue">透明度 (0 - 255)</param>
public static void WatermarkImage(Bitmap bmpobj, int transValue)
{
for (int i = 0; i < bmpobj.Height; i++)
{
for (int j = 0; j < bmpobj.Width; j++)
{
Color dot = bmpobj.GetPixel(j, i);
if (dot.A > 0)
{
bmpobj.SetPixel(j, i, Color.White);
bmpobj.SetPixel(j,i,Color.FromArgb(transValue,dot.R,dot.G,dot.B));
}
}
}
}
/// <summary>
/// 灰度转换,逐点方式
/// </summary>
public static void GrayByPixels(Bitmap bmpobj)
{
for (int i = 0; i < bmpobj.Height; i++)
{
for (int j = 0; j < bmpobj.Width; j++)
{
Color dot = bmpobj.GetPixel(j, i);
if (dot.A > 0)
{
int tmpValue = GetGrayNumColor(dot);
bmpobj.SetPixel(j, i, Color.FromArgb(tmpValue, tmpValue, tmpValue));
}
}
}
}
/// <summary>
/// 根据RGB,计算灰度值
/// </summary>
/// <param name="posClr">Color值</param>
/// <returns>灰度值,整型</returns>
private static int GetGrayNumColor(System.Drawing.Color posClr)
{
return (posClr.R * 19595 + posClr.G * 38469 + posClr.B * 7472) >> 16;
}
////public static bool Invert(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;
//// int nWidth = b.Width * 3;
//// for (int y = 0; y < b.Height; ++y)
//// {
//// for (int x = 0; x < nWidth; ++x)
//// {
//// p[0] = (byte)(255 - p[0]);
//// ++p;
//// }
//// p += nOffset;
//// }
//// }
//// b.UnlockBits(bmData);
//// return true;
////}
////public static bool Gray(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;
////}
////public static bool Brightness(Bitmap b, int nBrightness)
////{
//// if (nBrightness < -255 || nBrightness > 255)
//// return false;
//// 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;
//// int nVal = 0;
//// unsafe
//// {
//// byte* p = (byte*)(void*)Scan0;
//// int nOffset = stride - b.Width * 3;
//// int nWidth = b.Width * 3;
//// for (int y = 0; y < b.Height; ++y)
//// {
//// for (int x = 0; x < nWidth; ++x)
//// {
//// nVal = (int)(p[0] + nBrightness);
//// if (nVal < 0) nVal = 0;
//// if (nVal > 255) nVal = 255;
//// p[0] = (byte)nVal;
//// ++p;
//// }
//// p += nOffset;
//// }
//// }
//// b.UnlockBits(bmData);
//// return true;
////}
}
}