打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
C#在Winform中使用GDI绘制电路板元件模拟图

一块电路板上经常会出现各种电阻、二极管、跳线之类的元器件,许多生产加工电路板的自动化设备都会根据电路板上的元器件生成一个模拟图。我今天就试着做一个简单的,当然实际开发中远远不止文中提到的这些,还需要不断的完善和改进,这个例子的目的主要是为了演示GDI的使用。如有不足或者错误的地方欢迎大家指正。

首先我们看一下日常生活中我们所见到的电路板的样子:

然后再看一下我们程序运行时候的样子,当然我的程序模拟的并不是上图电路板。

程序模拟的电路板样子

这个例子主要的思路是这样子:有一个文本文件保存了一块电路板上电子元件的XY坐标、宽度、方向、以及元件的名称。其实这个文本文件就是一种自动化设备生产用的数据。如果没有这个数据文件,我们完全可以自己定义一个集合保存一些坐标、方向就可以了。

文本文件的内容

具体步骤如下:

  • 新建一个winform应用程序,在设计器中添加一个pictureBox控件,在load事件中设置picturebox控件的属性dock为DockStyle.Fill
  • 定义一个用来保存电路板数据的一个类
  • 编写一个方法从文本文件中获取所需要的数据
  • 将公制毫米为单位的坐标数据转换成屏幕像素
  • 得到数据中最大的坐标然后计算出与pictureBox控件的宽高的比例
  • 重写OnPaint()事件根据获取到的数据在pictureBox控件中绘制图形

设置picturebox控件的属性dock

pictureBox1.Dock = DockStyle.Fill;

定义一个DataContent类

定义一个DataContent类

List<DataContent> GetPointFromFile()方法从文本文件中获取所需要的数据

int MillimetersToPixelsWidth(int length)公制毫米单位转换成屏幕像素

得到数据中最大的坐标然后计算出与pictureBox控件的宽高的比例

在pictureBox控件中绘制图形

在绘制图形的时候,其实人们需要考虑的因素有许多,比如实际的坐标Y轴与屏幕Y轴的坐标相反等

最后我把完整代码贴出来:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Runtime.InteropServices;

using System.Text;

using System.Windows.Forms;

namespace WindowsFormsApplication3

