我用graphics在groupbox中画了一个单坐标轴(X轴),坐标轴表示的是从0-100%,我想用一个垂直走向的线段指示当前示数(比如说当前值为Value),我现在的做法是每修改一次Value的值,都要调用graphics.clear()清除上一次画的图像,然后重新画。这样一来在清除线段的同时就连坐标轴一起清空了,所以没更改一次Value值我就得连坐标轴和线段都重画。效率很低有没有好的方法,望高手指点...

解决方案 »

  1.   

    坐标轴你可以先绘制在一个底图上,每次贴图,或是每次clear后重绘。吧绘制坐标轴和网格的部分抽出单独方法。
      

  2.   

    问题补充:我在上述GroupBox的Paint事件中写了重写事件,没胆界面刷新时,就会重画坐标轴要花100条竖线,感觉除此图之外的其他控件总是很卡,分批的显示出来不知道是什么原因,高手帮忙分析一下,谢谢
      

  3.   

    clear不会连底图一起清空吗?
      

  4.   

    我试着解释下一楼的意思,比较你画好一个底图存为一个bmp或者别的格式,放在本地资源上,上面的坐标轴已经画好了,你下次把图清掉后,可一在把这个图load到picturebox上,再在上面画图,可能会轻松点,或者直接用这个图作为backgroudimage,前图透明来重绘,不知道这个方法可可行,应该就是这个思路。
      

  5.   

    可以调整算法,做成局部刷新,只刷新一个区域,GDI中称为“脏矩形”。贴出代码,帮你调一下。
      

  6.   

    我的代码
    public static  void GrahpicsUpdate()
            {
                System.Drawing.Font font = new System.Drawing.Font("Arial", 8, FontStyle.Regular);
                graphics.DrawLine(mypen, 0, 192, 700, 192);
                //String[] n = { "0", ((double)MaxValue / 6).ToString(), ((double)MaxValue / 3).ToString(), ((double)MaxValue / 2).ToString(), ((double)MaxValue * 2 / 3).ToString(), ((double)MaxValue * 5 / 6).ToString(), ((double)MaxValue).ToString() };
                String[] n = { "0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%" };
                int xstart = 10;
                for (int i = 0; i < 11; i++)
                {
                    graphics.DrawString(n[i].ToString(), font, Brushes.DarkGray , xstart - 7, 192);//.Red
                    int Xmin = xstart;
                    for (int j = 0; j < 9; j++)
                    {
                        Xmin += 6;
                        if (j == 4) graphics.DrawLine(mypen, Xmin, 184, Xmin, 192);
                        else graphics.DrawLine(mypen, Xmin, 188, Xmin, 192);
                    }
                    graphics.DrawLine(mypen, xstart, 182, xstart, 192);
                    xstart = xstart + 60;
                    Thread.Sleep(1);
                }
                //graphics.DrawRectangle(mypen, 8, 192, 600, 10);
                graphics1.DrawLine(mypen1, x1, 180, x1, 200);
            }
    private void groupBox2_Paint(object sender, PaintEventArgs e)
            {
                            System.Drawing.Font font = new System.Drawing.Font("Arial", 8, FontStyle.Regular);
                graphics.DrawLine(mypen, 0, 192, 700, 192);
                String[] n = { "0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%" };
                int xstart = 10;
                for (int i = 0; i < 11; i++)
                {
                    graphics.DrawString(n[i], font, Brushes.DarkGray, xstart - 7, 192);//.Red
                    int Xmin = xstart;
                    for (int j = 0; j < 9; j++)
                    {
                        Xmin += 6;
                        if (j == 4) graphics.DrawLine(mypen, Xmin, 184, Xmin, 192);
                        else graphics.DrawLine(mypen, Xmin, 188, Xmin, 192);
                    }
                    graphics.DrawLine(mypen, xstart, 182, xstart, 192);
                    xstart = xstart + 60;
                    Thread.Sleep(1);
                }
                //graphics.DrawRectangle(mypen, 8, 192, 600, 10);
                graphics1.DrawLine(mypen1, x1, 180, x1, 200);
            }
    private void textBox5_TextChanged(object sender, EventArgs e)
            {            if (textBoxPresentVal.Text.Trim() != "")
                {
                   double  newdate = Convert.ToDouble(textBoxPresentVal.Text.Trim());
                   textBoxDiffer .Text =  (1000*(newdate - Form_Main .CurrentStandOut ) / Form_Main.MaxValue).ToString();
                   int x = Convert.ToInt32(10 + newdate * 600 / Form_Main.MaxValue);
                   //if (graphics1 .TranslateClip ())
                   //graphics1.Clear(Color.White );.Transparent
                   
                    if (Form_Main.XCount1 == 0)
                   {
                      Form_Main.graphics1.Clear(Color.WhiteSmoke);
                      Form_Main.graphics1.DrawLine(Form_Main.mypen1, x, 182, x, 202);
                      Form_Main.x1 = x;
                      Form_Main.XCount1++;
                      Form_Main.GrahpicsUpdate();               }
                   else
                   {
                       Form_Main.graphics1.Clear(Color.WhiteSmoke);
                       //Form_Main.graphics1.DrawLine(Form_Main.mypen1, x, 182, x, 202);
                       Form_Main.graphics1.TranslateClip(x - Form_Main.x1, 0);// .TranslateTransform
                       Form_Main.x1 = x;
                       Form_Main.XCount1++;
                       Form_Main.GrahpicsUpdate();
                   }
                }
            }
       坐标上面的值是根据TEXTbox5中的具体值算出来的,请指点,在线等,谢谢
      

  7.   

    你好,我发现我是直接将坐标轴画在了,groupbox中 直接画的线段组成的,像你说的画在picturebox 有什么本质性的区别吗?是不是要达到预期的效果就必须画在picturebox中?
      

  8.   

    我有个想法,你可以用在panel上面添加你的groupbox,然后把坐标轴画到panel上,并设置groupbox的背景色为透明,groupbox.backColor=Color.TransParent,然后再在groupbox上画你的东西,不一定能行,希望能帮上楼主
      

  9.   

    form_load()
    picturebox1.backgroundimage=c:\坐标轴.bmpdrawvalue()
    picturebox1.invaldate()
    ....
    g.drawlines(...
      

  10.   

    我不知道国内的编程水平怎样,别人的一个3D效果的DLL也只不过2-3m,但是功能和效果及速度都很好,你可以看看

    网站

    我们的水平和国外还是差很远。
    my blog
    http://ufo-crackerx.blog.163.com/
      

  11.   

    其实这个程序完全重画也不会很慢的,我给你改了下:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;namespace Paint
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        int x1=10;
            int max = 600;
            public  void GrahpicsUpdate(Graphics graphics)
            {
                Pen mypen = new Pen(Color.Black);
                Pen mypen1 = new Pen(Color.Red);
                System.Drawing.Font font = new System.Drawing.Font("Arial", 8, FontStyle.Regular);
                graphics.DrawLine(mypen, 0, 192, 700, 192);
                String[] n = { "0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%" };
                int xstart = 10;
                for (int i = 0; i < 11; i++)
                {
                    graphics.DrawString(n[i].ToString(), font, Brushes.DarkGray, xstart - 7, 192);//.Red
                    int Xmin = xstart;
                    for (int j = 0; j < 9; j++)
                    {
                        Xmin += 6;
                        if (j == 4) graphics.DrawLine(mypen, Xmin, 184, Xmin, 192);
                        else graphics.DrawLine(mypen, Xmin, 188, Xmin, 192);
                    }
                    graphics.DrawLine(mypen, xstart, 182, xstart, 192);
                    xstart = xstart + 60;
                }
                graphics.DrawLine(mypen1, x1, 180, x1, 200);
            }        private void groupBox2_Paint(object sender, PaintEventArgs e)
            {
                GrahpicsUpdate(e.Graphics);
            }        private void textBox5_TextChanged(object sender, EventArgs e)
            {
                double d = Convert.ToDouble(textBoxPresentVal.Text);
                x1 = (int)(d / 100 * max)+10;
                groupBox1.Invalidate(); //这里可以传入要更新的区域,不过我觉得没有必要,反而破坏了算法的简洁性,如果不是刻意地追求效率
            }
        }
    }
      

  12.   

    临书涕零啊!太让我感动了,十分感谢你所做的这些。但是,我刚刚明白我的程序为什么会出现那种效果了,因为在Groupbox中还有好多其它的空间,groupbox重绘时其它控件也要重绘。并不是着段绘图的代码直接造成的。所以我把绘图区域从groupbox分离出来了,我用了一个pictureBox控件,这样一来当TextBox5中内容更新时,调用pictureBox1_Paint完成图像更新。忘了说了,这个TextBox5是我自定义的一个控件中的一个TextBox所以不能直接调用pictureBox1_Paint,我在将pictureBox1_Paint声明为static了但是还是不行,提示“无法使用实例引用来访问成员“NETTEST.Form_Main.pictureBox1_Paint(object, System.Windows.Forms.PaintEventArgs)”;请改用类型名来限定它” 请问这是什么原因呀,要怎么解决,谢谢帮忙,我的分给的太少了,不好意思
      

  13.   

    调用pictureBox1_Paint完成图像更新?
    这样不是更好吗?
    pictureBox1.Invalidate();把pictureBox1传给你的自定义控件。
      

  14.   

    你好,但是怎么把pictureBox1传给我的自定义控件呀?我手头上没有资料,高手讲的详细点,谢谢
      

  15.   

    给自定义控件定义个属性:public PictrueBox PicBox
    {
       get;set;
    }
      

  16.   

    定义属性我是会的,但是没有事件,我想当属性值发生变化的时候让它自动触发调用pictureBox1.Invalidate();这里的PictrueBox在我的自定义控件中,而是在Form中 与该自定义控件是平等的层次关系。请问如何实现?