Winform编程实现窗体上的函数曲线的绘制:(a值取1.05或0.95),绘制效果如下图所示.

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Winform编程实现窗体上的函数曲线的绘制:(a值取1.05或0.95),绘制效果如下图所示.相关的知识,希望对你有一定的参考价值。

void Main()

Form f = new Form();

//声明坐标轴与屏幕转换的参数与方法
float xScale = 100;
float yScale = 100;
f.Size = new Size(820,700);
PointF origin = new PointF(400,600);
Func<PointF, PointF> mapping = p=> 
return new PointF(origin.X+p.X*xScale,
origin.Y - p.Y*yScale);
;

f.Paint += (o,e) => 
var g = e.Graphics;
//绘制坐标轴
g.DrawLine(Pens.Black, mapping(new PointF(-10,0)),mapping(new PointF(10,0)));
for(int x=-10;x<=10;x++) 
g.DrawString(x.ToString(), f.Font, Brushes.Black, mapping(new PointF(x,0)));

g.DrawLine(Pens.Black, mapping(new PointF(0,-10)),mapping(new PointF(0,10)));
for(int y=1;y<=10;y++) 
g.DrawString(y.ToString(), f.Font, Brushes.Black, mapping(new PointF(0,y)));

//抗锯齿 曲线平滑
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//声明一个对指定数学函数描点绘制的方法
Action<Func<float, float>> DrawArc = func => 
Pen pen = new Pen(Color.Indigo, 3f);
List<PointF> points = new List<PointF>();
for(float x=-10;x<=10;x+=0.01f) 
points.Add(mapping(new PointF(x,func(x))));

g.DrawLines(pen, points.ToArray());
pen.Dispose();
;
//执行绘制 y=0.4^x
DrawArc(x=>(float)Math.Pow(0.4f, x));
//执行绘制 y=2.5^x
DrawArc(x=>(float)Math.Pow(2.5f, x));

;
Application.Run(f);

大致上就是用GDI+了。。这是个大致的例子。。具体的参数泥可以随意调整试试。

参考技术A 这个是指数函数啊。

你是不会算还是不会画?

实现Winform 跨线程安全访问UI控件

在多线程操作WinForm窗体上的控件时,出现“线程间操作无效:从不是创建控件XXXX的线程访问它”,那是因为默认情况下,在Windows应用程序中,.NET Framework不允许在一个线程中直接操作另一个线程中的控件(因为访问Windows窗体控件本质上不是线程安全的)。微软为了线程安全,窗体上的控件只能通过创建控件的线程来操作控件的数据,也就是只能是UI线程来操作窗体上的控件!可看看Control的Invoke和BeginInvoke

  要解决这个问题可以用以下方法:

  1、关闭线程安全检查(不过本人不推荐,这种方式可能会发生一些不可预计的后果)

Control对象.CheckForIllegalCrossThreadCalls = false;

  2、使用控件的Invoke方法(或BeginInvoke方法、BackgroundWorker)

(1)、Invoke方法