{

public class DataContent

{

public Point InsCoordinate { get; set; }

public int Span { get; set; }

public int InsAngle { get; set; }

public string Comment { get; set; }

public DataContent(Point point, int span, int angle,string comment)

{

this.InsCoordinate = point;//坐标

this.Span = span;//跨度

this.InsAngle = angle;//角度

this.Comment = comment;//元件名称

}

}

public partial class Form1 : Form

{

public Form1()

{

InitializeComponent();

}

private void Form1_Load(object sender, EventArgs e)

{

pictureBox1.Dock = DockStyle.Fill;

}

protected override void OnPaint(PaintEventArgs e)

{

base.OnPaint(e);

try

{

Bitmap bitmap = new Bitmap(pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height);

List<DataContent> list = GetPointFromFile();

Graphics dc = Graphics.FromImage(bitmap);// Create dc

pictureBox1.Image = bitmap;

Point maxPoint = GetMaxCoordinate(list);//获取程序中最大的XY坐标

double xRate = ((double)maxPoint.X) / ((double)pictureBox1.ClientRectangle.Width - 40);

double yRate = ((double)maxPoint.Y) / ((double)pictureBox1.ClientRectangle.Height - 60);

dc.FillRectangle(new SolidBrush(Color.Green), pictureBox1.ClientRectangle);//绘制一个绿色背景的矩形

for (int i = 0; i < list.Count; i++)//绘制多个矩形

{

double x = ((double)list[i].InsCoordinate.X) / xRate;//x坐标 = 实际坐标 除以 坐标与屏幕pixel的比例

double y = ((double)list[i].InsCoordinate.Y) / yRate;

//Y轴坐标+20 pixel 如果实际坐标0,0 反转Y轴之后就会是Y轴最大的坐标,矩形会绘制在Y轴最大坐标上无法显示

//Point point = new Point((int)x,pictureBox1.ClientRectangle.Height - ((int)y + 20));//反转Y轴坐标

Point point = new Point((int)Math.Round(x,MidpointRounding.AwayFromZero),

pictureBox1.ClientRectangle.Height - ((int)Math.Round(y,MidpointRounding.AwayFromZero) + 20));//反转Y轴坐标

Rectangle rect = new Rectangle(point, new Size(0, 0));

Rectangle rectBlack = new Rectangle(point, new Size(0, 0));

double height = 6 / yRate;//元件的高度

int rectHeight = (int)Math.Round(height,MidpointRounding.AwayFromZero);//四舍五入将小数转换成整数

Color[] colors = { Color.Black, Color.White ,Color.Gray,Color.Gold,Color.Orange,Color.Silver,Color.Green,

Color.Blue,Color.Brown,Color.Yellow,Color.Violet};//电阻色环

double dSpan = list[i].Span / xRate;//元件的大小适应屏幕显示

int rectWidth = (int)Math.Round(dSpan,MidpointRounding.AwayFromZero);//元件矩形的宽度

rectWidth = rectWidth - (rectWidth / 2 / 2);//减去两边引脚的长度

//计算出元件两端的引脚长度

int leadLength = rectWidth / 2 / 2;

if (list[i].InsAngle == 0 || list[i].InsAngle == 180)// 0 180度元件模拟图绘制

{

#region

//绘制元件白色部分的本体

rect = new Rectangle(point, new Size(rectWidth, rectHeight));

if (list[i].Comment.Contains('D') || list[i].Comment.Contains('Z'))//判断是否为二极管

{

dc.FillRectangle(new SolidBrush(Color.White), rect);//绘制元件白色区域矩形

//绘制元件黑色部分的本体

if (list[i].InsAngle == 0)

{

rectBlack = new Rectangle(new Point(point.X + rectWidth / 4, point.Y), new Size(rectWidth - rectWidth / 4, rectHeight));

}

else//180度

{

rectBlack = new Rectangle(new Point(point.X , point.Y), new Size(rectWidth - rectWidth / 4, rectHeight));

}

DrawLead(list[i].InsAngle, dc, point, rectHeight, rectWidth, leadLength);

dc.FillRectangle(new SolidBrush(Color.Black), rectBlack);//绘制黑色元件区域

}

else if (list[i].Comment.Contains('J'))//如果是跳线

{

dc.DrawLine(new Pen(Color.White, 3), point, new Point(point.X + rectWidth, point.Y));

}

else//认为是电阻

{

dc.FillRectangle(new SolidBrush(Color.Pink), rect);//用粉红色绘制电阻元件本体

Random rnd = new Random();

for (int j = 1; j < 6; j++)

{

//绘制电阻色环

dc.DrawLine(new Pen(Color.FromArgb(rnd.Next(0, 256), rnd.Next(0, 256), rnd.Next(0, 256)), 2),

new Point(point.X + rectWidth / 6 * j, point.Y),

new Point(point.X + rectWidth / 6 * j, point.Y + rectHeight));

}

DrawLead(list[i].InsAngle, dc, point, rectHeight, rectWidth, leadLength);

}

#endregion

}

else

{

#region

rect = new Rectangle(point, new Size(rectHeight, rectWidth));

if (list[i].Comment.Contains('D') || list[i].Comment.Contains('Z'))//判断是否为二极管

{

dc.FillRectangle(new SolidBrush(Color.White), rect);//绘制元件白色区域矩形

//绘制元件黑色部分的本体

if (list[i].InsAngle == 90)

{

rectBlack = new Rectangle(new Point(point.X, point.Y + rectWidth / 4),

new Size(rectHeight, rectWidth - rectWidth / 4));

}

else

{

rectBlack = new Rectangle(new Point(point.X, point.Y),

new Size(rectHeight, rectWidth - rectWidth / 4));

}

DrawLead(list[i].InsAngle, dc, point, rectHeight, rectWidth, leadLength);

dc.FillRectangle(new SolidBrush(Color.Black), rectBlack);

}

else if (list[i].Comment.Contains('J'))

{

dc.DrawLine(new Pen(Color.White, 3), point, new Point(point.X, point.Y + rectWidth));

}

else//认为是电阻

{

dc.FillRectangle(new SolidBrush(Color.Gray), rect);//绘制元件白色区域矩形

Random rnd = new Random();

for (int j = 1; j < 6; j++)

{

dc.DrawLine(new Pen(colors[rnd.Next(0,colors.Length)], 2), new Point(point.X, point.Y + rectWidth / 6 * j),

new Point(point.X + rectHeight, point.Y + rectWidth / 6 * j));

}

DrawLead(list[i].InsAngle, dc, point, rectHeight, rectWidth, leadLength);

}

#endregion

}

//dc.DrawString((i + 1).ToString(), new Font('宋体', 8, FontStyle.Regular),

//new SolidBrush(Color.Red), new Point(rect.Left, rect.Y));

//if(i>1)//绘制线条

//{

// double x2 = ((double)list[i - 1].InsCoordinate.X) / xRate;

// double y2 = ((double)list[i - 1].InsCoordinate.Y) / yRate;

// Point point2 = new Point((int)x2, pictureBox1.ClientRectangle.Height - ((int)y2 + 20));

// dc.DrawLine(new Pen(Color.White), point, point2);//连接前后两个点

//}

}

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

}

private static void DrawLead(int angle,Graphics dc, Point point, int rectHeight, int rectWidth, int leadLength)

{

if(angle == 0||angle==180)

{

//绘制元件左边的引脚

dc.DrawLine(new Pen(Color.Silver, 3), new Point(point.X - leadLength, point.Y + rectHeight / 2),

new Point(point.X, point.Y + rectHeight / 2));

//绘制元件右边的引脚

dc.DrawLine(new Pen(Color.Silver, 3), new Point(point.X + rectWidth, point.Y + rectHeight / 2),

new Point(point.X + rectWidth + leadLength, point.Y + rectHeight / 2));

}

else

{

//绘制元件左边的引脚

dc.DrawLine(new Pen(Color.Silver, 3), new Point(point.X + rectHeight / 2, point.Y - leadLength),

new Point(point.X + rectHeight / 2, point.Y));

//绘制元件右边的引脚

dc.DrawLine(new Pen(Color.Silver, 3), new Point(point.X + rectHeight / 2, point.Y + rectWidth),

new Point(point.X + rectHeight / 2, point.Y + rectWidth + leadLength));

}

}

/// <summary>

/// 获取程序中最大的坐标

/// </summary>

/// <param name='list'></param>

/// <returns></returns>

private Point GetMaxCoordinate(List<DataContent> list)

{

Point point = new Point(0, 0);

for (int i = 0; i < list.Count; i++)

{

if (list[i].InsCoordinate.X > point.X) point.X = list[i].InsCoordinate.X;

if (list[i].InsCoordinate.Y > point.Y) point.Y = list[i].InsCoordinate.Y;

}

return point;

}

private List<DataContent> GetPointFromFile()

{

List<DataContent> list = new List<DataContent>();

List<Point> offsetList = new List<Point>();//保存拼板程序偏移量

try

{

string[] points = File.ReadAllLines(@'e:\1.ncd', Encoding.Default);

bool bIs = false;

for (int i = 0; i < points.Length; i++)

{

if (points[i] != '*')

{

string x = points[i].Substring(points[i].IndexOf('X') + 1, 7);

string y = points[i].Substring(points[i].IndexOf('Y') + 1, 7);

string span = points[i].Substring(points[i].IndexOf('W+') + 2, 5);

span = span.Substring(0, 3);

string angle = points[i].Substring(points[i].IndexOf('T') + 2, 2);

string comment = points[i].Substring(86, 8).Trim();//Comment

if (angle == '01')

{

angle = '0';

}

else if (angle == '02')

{

angle = '90';

}

else if (angle == '11')

{

angle = '180';

}

else if (angle == '12')

{

angle = '270';

}

x = x.Substring(0, 7);

y = y.Substring(0, 7);

x = x.Insert(5, '.');

y = y.Insert(5, '.');

double dx = Convert.ToDouble(x);

double dy = Convert.ToDouble(y);

dx = Math.Round(dx,MidpointRounding.AwayFromZero);

dy = Math.Round(dy,MidpointRounding.AwayFromZero);

Point point = new Point(MillimetersToPixelsWidth((int)dx * 2),MillimetersToPixelsWidth((int)dy * 2));

if (point.X < 0 || point.Y < 0)

{

bIs = true;

}

string value = points[i].Substring(10, 3);//取PR值

if (value == '902' || value == '912' || value == '922' || value == '932')

{

offsetList.Add(point);

}

else

{

string s = points[i].Substring(points[i].IndexOf('T') + 1, 3);//去掉T004这一空白行

if (!(Convert.ToInt32(s) == 4 || Convert.ToInt32(s) == 0))

{

list.Add(new DataContent(point, MillimetersToPixelsWidth(Convert.ToInt32(span)) * 2,

Convert.ToInt32(angle), comment));

}

}

}

}

if (bIs)//如果坐标中有负数

{

Point minPoint = new Point(0, 0);

for (int i = 0; i < list.Count; i++)

{

if (list[i].InsCoordinate.X < minPoint.X) minPoint.X = list[i].InsCoordinate.X;

if (list[i].InsCoordinate.Y < minPoint.Y) minPoint.Y = list[i].InsCoordinate.Y;

}

minPoint = new Point(Math.Abs(minPoint.X) + 15, Math.Abs(minPoint.Y) + 15);//绝对值加15个pixel 防止从0,0坐标画图

for (int i = 0; i < list.Count; i++)//把负数坐标变成正数

{

list[i].InsCoordinate = new Point(list[i].InsCoordinate.X + minPoint.X,

list[i].InsCoordinate.Y + minPoint.Y);

}

}

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

}

return list;

}

/// <summary>

/// 将公制毫米转换成屏幕像素

/// </summary>

/// <param name='length'></param>

/// <returns></returns>

private static int MillimetersToPixelsWidth(int length)

{

System.Windows.Forms.Panel p = new Panel();

Graphics dc = Graphics.FromHwnd(p.Handle);

IntPtr hdc = dc.GetHdc();

int width = GetDeviceCaps(hdc, 4);

int pixels = GetDeviceCaps(hdc, 8);

dc.ReleaseHdc(hdc);

return (((int)pixels / (int)width) * (int)length); //将公制毫米转换成屏幕像素点

}

[DllImport('gdi32.dll')]

private static extern int GetDeviceCaps(IntPtr hdc, int Index);

}

}

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
J2ME中使用Canvas制作简单的游戏菜单
C#刷遍Leetcode面试题系列连载(5):No.593 - 有效的正方形
【新提醒】【C#指定图片添加文字(仅PC)】
delphi截屏
asp.net 文件上传示例整理
NGUI所见即所得之UIAnchor & UIStretch
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服