DIY自己的GIS程序(2)——局部刷新
- 绘制线过移动鼠标程中绘制临时线段防闪烁
参考OpenS-CAD想实现绘制线的功能。希望实现绘制线的过程,在移动线的时候没有闪烁和花屏。但是出现了问题,困扰了2天,前天熬的太晚,搞得现在精力都没有恢复。现在终于把问题搞清楚了:
第一个问题:没有给背景图片赋颜色,此时相当于透明。所以每次将图片局部范围重绘产生严重的花屏,绘制的线段残留在屏幕上,将透明的东西绘制是不可能将移动过程中产生的临时线段擦除的。
第二个问题:用当前移动产生的线段包围盒来重绘,其实在本次鼠标移动过程中,应该将上次产生的残留擦除,用上次的包围盒局部重绘。
以下是自己写的一个控件的雏形:

1 using System;
2 using System.Collections.Generic;
3 using System.Drawing;
4 using System.Windows.Forms;
5 using RGeos.Geometry;
6 using System.Drawing.Imaging;
7
8 namespace RGeos.PluginEngine
9 {
10 public partial class UcMapControl2 : UserControl, IRMapControl
11 {
12 private ITool mCurrentTool = null;
13
14 public ITool CurrentTool
15 {
16 get { return mCurrentTool; }
17 set { mCurrentTool = value; }
18 }
19 public REnvelope mExtent { get; set; }
20 public Map mMap { get; set; }
21
22 private PointF m_panOffset = new PointF(25, -25);
23
24 public PointF PanOffset
25 {
26 get { return m_panOffset; }
27 set { m_panOffset = value; }
28 }
29 private PointF m_dragOffset = new PointF(0, 0);
30
31 public PointF DragOffset
32 {
33 get { return m_dragOffset; }
34 set { m_dragOffset = value; }
35 }
36 public UcMapControl2()
37 {
38 InitializeComponent();
39 mMap = new Map();
40 this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint, true);
41 this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
42 }
43
44 bool m_staticDirty = true;
45 //缓存图片?
46 Bitmap m_staticImage = null;
47 System.Drawing.Drawing2D.SmoothingMode m_smoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
48 protected override void OnPaint(PaintEventArgs e)
49 {
50 Tracing.StartTrack(Program.TracePaint);
51 #region old
52 e.Graphics.SmoothingMode = m_smoothingMode;
53 Rectangle cliprectangle = e.ClipRectangle;
54 if (m_staticImage == null)
55 {
56 cliprectangle = ClientRectangle;
57 m_staticImage = new Bitmap(ClientRectangle.Width, ClientRectangle.Height);
58 //m_staticImage.Save("D:\\a.png", ImageFormat.Png);
59 m_staticDirty = true;
60 }
61 //绘制在背景图片上
62 Graphics BitMapGc = Graphics.FromImage(m_staticImage);
63 BitMapGc.SmoothingMode = m_smoothingMode;
64 //绘制背景,注意如果不设将为透明色
65 BitMapGc.Clear(Color.White);
66 //this.BackgroundLayer.Draw(dcStatic, r);
67 //if (m_model.GridLayer.Enabled)
68 // m_model.GridLayer.Draw(dcStatic, r);
69 //绘制十字丝
70 RPoint rCenterPoint = new RPoint(0, 0, 0);
71 PointF nullPoint = Transform.ToScreen(rCenterPoint, this);
72 BitMapGc.DrawLine(Pens.Blue, nullPoint.X - 10, nullPoint.Y, nullPoint.X + 10, nullPoint.Y);
73 BitMapGc.DrawLine(Pens.Blue, nullPoint.X, nullPoint.Y - 10, nullPoint.X, nullPoint.Y + 10);
74 if (m_staticDirty)
75 {
76 m_staticDirty = false;
77
78 List<ILayer> layers = mMap.Layers;
79 for (int layerindex = layers.Count - 1; layerindex >= 0; layerindex--)
80 {
81 //if (layers[layerindex].Visible)
82 //layers[layerindex].Draw();
83 }
84 BitMapGc.Dispose();
85 }
86 //绘制背景图片
87 e.Graphics.DrawImage(m_staticImage, cliprectangle, cliprectangle, GraphicsUnit.Pixel);
88 //绘制新建对象
89 //if (m_newObject != null)
90 // m_newObject.Draw(dc, r);
91 #endregion
92 Tracing.EndTrack(Program.TracePaint, "OnPaint complete");
93
94 }
95
96 protected override void OnResize(EventArgs e)
97 {
98 base.OnResize(e);
99 if (m_lastCenterPoint != null && Width != 0)
100 SetCenterScreen(Transform.ToScreen(m_lastCenterPoint, this), false);
101 m_lastCenterPoint = CenterPointUnit();
102 m_staticImage = null;
103 Invalidate();
104 }
105 RPoint m_lastCenterPoint;
106 /// <summary>
107 /// 设置画布到屏幕的中心
108 /// </summary>
109 /// <param name="rPoint">直角坐标系坐标</param>
110 public void SetCenter(RPoint unitPoint)
111 {
112 PointF point = Transform.ToScreen(unitPoint, this);
113 m_lastCenterPoint = unitPoint;
114 SetCenterScreen(point, false);
115 }
116
117 protected void SetCenterScreen(PointF screenPoint, bool setCursor)
118 {
119 float centerX = ClientRectangle.Width / 2;
120 m_panOffset.X += centerX - screenPoint.X;
121
122 float centerY = ClientRectangle.Height / 2;
123 m_panOffset.Y += centerY - screenPoint.Y;
124
125 if (setCursor)
126 Cursor.Position = this.PointToScreen(new Point((int)centerX, (int)centerY));
127 Invalidate();
128 }
129 public RPoint CenterPointUnit()
130 {
131 RPoint p1 = Transform.ToUnit(new PointF(0, 0), this);
132 RPoint p2 = Transform.ToUnit(new PointF(this.ClientRectangle.Width, this.ClientRectangle.Height), this);
133 RPoint center = new RPoint();
134 center.X = (p1.X + p2.X) / 2;
135 center.Y = (p1.Y + p2.Y) / 2;
136 return center;
137 }
138 protected override void OnMouseUp(MouseEventArgs e)
139 {
140 base.OnMouseUp(e);
141
142 }
143 int n = 0;
144 PointF p1;
145 PointF TempPoint2;//缓存移动过程中产生的第二个点,上一移动过程中
146 protected override void OnMouseMove(MouseEventArgs e)
147 {
148 base.OnMouseMove(e);
149
150 Rectangle invalidaterect = Rectangle.Empty;
151 if (n < 1)
152 {
153
154 }
155 else
156 {
157 //REnvelope env = mNewLine.GetBoundingBox();
158 //mNewLine.P1 = new RPoint(e.X, e.Y, 0);
159
160 double xmin = Math.Min(p1.X, TempPoint2.X);
161 double ymin = Math.Min(p1.Y, TempPoint2.Y);
162 double w = Math.Abs(p1.X - TempPoint2.X);
163 double h = Math.Abs(p1.Y - TempPoint2.Y);
164 invalidaterect = new Rectangle((int)xmin, (int)ymin, (int)w, (int)h);
165 invalidaterect.Inflate(2, 2);
166
167 Pen pen = new Pen(Color.Red);
168 //擦除上次移动绘制的线,通过重绘上次移动范围区域的缓存图片实现
169 RepaintStatic(invalidaterect);
170 //Bitmap m_staticImage2 = new Bitmap(invalidaterect.Width, invalidaterect.Height);
171 //m_staticImage2.Save("D:\\adfghj.png", ImageFormat.Png);
172 pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;
173 pen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
174 Graphics dc = Graphics.FromHwnd(Handle);
175 dc.SmoothingMode = m_smoothingMode;
176 Point p2 = new Point(e.X, e.Y);
177 dc.DrawLine(pen, p1, p2);
178 dc.Dispose();
179 TempPoint2 = p2;
180 //Invalidate();
181 //DoInvalidate(false, invalidaterect);
182
183 }
184 }
185 protected override void OnMouseDown(MouseEventArgs e)
186 {
187 n++;
188 if (n <= 1)
189 {
190 //mNewLine = new RSegment();
191 //mNewLine.P0 = new RPoint(e.X, e.Y, 0);
192 //mNewLine.P1 = new RPoint();
193 //初始化两个点,注意此处两点相同。
194 p1 = new PointF(e.X, e.Y);
195 TempPoint2 = new Point(e.X, e.Y);
196 Invalidate(true);
197 }
198 base.OnMouseDown(e);
199 }
200 public void DoInvalidate(bool dostatic, Rectangle rect)
201 {
202 if (dostatic)
203 m_staticDirty = true;
204 Invalidate(rect);
205 }
206 /// <summary>
207 /// 局部刷新,重新绘制图片Bitmap无效区域
208 /// </summary>
209 /// <param name="r"></param>
210 public void RepaintStatic(Rectangle r)
211 {
212 if (m_staticImage == null)
213 return;
214 Graphics dc = Graphics.FromHwnd(Handle);
215 if (r.X < 0) r.X = 0;
216 if (r.X > m_staticImage.Width) r.X = 0;
217 if (r.Y < 0) r.Y = 0;
218 if (r.Y > m_staticImage.Height) r.Y = 0;
219
220 if (r.Width > m_staticImage.Width || r.Width < 0)
221 r.Width = m_staticImage.Width;
222 if (r.Height > m_staticImage.Height || r.Height < 0)
223 r.Height = m_staticImage.Height;
224 dc.DrawImage(m_staticImage, r, r, GraphicsUnit.Pixel);
225 Image temp = new Bitmap(m_staticImage);
226 Graphics gc = Graphics.FromImage(temp);
227 gc.DrawLine(Pens.Blue, r.Location, new Point(r.Location.X + r.Width, r.Location.Y + r.Height));
228 gc.Dispose();
229 temp.Save("d:\\AAAA.png", ImageFormat.Png);
230 m_staticImage.Save("d:\\BBBB.png", ImageFormat.Png);
231 dc.Dispose();
232 }
233 public float ScreenHeight()
234 {
235 return (float)(Transform.ToUnit(this.ClientRectangle.Height, this as IRMapControl));
236 }
237 private float mZoom = 1.0f;
238 public float Zoom
239 {
240 get
241 {
242 return mZoom;
243 }
244 set
245 {
246 mZoom = value;
247 }
248 }
249 }
250 }
今年的一个目标:完成一个开源项目
参考:http://www.codeproject.com/Articles/6238/Canvas-implementation-for-C
作者:太一吾鱼水
文章未经说明均属原创,学习笔记可能有大段的引用,一般会注明参考文献。
欢迎大家留言交流,转载请注明出处。
分类:
图形学 & GIS算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2012-01-04 DataGridViewButtonCell增加事件处理