技术分享图片
if (this.InvokeRequired)
{
    this.Invoke(new Action(() => button1.Enabled = false));
    //button1.Invoke(new MethodInvoker(delegate() { button1.Enabled = false; }));
//textBox1.SafeCall(() =>{ textBox1.Text = (i++).ToString();});
button1.Invoke(new MethodInvoker(() => button1.Enabled = false )); button1.Invoke(new Action(() => button1.Enabled = false)); // 跨线程访问UI控件 } else { button1.Enabled = false }
技术分享图片

(2)、BeginInvoke方法

技术分享图片
        delegate void AppendValueDelegate(string strValue);

        public void AppendValue(string strValue)
        {
            textBox1.BeginInvoke(new AppendValueDelegate(AddValueToTextBox), new object[] { strValue });
        }

        private void AddValueToTextBox(string strValue)
        {
            textBox1.Text += strValue;
        }
技术分享图片

可精简成:

        public void AppendValue(string strValue)
        {
            // 无返回值无参数用MethodInvoker委托,无返回值可有参数用Action委托,有返回值可有参数用Func委托
            textBox1.BeginInvoke(new Action<string>(msg => textBox1.Text += msg), 
                new object[] { strValue });
        }

  3、使用委托

技术分享图片
public delegate void AddLog(string info);
/// <summary>
/// 添加日志
/// </summary>
AddLog OnAddLog;

/// <summary>
/// 加载事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FrmDataBackup_Load(object sender, EventArgs e)
{
    OnAddLog = new AddLog(PrintMsg);
}

/// <summary>
/// 打印信息到即时显示控件
/// </summary>
/// <param name="info"></param>
public void PrintMsg(string info)
{
    // InvokeRequired 属性判断是否跨线程操作
    if (this.InvokeRequired)
    {
        this.Invoke(OnAddLog, info);
        return;
    }
    listBoxInfo.Items.Insert(0, "[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "] " + info);
    if (listBoxInfo.Items.Count > 100)
    {
        listBoxInfo.Items.RemoveAt(100);
    }
}
技术分享图片

4、使用SynchronizationContext基类,该类记录着线程的同步上下文对象,我们可以通过在GUI线程中调用SynchronizationContext.Current属性来获得GUI线程的同步上下文,然后当线程池线程需要更新窗体时,可以调用保存的SynchronizationContext派生对象的Post方法(Post方法会将回调函数送到GUI线程的队列中,每个线程都有各自的操作队列的,线程的执行都是从这个队列中拿方法去执行),向Post方法传递要由GUI线程调用的方法(该方法的定义要匹配SendOrPostCallback委托的签名),还需要想Post方法传递一个要传给回调方法的参数。

技术分享图片
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.Runtime.Remoting.Messaging;
using System.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 定义用来实现异步编程的委托
         /// </summary>
        /// <returns></returns>
        private delegate string GetTextInfoDelegate();

        /// <summary>
        /// 线程同步上下文对象
         /// </summary>
        SynchronizationContext syncContext;
        /// <summary>
        /// 调用委托
         /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            GetTextInfoDelegate textInfo = new GetTextInfoDelegate(GetInfo);
            textInfo.BeginInvoke(new AsyncCallback(GetTextInfoResult), null);
            // 捕捉调用线程的同步上下文派生对象
              syncContext = SynchronizationContext.Current;
        }

        /// <summary>
        /// 异步操作获取信息
         /// </summary>
        /// <returns></returns>
        private string GetInfo()
        {
            return "使用SynchronizationContext基类";
        }

        /// <summary>
        /// 异步操作完成时执行的方法
         /// </summary>
        /// <param name="result"></param>
        private void GetTextInfoResult(IAsyncResult result)
        {
            GetTextInfoDelegate caller = (GetTextInfoDelegate)((AsyncResult)result).AsyncDelegate;
            // 调用EndInvoke去等待异步调用完成并且获得返回值
             // 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成
             string text = caller.EndInvoke(result);

            // 通过获得GUI线程的同步上下文的派生对象,
             // 然后调用Post方法来使更新GUI操作方法由GUI 线程去执行
             // ShowText(text);   // 报错:线程间操作无效: 从不是创建控件“textBox1”的线程访问它。
             syncContext.Post(new SendOrPostCallback(ShowText), text); 
        }

        /// <summary>
        /// 显示结果到TextBox文本框
         /// 因为该方法是由GUI线程执行的,所以当然就可以访问窗体控件了
         /// </summary>
        /// <param name="text"></param>
        private void ShowText(object text)
        {
            textBox1.Text = text.ToString();
        }
    }
}
技术分享图片

参考资料:http://www.cnblogs.com/easyfrog/archive/2012/02/08/2343075.html 和 http://www.cnblogs.com/zhili/archive/2013/05/10/APM.html



以上是关于Winform编程实现窗体上的函数曲线的绘制:(a值取1.05或0.95),绘制效果如下图所示.的主要内容,如果未能解决你的问题,请参考以下文章

winform 滚动条

c#winform编程中 在窗体上画一个大图盖住一个小图 怎么用程序实现选中小图

C#winform 主窗体上的用户控件怎样调用主窗体的一个方法!

C# winform怎么实现子窗体关闭时刷新父窗体数据

winform 怎么实现无边框阴影

在C#中如何实现winform窗体的全屏截图功能