C#GDI+;剪贴画等
我正在编写一个具有面板的应用程序,其中显示:C#GDI+;剪贴画等,c#,zooming,gdi+,clip,pan,C#,Zooming,Gdi+,Clip,Pan,我正在编写一个具有面板的应用程序,其中显示: 图片背景 大量绘制的对象(使用GDI+线、路径等) 所述对象在鼠标移动事件中具有一定的命中检测 面板将平移和缩放。面板是双缓冲的 所以一切都很好——一切看起来都很好,没有闪烁,但我正努力专注于性能。我用不到1毫秒的时间来绘制我的对象(每个对象),但缩小后,我可以绘制500多个对象,这开始使从绘制到命中检测的一切都变得缓慢 为了提高性能,我已经做了一些事情,比如只列出屏幕上的(可绘制的)对象——但正如前面提到的,缩小后,仍然可能有很多。我有一个伟大
- 图片背景
- 大量绘制的对象(使用GDI+线、路径等)
- 所述对象在鼠标移动事件中具有一定的命中检测
private void PaintImage(PaintEventArgs e)
{
int scale = 10; //TARGET ICON BASE SCALE....
var watch2 = System.Diagnostics.Stopwatch.StartNew();
if (bitmap != null && redrawBG)
{
float widthZoomed = TgtPanel.Width / Zoom;
float heigthZoomed = TgtPanel.Height / Zoom;
//Do checks the reason 30,000 is used is because
//much over this will cause DrawImage to crash
if (widthZoomed > 30000.0f)
{
Zoom = TgtPanel.Width / 30000.0f;
widthZoomed = 30000.0f;
}
if (heigthZoomed > 30000.0f)
{
Zoom = TgtPanel.Height / 30000.0f;
heigthZoomed = 30000.0f;
}
//we stop at 2 because at this point you have almost zoomed into a single pixel
if (widthZoomed < 2.0f)
{
Zoom = TgtPanel.Width / 2.0f;
widthZoomed = 2.0f;
}
if (heigthZoomed < 2.0f)
{
Zoom = TgtPanel.Height / 2.0f;
heigthZoomed = 2.0f;
}
float wz2 = widthZoomed / 2.0f;
float hz2 = heigthZoomed / 2.0f;
Rectangle drawRect = new Rectangle(
(int)(viewPortCenter.X - wz2),
(int)(viewPortCenter.Y - hz2),
(int)(widthZoomed),
(int)(heigthZoomed));
e.Graphics.Clear(Color.White); //Clear the Back buffer
//Draw the image, Write image to back buffer, and [render back buffer - no longer using my own backbuffer]
e.Graphics.DrawImage(bitmap,
this.TgtPanel.DisplayRectangle, drawRect, GraphicsUnit.Pixel);
// e.Graphics.ScaleTransform(Zoom, Zoom);
// e.Graphics.DrawImage(bitmap,
// 0,0);
if (draging)
{ //line to visualize the drag
e.Graphics.DrawLine(new Pen(Color.Yellow, 10), StartDrag.X, StartDrag.Y, lastMouse.X, lastMouse.Y);
}
//this checks for offscreen - works
if (drawRect.X > iconbitmap.Width || drawRect.X < -(drawRect.Width) ||
drawRect.Y > 0 + iconbitmap.Height || drawRect.Y < -(drawRect.Height))
{
label1.Text = "OFF";
}
} //if bitmap != null & redraw
// Font and Brush for the text graphics
Point mypoint = WorldToScreen(0.75f * scale, 7.0f * scale);
RectangleF bgrect = new RectangleF();
bgrect.X = mypoint.X;
bgrect.Y = mypoint.Y;
bgrect.Width = (3.5f * scale * Zoom);
bgrect.Height = (2.0f * scale * Zoom);
int aFontSizeDefault = 40;
int aFontSizeMinimum = 2;
String adrawString = "AAA"; //test this length
Font aDefaultFont = new Font("MS Sans Serif", aFontSizeDefault, FontStyle.Regular);
FontAdjustment afa = new FontAdjustment();
Font AAdjustedFont = afa.GetAdjustedFont(e.Graphics, adrawString,
aDefaultFont, Convert.ToInt32(bgrect.Width), aFontSizeDefault, aFontSizeMinimum, true);
//DRAW TGT BG
var Point1 = ScreenToWorld(0, 0);
var Point2 = ScreenToWorld(TgtPanel.Width, TgtPanel.Height);
//getVisible Screen == on;y draw visible targets
if (redrawBG)
{
VISIBLETARGETS.Clear(); //erase visible tgts array - we're going to update it
foreach (Target TGT in THETARGETS)
if (TGT.PosX >= Point1.X - 40 && TGT.PosX <= Point2.X - 9)
if (TGT.PosY >= Point1.Y - 83 && TGT.PosY <= Point2.Y - 5)
{
TGT.OnScreen = true;
//drawTarget(TGT, AAdjustedFont, e);
VISIBLETARGETS.Add(TGT); //update as visible
}
else TGT.OnScreen = false;
//redrawBG = false;
}
var watch = System.Diagnostics.Stopwatch.StartNew();
foreach(Target TGT in VISIBLETARGETS)
{
if(TGT.Invalidated || redrawBG) // THIS IS DRAWING ONLY TGT -- NOT OTHERS, OR BG - FIX THIS WITH CLIPPING?
drawTarget(TGT, AAdjustedFont, e);
}
watch.Stop();
watch2.Stop();
var elapsedMs = watch.ElapsedMilliseconds;//ElapsedTicks;
label6.Text = "TotalDrawTime = " + watch2.ElapsedMilliseconds.ToString();
label4.Text = "AvgDrawTime = " + elapsedMs.ToString();
label5.Text = "VisibleTgts = " + VISIBLETARGETS.Count.ToString();
AAdjustedFont.Dispose();
aDefaultFont.Dispose();
//------------- DRAWING TGT WITH GDI - WITH ORIGINAL BACKBUFFER
/// myBuffer.Render(this.TgtPanel.CreateGraphics());
redrawBG = false;
}
public void drawTarget(Target Tgt, Font AAdjustedFont, PaintEventArgs e)
{
var watch = System.Diagnostics.Stopwatch.StartNew();
const float scale = 10; //10 is at 1 zoom
var bgrect = new RectangleF();
Point mypoint = WorldToScreen(Tgt.PosX + 0.75f * scale, Tgt.PosY + 1.0f * scale);
bgrect.X = mypoint.X;
bgrect.Y = mypoint.Y;
bgrect.Width = 3.5f * scale * Zoom;
bgrect.Height = 7.5f * scale * Zoom;
//PLAY WITH CLIP
e.Graphics.Clip = new Region(bgrect);
//var hbrush = new HatchBrush(HatchStyle.DarkDownwardDiagonal, Color.White);
var hbrush = new SolidBrush(Color.White);
//if(WantToDrawIconBG() ....
//e.Graphics.FillRectangle(hbrush, bgrect); //ICON BACKGROUND
//ADDR RECT
// mypoint = WorldToScreen(0, Tgt.PosY + 7.0f * scale);
mypoint = WorldToScreen(0, Tgt.PosY + 6.90f * scale); //moved Y up a bit from above
bgrect.Y = mypoint.Y;
bgrect.Height = 1.5f * scale * Zoom;
/////brush.Color = (Color.GhostWhite);
e.Graphics.FillRectangle(hbrush, bgrect);
hbrush.Dispose();
string adrawString = Tgt.Address;
System.Drawing.Font adrawFont = new System.Drawing.Font("Arial", 16);
System.Drawing.SolidBrush adrawBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.StringFormat adrawFormat = new System.Drawing.StringFormat();
adrawFormat.Alignment = StringAlignment.Center;
e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw addr
//======= LETS MAKE THE TGT ICON SHAPE =======
GraphicsPath path = new GraphicsPath(FillMode.Alternate);
//TARGET POINTS (w = 3, h = 6)
var h1 = WorldToScreen(Tgt.PosX + 2 * scale, Tgt.PosY + 1.1f * scale);
var h2 = WorldToScreen(Tgt.PosX + 3 * scale, Tgt.PosY + 1.1f * scale);
var n1 = WorldToScreen(Tgt.PosX + 2 * scale, Tgt.PosY + 2 * scale);
var n2 = WorldToScreen(Tgt.PosX + 3 * scale, Tgt.PosY + 2 * scale);
var s1 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 3 * scale);
var s2 = WorldToScreen(Tgt.PosX + 4 * scale, Tgt.PosY + 3 * scale);
var b1 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 7 * scale);
var b2 = WorldToScreen(Tgt.PosX + 4 * scale, Tgt.PosY + 7 * scale);
var controln2 = WorldToScreen(Tgt.PosX + 1 * scale, (Convert.ToInt32(Tgt.PosY + 0.5 * scale)));
var controls2 = WorldToScreen(Tgt.PosX + 1 * scale, Tgt.PosY + 1 * scale);
Pen pen = new Pen(Color.FromArgb(255, 0, 0, 255));
PointF[] npoints = { n2, s2, b2 };
PointF[] npoints2 = { n1, s1, b1 };
e.Graphics.DrawCurve(pen, npoints, 0.5f);
path.AddCurve(npoints, 0.5f); /////
e.Graphics.DrawLine(pen, b2, b1);
path.AddLine(b2, b1); /////
e.Graphics.DrawCurve(pen, npoints2, 0.5f);
path.AddCurve(npoints2, 0.5f); /////
PointF[] hpoints = { n1, h1, h2, n2 };
e.Graphics.DrawCurve(pen, hpoints, 0.1f);
path.AddCurve(hpoints, 0.1f); /////
path.CloseAllFigures();
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
if (Zoom > 0.9) //only draw stroke if big enough to see (and there arent a million targets to draw
{
pen.Color = Tgt.Selected ? Color.Chartreuse : Color.FromName(comboBox1.Text); //black default
pen.Width = Tgt.Selected ? 2 * Zoom : 1 * Zoom; //draw thicker border if selected
e.Graphics.DrawPath(pen, path); ///------------------------------------------STROKE PATH.....
//e.Graphics.FillPath(new SolidBrush(Color.ForestGreen), path);
}
// how much time is wasted making 2 gradient brushes? One we wont even use.
LinearGradientBrush linGrBrush = new LinearGradientBrush(
WorldToScreen(Tgt.PosX + 0 * scale, Tgt.PosY + 5 * scale),
WorldToScreen(Tgt.PosX + 5.5f * scale, Tgt.PosY + 5 * scale),
Color.ForestGreen, // Opaque red
Color.FromArgb(255, 0, 255, 0)); // Opaque blue
LinearGradientBrush linRedBrush = new LinearGradientBrush(
WorldToScreen(Tgt.PosX + 0 * scale, Tgt.PosY + 5 * scale),
WorldToScreen(Tgt.PosX + 5.5f * scale, Tgt.PosY + 5 * scale),
Color.FromArgb(255, 255, 0, 0), // Opaque red
Color.Firebrick); // Opaque blue
//FILL TARGET ICON WITH COLOR - UP or DOWN
if (Tgt.IsUp) e.Graphics.FillPath(linGrBrush, path);
else e.Graphics.FillPath(linRedBrush, path);
//------------
//tgt lines (cosmetic only)
if (Zoom > 0.9) //only draw if big enough to see (and there arent a million targets to draw
{
var transPen = new Pen(Color.FromArgb(150, 200, 200, 200));
var l1a = WorldToScreen(Tgt.PosX + 2.5f * scale, Tgt.PosY + 1.5f * scale);
var l1b = WorldToScreen(Tgt.PosX + 2.5f * scale, Tgt.PosY + 6 * scale);
e.Graphics.DrawLine(transPen, l1a, l1b);
var l2a = WorldToScreen(Tgt.PosX + 1.5f * scale, Tgt.PosY + 2.5f * scale);
var l2b = WorldToScreen(Tgt.PosX + 1.5f * scale, Tgt.PosY + 6.5f * scale);
e.Graphics.DrawLine(transPen, l2a, l2b);
var l3a = WorldToScreen(Tgt.PosX + 3.5f * scale, Tgt.PosY + 2.5f * scale);
var l3b = WorldToScreen(Tgt.PosX + 3.5f * scale, Tgt.PosY + 6.5f * scale);
e.Graphics.DrawLine(transPen, l3a, l3b);
}
//Draw Hits....
mypoint = WorldToScreen(Tgt.PosX + 1.0f * scale, Tgt.PosY + 3.0f * scale);
bgrect.X = mypoint.X;
bgrect.Y = mypoint.Y;
bgrect.Width = 3.0f * scale * Zoom;
bgrect.Height = 1.5f * scale * Zoom;
adrawString = Tgt.Hits.ToString();
adrawFormat.Alignment = StringAlignment.Center;
if (Zoom > 0.9) //only draw if big enough to see (and there arent a million targets to draw
{
adrawBrush.Color = Color.FromArgb(100, 100, 100, 100);
e.Graphics.FillRectangle(adrawBrush, bgrect);
}
adrawBrush.Color = Color.White;
e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw hits
//Draw Score....
mypoint = WorldToScreen(Tgt.PosX + 1.0f * scale, Tgt.PosY + 5.0f * scale);
bgrect.X = mypoint.X;
bgrect.Y = mypoint.Y;
bgrect.Width = 3.0f * scale * Zoom;
bgrect.Height = 1.5f * scale * Zoom;
adrawString = Tgt.Score.ToString();
adrawFormat.Alignment = StringAlignment.Center;
if (Zoom > 0.9) //only draw if big enough to see (and there arent a million targets to draw
{
adrawBrush.Color = Color.FromArgb(100, 100, 100, 100);
e.Graphics.FillRectangle(adrawBrush, bgrect);
}
adrawBrush.Color = Color.White;
e.Graphics.DrawString(adrawString, AAdjustedFont, adrawBrush, bgrect, adrawFormat); //draw hits
adrawFont.Dispose();
adrawBrush.Dispose();
adrawFormat.Dispose();
path.Dispose();
watch.Stop();
var elapsedMs = watch.ElapsedTicks;
//14279 original ticks
//12764 removing label and reducing font size calcs...
// 1695 ! removed font size to external calc so it happens only once
e.Graphics.ResetClip();
e.Graphics.Clip.Dispose();
Tgt.Invalidated = false; //dont draw again until change
}
private void PaintImage(PaintEventArgs e)
{
int scale=10;//目标图标基本比例。。。。
var watch2=System.Diagnostics.Stopwatch.StartNew();
if(位图!=null&&redrawBG)
{
浮动宽度缩放=TgtPanel.Width/Zoom;
浮动高度缩放=TgtPanel.高度/缩放;
//Do checks使用30000的原因是
//超过此范围将导致DrawImage崩溃
如果(宽度缩放>30000.0f)
{
缩放=TgtPanel.Width/30000.0f;
宽度缩放=30000.0f;
}
如果(高度缩放>30000.0f)
{
缩放=TgtPanel.高度/30000.0f;
高度缩放=30000.0华氏度;
}
//我们在2处停止,因为此时您几乎已放大到单个像素
如果(宽度缩放<2.0f)
{
缩放=TgtPanel.Width/2.0f;
宽度缩放=2.0f;
}
如果(高度缩放<2.0f)
{
缩放=TgtPanel.高度/2.0f;
高度缩放=2.0f;
}
浮动wz2=宽度缩放/2.0f;
浮动hz2=高度缩放/2.0f;
矩形drawRect=新矩形(
(int)(viewPortCenter.X-wz2),
(国际)(viewPortCenter.Y-hz2),
(int)(放大),
(内部)(高度缩放);
e、 Graphics.Clear(Color.White);//清除后缓冲区
//绘制图像,将图像写入后缓冲区,然后[渲染后缓冲区-不再使用我自己的后缓冲区]
e、 Graphics.DrawImage(位图、,
this.TgtPanel.DisplayRectangle、drawRect、GraphicsUnit.Pixel);
//e.Graphics.ScaleTransform(缩放、缩放);
//e.Graphics.DrawImage(位图、,
// 0,0);
如果(拖动)
{//line以可视化拖动
e、 绘图线(新钢笔(颜色:黄色,10),StartDrag.X,StartDrag.Y,lastMouse.X,lastMouse.Y);
}
//这检查屏幕外的工作
如果(drawRect.X>iconbitmap.Width | | drawRect.X<-(drawRect.Width)||
drawRect.Y>0+iconbitmap.Height | | drawRect.Y<-(drawRect.Height))
{
标签1.Text=“关闭”;
}
}//如果位图!=null&重新绘制
//文本图形的字体和画笔
点mypoint=WorldToScreen(0.75f*刻度,7.0f*刻度);
矩形F bgrect=新矩形F();
bgrect.X=mypoint.X;
bgrect.Y=mypoint.Y;
bgrect.Width=(3.5f*比例*缩放);
bgrect.Height=(2.0f*缩放比例*缩放);
int-aFontSizeDefault=40;
intafontsizeminimum=2;
String adrawString=“AAA”//测试此长度
Font aDefaultFont=新字体(“MS Sans Serif”,afontsizedfault,FontStyle.Regular);
FontAdjustment afa=新FontAdjustment();
字体aaadjustedFont=afa.GetAdjustedFont(例如图形、adrawString、,
aDefaultFont,Convert.ToInt32(bgrect.Width),afontsizedfault,aFontSizeMinimum,true);
//绘制TGT BG
变量点1=屏幕世界(0,0);
变量点2=屏幕到世界(TgtPanel.Width,TgtPanel.Height);
//getVisible Screen==打开;y绘制可见目标
如果(重绘背景)
{
VISIBLETARGETS.Clear();//删除可见tgts数组-我们将更新它
foreach(目标中的目标TGT)
if(TGT.PosX>=Point1.X-40&&TGT.PosX=Point1.Y-83&&TGT.PosY 0.9)//仅在足够大可以看到(并且没有一百万个目标)时绘制笔划