正如标题所说:
我有2个轨道栏的表格。一个用于频率,一个用于幅度。我为即时更改设置了计时器。
private void timer1_Tick(object sender, EventArgs e)
{
float amplitude, frequency;
amplitude = Convert.ToSingle(trackBar1.Value) / 100;
label1.Text = amplitude.ToString() + " V";
frequency = trackBar2.Value;
label2.Text = frequency.ToString() + " Hz";
}
我还有4个无线电按钮来决定,将显示类型的信号(正弦,方形,三角形,锯齿形)
现在我用ImageList实现了这个(改变信号图像)。
如何绘制信号类型并使用跟踪条进行调节?所以它就像在振镜中一样。
感谢您的回答和代码。
答案 0 :(得分:1)
让我们从创建不同的信号类型开始,这是一个创建一个幅度为1的波长的函数:
private PointF[] CreateBaseSignal(SignalType signalType)
{
switch (signalType)
{
case SignalType.Sine:
const int oversampling = 32;
PointF[] signal = new PointF[oversampling];
for (int i = 0; i < signal.Length; i++)
{
signal[i].X = (float) i / oversampling;
signal[i].Y = Convert.ToSingle(Math.Sin((double) i / oversampling * 2 * Math.PI));
}
return signal;
case SignalType.Square:
return new PointF[]
{
new PointF(0.0f, -1.0f),
new PointF(0.5f, -1.0f),
new PointF(0.5f, 1.0f),
new PointF(1.0f, 1.0f),
};
case SignalType.Triangle:
return new PointF[]
{
new PointF(0.0f, -1.0f),
new PointF(0.5f, 1.0f),
};
case SignalType.Sawtooth:
return new PointF[]
{
new PointF(0.0f, -1.0f),
new PointF(1.0f, 1.0f),
};
default:
throw new ArgumentException("Invalid signal type", "signalType");
}
}
然后我们用选定的幅度和频率创建实际信号:
private PointF[] CreateSignal(PointF[] baseSignal, float frequency, float amplitude)
{
PointF[] signal = new PointF[Convert.ToInt32(Math.Ceiling(baseSignal.Length * frequency))];
for(int i = 0; i < signal.Length; i++)
{
signal[i].X = baseSignal[i % baseSignal.Length].X / frequency + (i / baseSignal.Length) / frequency;
signal[i].Y = baseSignal[i % baseSignal.Length].Y * amplitude;
}
return signal;
}
在尝试将此信号绘制到PictureBox之前,我们缩放信号以适合宽度和高度:
private PointF[] ScaleSignal(PointF[] signal, int width, int height)
{
const float maximumAmplitude = 10.0f;
PointF[] scaledSignal = new PointF[signal.Length];
for(int i = 0; i < signal.Length; i++)
{
scaledSignal[i].X = signal[i].X * width;
scaledSignal[i].Y = signal[i].Y * height / 2 / maximumAmplitude;
}
return scaledSignal;
}
使用Graphics.DrawLine绘制信号比Bitmap.SetPixel更好,因为即使在高频率下数据点也会连接。 Bitmap.SetPixel也很慢,你真的需要使用Bitmap.LockBits和不安全的代码来操纵单个像素来实现任何体面的性能。使用Graphics.DrawLine,您还可以控制线宽,消除锯齿等。
由于我们已将信号存储在PointF数组中,因此我们可以使用简单的Graphics.DrawLines方法绘制信号,而不是迭代数据点:
private void PlotSignal(PointF[] signal, PictureBox pictureBox)
{
Bitmap bmp = new Bitmap(pictureBox.ClientSize.Width, pictureBox.ClientSize.Height);
signal = ScaleSignal(signal, bmp.Width, bmp.Height); // Scale signal to fit image
using(Graphics gfx = Graphics.FromImage(bmp))
{
gfx.SmoothingMode = SmoothingMode.HighQuality;
gfx.TranslateTransform(0, bmp.Height / 2); // Move Y=0 to center of image
gfx.ScaleTransform(1, -1); // Make positive Y axis point upward
gfx.DrawLine(Pens.Black, 0, 0, bmp.Width, 0); // Draw zero axis
gfx.DrawLines(Pens.Blue, signal); // Draw signal
}
// Make sure the bitmap is disposed the next time around
Image old = pictureBox.Image;
pictureBox.Image = bmp;
if(old != null)
old.Dispose();
}
如果经常重绘信号,您可能希望重复使用Bitmap和Graphics对象,而不是每次都创建新对象。只需记住在每次重绘之间调用Graphics.Clear。
将所有内容放在一个大的声明中:
PlotSignal(
CreateSignal(
CreateBaseSignal(signalType),
frequency,
amplitude),
thePictureBox);
答案 1 :(得分:0)
如果您正在使用快速绘图库,我真的很喜欢动态数据显示
这是一个WPF组件,但是对于快速,流畅的绘图应用程序,我真的认为有必要比以后更快地移植到WPF。无论如何,感觉你现在的项目并不太远。
WPF的开发似乎已经停止了这个组件(虽然它继续为Silverlight工作)。文档很糟糕,但源代码可以从上面的链接获得,因此您可以根据需要进行扩展(它编写得非常好并且非常易于扩展),并且源代码非常宝贵,可以替代几乎完全没有任何文档。
答案 2 :(得分:0)
假设您要在图片框控件上绘制正弦波,请在表单上创建一个图片框控件,然后执行以下操作:
int width = pictureBox1.Width;
int height = pictureBox1.Height;
Bitmap b = new Bitmap(width, height);
for (int i = 0; i < width; i++)
{
int y = (int)((Math.Sin((double)i * 2.0 * Math.PI / width) + 1.0) * (height - 1) / 2.0);
b.SetPixel(i, y, System.Drawing.Color.Red);
}
pictureBox1.Image = b;