Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#GDI+;剪贴画等_C#_Zooming_Gdi+_Clip_Pan - Fatal编程技术网

C#GDI+;剪贴画等

C#GDI+;剪贴画等,c#,zooming,gdi+,clip,pan,C#,Zooming,Gdi+,Clip,Pan,我正在编写一个具有面板的应用程序,其中显示: 图片背景 大量绘制的对象(使用GDI+线、路径等) 所述对象在鼠标移动事件中具有一定的命中检测 面板将平移和缩放。面板是双缓冲的 所以一切都很好——一切看起来都很好,没有闪烁,但我正努力专注于性能。我用不到1毫秒的时间来绘制我的对象(每个对象),但缩小后,我可以绘制500多个对象,这开始使从绘制到命中检测的一切都变得缓慢 为了提高性能,我已经做了一些事情,比如只列出屏幕上的(可绘制的)对象——但正如前面提到的,缩小后,仍然可能有很多。我有一个伟大

我正在编写一个具有面板的应用程序,其中显示:

  • 图片背景
  • 大量绘制的对象(使用GDI+线、路径等)
  • 所述对象在鼠标移动事件中具有一定的命中检测
面板将平移和缩放。面板是双缓冲的

所以一切都很好——一切看起来都很好,没有闪烁,但我正努力专注于性能。我用不到1毫秒的时间来绘制我的对象(每个对象),但缩小后,我可以绘制500多个对象,这开始使从绘制到命中检测的一切都变得缓慢

为了提高性能,我已经做了一些事情,比如只列出屏幕上的(可绘制的)对象——但正如前面提到的,缩小后,仍然可能有很多。我有一个伟大的想法,也许我可以实现一个简单的Invalidate(),告诉对象它做出了值得绘制的视觉变化,而不是每次都更新每个对象。在对象绘制代码(传递给e.graphics)中,我尝试将剪裁区域设置为对象的大小,并仅更新面板BG的该部分(完成后,我重置了e.Grpahics.clip)。结果只有无效的对象绘制-其他所有内容均为空白

我相信这就是我身上的C#/GDI noob,你们都会告诉我我可能忽略了什么愚蠢的错误

在写这篇文章时,我意识到我可以通过使对象的路径保持不变而不是每次在draw函数中都使其保持新鲜来节省一些时间(因为所有对象路径都是相同的)。我很快就会随着剃掉的时间更新

下面是绘制BG图像(并确定要绘制的OBJ)和OBJ绘制代码的代码

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)//仅在足够大可以看到(并且没有一百万个目标)时绘制笔划