Visual C# 2005 - 如何利用程序代码产生多层次绘图效果
看完前一篇「如何利用程序代码制作简单动画效果」文章之后,可以制作简单动画效果,接下来,要更进一步运用 .Net Framework 的 System.Drawing 与 System.Drawing.Drawing2D 命名空间中的 Graphics、SolidBrush、HatchBrush、TextureBrush、LinearGradientBrush、Point、PathGradientBrush 以及 Pen 类别,制作媲美专业绘图软件的图像、实线笔刷、缝影线笔刷、纹理、线性渐层、与路径渐层。
程序范例
图表1
图表 1 是我们所撰写之程序的执行画面,它示范如何提供笔刷类型、绘图样式、前景与背景颜色、笔刷尺寸、拼接、花纹以及翻转、渐层等…各种选项,用户设定完毕之后,程序会自动根据不同的选项将图像绘制于右方的 PictureBox 控件中,程序设计重点说明如下。
在窗体的 Load 事件处理例程中,除了将组件的 AsmFQName 属性值指派给窗体的 Text 属性之外,特别要说明的是,如果您希望在程序执行阶段将子项目加入 ComboBox 控件,请采用 comboBox.Items.Add(Item) 方法,完整的程序代码如下所示:
private void Blog_DemoForm005_Load(object sender, EventArgs e)
{
AssemblyInfoClass myAssembly = new AssemblyInfoClass();
this.Text = myAssembly.AsmFQName;
m_BrushSize = new Rectangle(0, 0, picDemoArea.Width,
picDemoArea.Height);
// 将弯曲变换模式加入ComboBox 当作子项目。
cboWrapMode.Items.Add(WrapMode.Clamp);
cboWrapMode.Items.Add(WrapMode.Tile);
cboWrapMode.Items.Add(WrapMode.TileFlipX);
cboWrapMode.Items.Add(WrapMode.TileFlipY);
cboWrapMode.Items.Add(WrapMode.TileFlipXY);
const int maxHatchStyle = 52;
for(int i = (int)HatchStyle.Min;i <= maxHatchStyle;i++)
{
cboHatchStyle.Items.Add((HatchStyle)(i));
}
// 将线形渐层的方向加入ComboBox 当作子项目。
cboGradientMode.Items.Add(
LinearGradientMode.BackwardDiagonal);
cboGradientMode.Items.Add(
LinearGradientMode.ForwardDiagonal);
cboGradientMode.Items.Add(LinearGradientMode.Horizontal);
cboGradientMode.Items.Add(LinearGradientMode.Vertical);
// 设定窗体ComboBox 控件默认值。
cboBrushSize.SelectedIndex = 0;
cboGradientMode.SelectedIndex = 0;
cboHatchStyle.SelectedIndex = 0;
cboWrapMode.SelectedIndex = 0;
}
要让用户选择前景与背景颜色,利用 ColorDialog 类别来显示「色彩」对话框最为简便,相关程序代码撰写于 btnSetColor1 与 btnSetColor2 按钮的 Click 事件处理例程,列示如下:
private void btnSetColor1_Click(object sender, EventArgs e)
{
ColorDialog cdlg = new ColorDialog();
// 开启色彩对话框。
if (cdlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
m_Color1 = cdlg.Color;
txtColor1.Text = cdlg.Color.ToString();
txtColor1.BackColor = cdlg.Color;
}
}
private void btnSetColor2_Click(object sender, EventArgs e)
{
ColorDialog cdlg = new ColorDialog();
// 开启色彩对话框。
if (cdlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
m_Color2 = cdlg.Color;
txtColor2.Text = cdlg.Color.ToString();
txtColor2.BackColor = cdlg.Color;
}
}
当用户选择不同的笔刷尺寸之后,会产生以原点(也就是X轴坐标为零且Y轴坐标为零)为基准,不同大小的矩型参数,并重新绘制图像(程序代码撰写于 cboBrushSize 控件的 SelectedIndexChanged 事件处理例程):
private void cboBrushSize_SelectedIndexChanged(
object sender, EventArgs e)
{
// 判断笔刷尺寸。
switch(cboBrushSize.Text)
{
case "大" :
m_BrushSize =
new Rectangle(
0, 0, picDemoArea.Width, picDemoArea.Height);
break;
case "中" :
m_BrushSize =
new Rectangle(
0, 0, picDemoArea.Width / 2, picDemoArea.Height / 2);
break;
case "小" :
m_BrushSize =
new Rectangle(
0, 0, picDemoArea.Width / 4, picDemoArea.Height / 4);
break;
}
// 重新绘制图片。
RedrawPicture(cboBrushSize, new EventArgs());
}
cboBrushSize 控件的 SelectedIndexChanged 事件处理例程会叫用自订函式 RedrawPicture 来重置 PictureBox 及状态列信息,同时函式会根据用户设定的笔刷类型与绘图样式参数重绘图像,兹将程序代码列示如下:
private void RedrawPicture(
System.Object sender, System.EventArgs e)
{
// 重置PictureBox。
picDemoArea.CreateGraphics().Clear(Color.White);
picDemoArea.Refresh();
// 重置状态列。
this.toolStripStatusLabel1.Text = "";
// 判断笔刷类型。
switch(cboBrushType.Text)
{
case "实线" :
…
SolidBrush mySolidBrush = new SolidBrush(m_Color1);
m_Brush = mySolidBrush;
break;
case "缝影线" :
…
HatchBrush myHatchBrush =
new HatchBrush(
(HatchStyle)(cboHatchStyle.SelectedItem),
m_Color1, m_Color2);
m_Brush = myHatchBrush;
break;
case "纹理" :
…
TextureBrush myTextureBrush = new TextureBrush(
new Bitmap(Resources.WaterLilies), m_BrushSize);
myTextureBrush.WrapMode =
(WrapMode)(cboWrapMode.SelectedItem);
myTextureBrush.RotateTransform((float)nudRotation.Value);
m_Brush = myTextureBrush;
break;
case "线性渐层" :
…
LinearGradientBrush myLinearGradientBrush =
new LinearGradientBrush(
m_BrushSize, m_Color1, m_Color2,
(LinearGradientMode)(cboGradientMode.SelectedItem));
if((WrapMode)(cboWrapMode.SelectedItem) != WrapMode.Clamp)
{
myLinearGradientBrush.WrapMode =
(WrapMode)(cboWrapMode.SelectedItem);
}
else
{
this.toolStripStatusLabel1.Text +=
"线型渐层笔刷不能使用在Clamp 拼接模式。";
}
myLinearGradientBrush.RotateTransform(
(float)nudRotation.Value);
myLinearGradientBrush.SetBlendTriangularShape(
(float)nudGradientBlend.Value);
m_Brush = myLinearGradientBrush;
break;
case "路径渐层" :
…
Point[] pathPoint = new Point[]
{
new Point(0, m_BrushSize.Height),
new Point(m_BrushSize.Width, m_BrushSize.Height),
new Point(m_BrushSize.Width, 0)
};
PathGradientBrush myPathGradientBrush =
new PathGradientBrush(pathPoint);
myPathGradientBrush.CenterColor = m_Color1;
myPathGradientBrush.SurroundColors =
new Color[] {m_Color2};
myPathGradientBrush.WrapMode =
(WrapMode)(cboWrapMode.SelectedItem);
myPathGradientBrush.RotateTransform(
(float)nudRotation.Value);
myPathGradientBrush.SetBlendTriangularShape(
(float)nudGradientBlend.Value);
m_Brush = myPathGradientBrush;
break;
}
myGraphics = picDemoArea.CreateGraphics();
// 判断绘图样式。
switch(cboDrawing.Text)
{
case "填满" :
myGraphics.FillRectangle(m_Brush, 0, 0,
picDemoArea.Width, picDemoArea.Height);
break;
case "椭圆" :
myGraphics.FillEllipse(m_Brush, picDemoArea.Width / 10,
picDemoArea.Height / 10, picDemoArea.Width / 2,
picDemoArea.Height / 2);
myGraphics.FillEllipse(m_Brush, picDemoArea.Width / 3,
picDemoArea.Height / 3, picDemoArea.Width / 2,
picDemoArea.Height / 2);
break;
case "线形" :
Pen myPen = new Pen(m_Brush, 40);
myGraphics.DrawLine(
myPen, 0, 0, picDemoArea.Width, picDemoArea.Height);
myGraphics.DrawLine(myPen, 0, 0, 0, picDemoArea.Height);
myGraphics.DrawLine(myPen, 0, 0, picDemoArea.Width, 0);
myGraphics.DrawLine(myPen, picDemoArea.Width, 0,
picDemoArea.Width, picDemoArea.Height);
myGraphics.DrawLine(myPen, 0, picDemoArea.Height,
picDemoArea.Width, picDemoArea.Height);
myGraphics.DrawLine(
myPen, picDemoArea.Width, 0, 0, picDemoArea.Height);
break;
}
// 显示状态列讯息。
if (this.toolStripStatusLabel1.Text == "")
{
this.toolStripStatusLabel1.Text = "成功!";
}
}
最后,本程序范例的执行结果如图表 2 到 5 所示。
图表2
图表3
图表4
图表 5