我需要实现读取心电数据(.ecg格式,二进制文件),然后每读16位转成十进制存到一个short型的数组中(关于数据说一下,我要显示30秒的动态波形,每一秒有360个点,一个十进制数据代表一个点的纵坐标的值,也就是说要绘360*30个点),将这些点连接起来就是那条动态曲线。以下是我根据别人的代码修改过的,但是波形不动,请各位牛人帮我看一下,我在这里不胜感激!(网格部分无所谓,主要是波形)namespace WindowsFormsApplication4
{
    public partial class Form8 : Form
    {
        public Form8()
        {
            InitializeComponent();
        }
        int 网格间距 = 12; //网格间距
        int 网格偏移 = 0;   //网格偏移
        Pen 网格颜色 = new Pen(Color.FromArgb(0x00, 0x80, 0x40));
        Pen 曲线颜色 = new Pen(Color.Lime);
        private void Form8_Paint(object sender, PaintEventArgs e)
        {
            short[] data = new short[10800];
            FileStream fs = new FileStream("c://a.ecg", FileMode.Open);
            BinaryReader r = new BinaryReader(fs);
            for (int i = 0; i < 10800; i++)
            {
                data[i] = r.ReadInt16();
            }
            fs.Close();
            
            e.Graphics.FillRectangle(Brushes.Black, 0,0,800,640);
            for (int i = 800 - 网格偏移; i >= 0; i -= 网格间距)
                e.Graphics.DrawLine(网格颜色, i, 0, i, 640);
            //绘制横线
            for (int i = 640; i >= 0; i -= 网格间距)
                e.Graphics.DrawLine(网格颜色, 0, i, 800, i);
           
            short First = data[10800 - 1];
            for (int i = 10800 - 2; i >= 0; i--)
            {
                short Second = data[i];                e.Graphics.DrawLine(曲线颜色,
                    800 - (10800 - i), First / 3,
                    800 - (10800 - i) - 1, Second / 3);                First = Second;
            }
        }        private void Form8_Load(object sender, EventArgs e)
        {
            DoubleBuffered = true;
            this.timer1.Interval = 100;
            this.timer1.Start();
        }        private void timer1_Tick(object sender, EventArgs e)
        {
            网格偏移 = (网格偏移 + 1) % 网格间距;
            Invalidate();
        }
        private void Form8_Resize(object sender, EventArgs e)
        {
             Invalidate();
        }
    }
}我怀疑是不是private void timer_Tick这里少点东西??

