参考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