PictureBox仅在调整大小时更新

时间:2015-08-07 09:30:54

标签: c# winforms visual-studio picturebox

尝试在Form应用程序上显示图形。 创建一个PictureBox控件并使用其值初始化此类。 调整大小时,图表始终更新;在鼠标滚动上,它几乎没有。 它是GraphBox,PictureBox控件,在GraphBoxPanel,Panel控件中。

这个班:

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值快速执行(它是否有意义???),但对于较大的,更新或根本不需要几秒钟。 非常感谢你

2 个答案:

答案 0 :(得分:1)

像这样更改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应分配到PictureBoxe的{​​{1}}。

另请注意,除非Image没有PictureBox,否则外部尺寸(又名Border)与内部大小,Bounds。图片应该有ClientRectangle / ClientSize

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

但仔细研究source code我们找到原因:

PictureBox的Image是一个属性,在其setter中有一个对ClientSize的调用:

InstallNewImage

同样的电话也出现在其他一些地方,例如 public Image Image { get { return image; } set { InstallNewImage(value, ImageInstallationType.DirectlySpecified); } } Load的设定者。但仅改变场景背后的图像不会强制PictureBox进行该调用。 ImageLocation也应该这样做。而且,正如您所知,调整大小也会导致PictureBox在图像位图中拾取更改的数据。

答案 1 :(得分:0)

强制更新的最简单方法是invalidate the control

timer = new Timer();
timer.Interval = 200; //refreshes every 200 ms
timer.Tick += (sender,e) => targetImageBoxbox.Invalidate();
timer.Start();