解决方案 »

  1.   

    肯定啊,你看你在OnPaint中写了什么,每次都在初始化数组,每次画的都是一样的
      

  2.   

    粗看了一下,“网络偏移”这个变量没有用到实处。
    short First = data[10800 - 1];
      for (int i = 10800 - 2; i >= 0; i--)这两行改成这样试试:
    short First = data[10800 - 1 - 网格偏移];
      for (int i = 10800 - 2 - 网格偏移; i >= 0; i--)
      

  3.   

    请问bdmh,应该把读入和赋值写在哪里呢?谢谢,我是面向对象新手
      

  4.   


    short[] data = new short[10800];放在方法外面,在 Paint方法里面直接调用。
      

  5.   

    定义一个全局变量,标识每一次画图的起始点位置
    然后在timer_tick中修改这个变量
    paint中从这个变量的位置开始画图
      

  6.   

    还是不太懂,你的意思是说在全局那里读取文件一次,然后在timer_tick那里在读取文件 赋值,是吗?
      

  7.   

    中午闲来无事写了一段代码,希望对你有帮助。
        public partial class WaveForm : Form
        {
            const int POINTS_PER_SECOND = 360;        short[] _data;        public WaveForm()
            {
                InitializeComponent();            _data = GetWaveData(30);
            }        /// <summary>
            /// 由于没有数据文件,此方法生成一条SIN曲线的数据。
            /// </summary>
            /// <param name="seconds">以秒为单位的曲线长度。</param>
            /// <returns></returns>
            private static short[] GetWaveData(int seconds)
            {
                int length = seconds * POINTS_PER_SECOND;
                short[] array = new short[length];
                
                for (int i = 0; i < length; i++)
                {
                    array[i] = (short)Math.Round(100.0 * Math.Sin((double)(i % 360) * (Math.PI / 180.0)));
                }            return array;
            }        protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);
            }        protected override void OnPaint(PaintEventArgs e)
            {
                base.OnPaint(e);
                RenderWaveLine(e);
            }        private void RenderWaveLine(PaintEventArgs e)
            {
                Graphics g = e.Graphics;            g.TranslateTransform(20f, Height / 2f);            GraphicsPath path = new GraphicsPath();            int length = _data.Length;
                List<PointF> points = new List<PointF>(length);
                for (int i = _offset; i < length; i++)
                {
                    points.Add(new PointF(i - _offset, _data[i]));
                }
                
                path.AddLines(points.ToArray());            g.DrawPath(Pens.Lime, path);            path.Dispose();
            }        int _offset;        private void timer1_Tick(object sender, EventArgs e)
            {
                _offset = (_offset + 36) % _data.Length;
                
                this.Invalidate();
            }
        }
      

  8.   

    effun您好,您给我留的代码我运行了一次,是一条绿色的正弦曲线,请问怎么不能动呢?谢谢!麻烦您再帮我看看,不胜感激!
      

  9.   

    哦,忘掉说了,要在窗体上放一个Timer控件,然后把它的Tick事件和现有的timer1_Tick方法关联在一起就可以了。
      

  10.   

    唉~~~~ 再补充一句,timer1的Enabled属性要改为true,其它不用改。
      

  11.   

    画图实际不是这个问题的关键,画图是很容易滴关键是心电图这玩意的时间精度控制要求比较高,而Timer也只是一个大体上的控制,毕竟windows是个多任务平台,他并不是时时刻刻都在处理你这一件事情
      

  12.   

    我以前写过一个,呵呵。就是传入pint数组后就可以自动画了没什么麻烦的。
      

  13.   

    嗯,咱也是做过心电图的,主要注意下扫描速度,增益,回放的时候这个是有规定的。
    另外别用GDI+的反走样,医生不习惯看的。
      

  14.   

    一风先生您好!您说的很详细!那条曲线可以移动了。我刚刚接触编程,还是有些不解,我读取数据文件,然后赋到数组,是写在GetWaveData里吗?private static short[] GetWaveData(int seconds)
            {
                int length = seconds * POINTS_PER_SECOND;
                short[] array = new short[length];
                FileStream fs = new FileStream("c://a.ecg", FileMode.Open);
                BinaryReader r = new BinaryReader(fs);
                for (int i = 0; i < length; i++)
                {
                    array[i] = r.ReadInt16();
                }
                fs.Close();
                return array;
            }
           这样写貌似根本看不到曲线,麻烦您解答一下~
      

  15.   

    如果看不到曲线,可能是数值的关系。现在画图是按1:1的比例绘制的,如果数据文件里单个数据的绝对值超过窗体的高度那就自然看不到啦。你需要了解心电图数据值的波动范围,再根据这个数字以适当的比例生成绘图时的Y坐标。
    刚才仔细看你提供的代码,原来在绘图的时候是缩小3倍,那你也可以这样试试:
    for (int i = _offset; i < length; i++)
    {
         points.Add(new PointF(i - _offset, _data[i] / 3f));
    }
      

  16.   

    谢谢您一风先生!您说的很正确,就是这个原因。还有一个问题,现在我导入文件的路径是我手动改写的,FileStream fs = new FileStream("c://a.ecg", FileMode.Open);现在我想用父窗体的textBox.Text传过来的路径来作为子窗体(该绘图窗体)的文件路径,我在父窗体这样:public string passText
            {
                get { return textBox1.Text; }
            }然后在子窗体(该绘图窗体)也设定了一个public string dir,是这样接值的:
    dir = ((Form7)this.Owner).passText;/*(form7)是父窗体*/, dir变量取代了路径位置,可是运行时提示找不到'c:\dir'      请问您这该如何改呢?
      

  17.   

    对了,补充一下,我父窗体的下一步按钮是这样的:
     private void button2_Click(object sender, EventArgs e)
            {
                Form frm = new Form8();
                frm.Owner = this;
                frm.Show();
                this.Hide();
            }
      

  18.   

    美康都做了N多了,直接去买他一个就OK了.还用自己做?
    楼猪神经病.
      

  19.   


    从你描述的来看,传值应该没有问题,那就要确认在textBox1里输入的内容没有问题,再调试一下,看dir这个变量和textBox1里的内容是否相同。
    另外,你这种传值方法不太可靠,假如Owner不是Form7而是其它类型怎么办呢?最好是在Form8里设置一个参数并由调用者传入,可以在构造函数里写,例如:
    class Form8
    {
      // 这是原来的构造函数
      public Form8()
      {
         InitializeComponent();
      }  // 设置一个全局变量存放文件路径
      string _filename;  public Form8(string filename)
        : this()   // 调用原来的构造函数
      {
         if (!System.IO.File.Exists(filename))
            throw new System.IO.FileNotFoundException();
         _filename = filename;
      }
    }
    [code]
    这样,在Form7这样写:[code=C#]
    private void button2_Click(object sender, EventArgs e)
    {  string filename = textBox1.Text;
      if (System.IO.File.Exists(filename))   
      {
        Form8 frm = new Form8(filename);   // 在构造函数里把文件名传进去
        frm.FormClosed += (s, e1) => { this.Show(); }  // 这是为了在form8关闭了以后把自己自显示出来
        frm.Show();
        this.Hide();
      }
      else
        MessageBox.Show("文件" + filename + "未找到。");
    }
      

  20.   

    先生,您说的没错!我在Form8(子窗体,也就是绘图窗体)上加了一个label控件,然后把传过来的值赋到里面去,发现传值上确实没有问题。但还是报同样的问题。是不是这的问题呀:举个例子,假如父窗体(form7)用openFileDialog对话框,选择一个文件,得到文件名为D:\a.ecg,子窗体(form8) FileStream fs = new FileStream("_filename", FileMode.Open);/*_filename就是上面的路径*/而他要求的路径是这样写:D:\\a.ecg,是不是我少了一个"\"才导致找不到文件呢?如果是这样,请问您有什么高见呢?