c# - PictureBox 仅在调整大小时更新

标签 c# winforms visual-studio picturebox

尝试在表单应用程序上显示图形。 创建一个 PictureBox 控件并使用它的值初始化此类。 在调整大小时,图表总是更新;在鼠标滚动上,它几乎没有。 它是 GraphBox 和 PictureBox 控件,位于 GraphBoxPanel 面板控件内。

这个类:

public struct DLT_measure_item
{
    public DateTime ts;
    public float value;
    public int id;
    public int X;
    public int Y;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct dlt_ser_meas
{
    public byte msg_id;         // 'D'
    public byte meas_count;        // Number of measures
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public byte[] port;        // Module ID (4b) + Port ID (4b)
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
    public float[] meas;       // measure
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] msg_end;
}

public class manageGraph
{
    private PictureBox box;
    public bool displayGrid = true;
    private int   horAxisMin_p = 0;
    private int   horAxisMax_p = 300;
    private float verAxisMin_p = 0;
    private float verAxisMax_p = 40;
    public int   horAxisMin
    {
        get { return this.horAxisMin_p; }
        set
        {
            if (value < horAxisMax_p)
            {
                this.horAxisMin_p = value;
                reDraw();
            }
        }
    }
    public int   horAxisMax      
    {
        get { return this.horAxisMax_p; }
        set
        {
            if (value > horAxisMin_p)
            {
                this.horAxisMax_p = value;
                reDraw();
            }
        }
    }
    public float verAxisMin
    {
        get { return this.verAxisMin_p; }
        set
        {
            if (value < verAxisMax_p)
            {
                this.verAxisMin_p = value;
                verPointPerUnit = graphArea.Height / (verAxisMax_p - this.verAxisMin_p);
            }
        }
    }
    public float verAxisMax
    {
        get { return this.verAxisMax_p; }
        set
        {
            if (value > verAxisMin_p)
            {
                this.verAxisMax_p = value;
                verPointPerUnit = graphArea.Height / (this.verAxisMax_p - verAxisMin_p);
            }
        }
    }
    Pen axes = new Pen(Color.Black, (float)1.5);
    public int horAxisSpacing = 30;
    public int verAxisSpacing = 20;
    public int horAxis = 20;
    public int verAxis = 20;
    private float horPointPerUnit = 1;
    private float verPointPerUnit = 1;
    public int horAxisTickLen = 5;
    public int verAxisTickLen = 5;
    public bool horAxisShowTime = false;
    private Rectangle graphArea = new Rectangle();


    public void reDraw()
    {
        box.Image.Dispose();
        Bitmap GraphBlankImage = new Bitmap(box.Width, box.Height);
        box.Image = GraphBlankImage;
        updatePointPerUnit();
        drawGrid();
        box.Refresh();

    }
    public manageGraph(PictureBox targetImageBoxbox)
    {
        box = targetImageBoxbox;
        horAxisMin_p = 0;
        horAxisMax_p = 300;
        verAxisMin_p = 0F;
        verAxisMax_p = 50F;
        updatePointPerUnit();
    }
    private Point measToPoint(DLT_measure_item measure) {
        Point coords = new Point();
        coords.X = graphArea.Width - (int)( 
         ((DateTime.Now - measure.ts).TotalSeconds  + horAxisMin_p) * horPointPerUnit  )   ;
        coords.Y = graphArea.Height - (int)(
         ((measure.value - verAxisMin_p) * verPointPerUnit));
        return coords;
    }
    public manageGraph(PictureBox targetImageBoxbox, 
                       int xmin, int xmax, float ymin, float ymax)
    {
        box = targetImageBoxbox;
        horAxisMin_p = xmin;
        horAxisMax_p = xmax;
        verAxisMin_p = ymin;
        verAxisMax_p = ymax;
        updatePointPerUnit();
    }

    private void updateGraphArea()
    {
        graphArea = new Rectangle(0, 0, box.Width - horAxis, box.Height - verAxis);
    }

    private void updatePointPerUnit()
    {
        updateGraphArea();
        horPointPerUnit = graphArea.Width / (horAxisMax_p - horAxisMin_p);
        verPointPerUnit = graphArea.Height / (verAxisMax_p - verAxisMin_p);
    }

    public void drawGrid()
    {

        //updatePointPerUnit();
        using (Graphics g = Graphics.FromImage(box.Image))
        {
            // X axis
            g.DrawLine(axes, graphArea.Left, graphArea.Bottom, box.Width, graphArea.Bottom);
            // Y axis
            g.DrawLine(axes, graphArea.Right + 1, graphArea.Top, graphArea.Right +1, graphArea.Bottom);
            using (Font ArialFont = new Font("Arial", 10))
            {
                g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
                // Put x labels 
                for (int i = 1; i <= (graphArea.Width / horPointPerUnit); i = i + (int)(horAxisSpacing / horPointPerUnit ) + 1)
                {
                    g.DrawString((i).ToString(), ArialFont, Brushes.Black, graphArea.Width - ( i * horPointPerUnit) - 5, graphArea.Bottom +5);
                    g.DrawLine(axes, graphArea.Width - (i * horPointPerUnit), graphArea.Bottom + (horAxisTickLen / 2), graphArea.Width - (i * horPointPerUnit), graphArea.Bottom - (horAxisTickLen / 2));
                }
                // Put y labels 
                for (int i = 1; i <= (graphArea.Height / verPointPerUnit); i = i + (int)(verAxisSpacing / verPointPerUnit) +1)
                {
                    g.DrawString((i).ToString(), ArialFont, Brushes.Black, graphArea.Right + 1 , graphArea.Height - (i * verPointPerUnit) - 8);
                    g.DrawLine(axes, graphArea.Width - (verAxisTickLen / 2), (i * verPointPerUnit), graphArea.Width + (verAxisTickLen / 2), (i * verPointPerUnit));
                }
            }
            /*Put some random data*/
            DLT_measure_item testmeas = new DLT_measure_item();
            Point testGraphPoint = new Point();
            testmeas.ts = DateTime.Now;
            testmeas.value = 0;
            testGraphPoint = measToPoint(testmeas);
            g.FillEllipse(Brushes.Blue, testGraphPoint.X, testGraphPoint.Y, 4, 4);
            for (double i = 0; i < 300; i++)
            {
                double x = i;
                double freq = 10;
                double y = 30 - (i/10);
                testmeas.value = (float)y;
                testmeas.ts = DateTime.Now.AddSeconds(-1 * i);
                testGraphPoint = measToPoint(testmeas);
                g.FillEllipse(Brushes.Red, testGraphPoint.X, testGraphPoint.Y, 2,2);
            }
        }
    }
}

初始化:

    public DLThermalogMainForm()
    {
        InitializeComponent();
        Bitmap GraphBlankImage = new Bitmap(GraphBox.Width, GraphBox.Height);
        GraphBox.Image = GraphBlankImage;
        myGraph = new manageGraph(GraphBox);
        myGraph.drawGrid();

    }

那些处理程序:

    private void Form1_ResizeEnd(object sender, EventArgs e)
    {
        myGraph.reDraw();
        OutputTextBox.AppendText("Resize." + Environment.NewLine);
    }

    private void GraphBox_MouseMove(object sender, MouseEventArgs e)
    {
        //Get the focus to have the wheel working
        GraphBoxPanel.Focus();
    }

    private void GraphBoxPanel_MouseWheel(object sender, MouseEventArgs e)
    {
        // Change x axis max value to zoom in/out the graph
        myGraph.horAxisMax += e.Delta/ 120;
        myGraph.reDraw();
    }

在调整大小事件中,它总是重绘;在鼠标滚轮上,只有较小的 horAxisMax 值才会快速执行(这有意义吗???),但对于较大的值,更新需要很多秒,或者根本不需要。 非常感谢

最佳答案

像这样更改reDraw:

public void reDraw()
{
    box.Image.Dispose();
    Bitmap GraphBlankImage = new Bitmap(box.ClientSize.Width, box.ClientSize.Height);
    updatePointPerUnit();
    drawGrid(GraphBlankImage);
    box.Image = GraphBlankImage;
}

drawGrid像这样:

public void drawGrid(Bitmap bmp)
{
    //updatePointPerUnit();  //??
    using (Graphics g = Graphics.FromImage(bmp))
    {
     ...
     ...
     ...
    }
}

现在带有网格的 Bitmap 应该立即显示在 PictureBox 中。

如前所述,Graphics 对象是一种用于更改关联的Bitmap 的工具。要选择它,Bitmap 应该分配给 PictureBoxeImage

另请注意,除非您的 PictureBox 没有 Border,否则 outer 大小(也称为 Bounds ) 和内部 大小,ClientRectangle/ClientSize。图片应具有 ClientSize

您可能想知道为什么您的原始代码不起作用?毕竟 Image 是一种引用类型,因此像您所做的那样更改它就足够了..

但深入研究 source code我们找到原因:

PictureBox 的 Image 是一个属性,在它的 setter 中调用了 InstallNewImage:

    public Image Image {
        get {
            return image;
        }
        set {
            InstallNewImage(value, ImageInstallationType.DirectlySpecified);
        }
    }

同样的调用也出现在其他几个地方,如 LoadImageLocation 的 setter 中。但是仅在幕后更改 Image 不会强制 PictureBox 进行调用。 Refresh() 也应该这样做。而且,正如您所发现的,调整它的大小也会导致 PictureBox 在 Image Bitmap 中获取更改的数据。

关于c# - PictureBox 仅在调整大小时更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31874341/

相关文章:

c# - DevExpress Lookup编辑问题

c# - 有什么好的例子或框架可以教我n层开发吗?

c# - 获取覆盖的属性属性

C#:当用户开始输入时激活文本框

c# System.OutOfMemoryException 我该如何解决?

visual-studio - 错误 : this template attempted to load component assembly 'Microsoft. VisualStudio.Universal.TemplateWizards,版本=15.0.0.0

javascript - ES6 的 Visual Studio 任务运行程序错误

c# - 将扩展方法转换为泛型方法时出现编译时错误

c# - 如何正确使用UrlEncode和Decode

c# - 将空格附加到 stringbuilder?