C#窗体应用开发基础(二)——事件与方法

2 篇文章 0 订阅
1 篇文章 0 订阅

目录

总述

控件交互型事件

类与属于类的方法

方法在事件中调用

控件窗体交互型事件

方法中值的返回


总述

事件在某种意义上可以理解为控件交互或控件与窗体的交互,可以说成是不需要编写代码来调用的方法。这样分类可能并不严格,解释也不一定正确,但比较容易理解。按照这个思路,首先来看一下控件交互型事件。

控件交互型事件

控件间的交互很容易理解,打个比方:点击某个按钮,实现了对某个文本框内的数据的计算并返回给另一个文本框。在这里,点击按钮这个事件出发的即是后续一系列内容。

具体应该如何实现,就以单击按钮实现读取计算写入为例来说明。

类与属于类的方法

首先,应有实现此计算所使用的系列方法,在此不建议直接将方法写入事件内,而是单独建立一个类,实现方法的调用。例如,要实现角度计算(Angel Calculation),可以先创建一个角度计算类:

using System;

namespace AngCal
{
    /// <summary>
    /// 角度相关
    /// </summary>
    public class AngCal
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        public AngCal()
        {

        }
    }
}

当然,也可以加入一些字段封装成属性,比如

using System;

namespace AngCal
{
    /// <summary>
    /// 角度相关
    /// </summary>
    public class AngCal
    {
        private double degree;
        private double minute;
        private double second;
        private double rad;
        public double Degree { get => degree; set => degree = value; }
        public double Minute { get => minute; set => minute = value; }
        public double Second { get => second; set => second = value; }
        public double Rad { get => rad; set => rad = value; }
        /// <summary>
        /// 构造方法
        /// </summary>
        public AngCal()
        {

        }
    }
}

属性与全局变量有一定类似之处,但又不完全相同,此处不再赘述。

类中的方法,根据是否有static关键字修饰,可分为静态与非静态两种。静态方法要以类调用,非静态方法则是以对象调用。下面举例说明:

/// <summary>
/// 非静态:角度转弧度
/// 输入格式dd(度).mm(分)ssss(秒)
/// </summary>
public double Ang2Rad(double Degrees)
{
    double Degree = Math.Truncate(Degrees);
    double Minute = Math.Truncate((Degrees - Degree) * 100);
    double Second = ((Degrees - Degree) * 100 - Minute) * 100;
    double Rad = (Degree + Minute / 60 + Second / 3600) / 180 * Math.PI;
    return Rad;
}

/// <summary>
/// 静态:角度转弧度
/// 输入格式dd(度).mm(分)ssss(秒)
/// </summary>
static public double Ang2Rad(double Degrees)
{
    double Degree = Math.Truncate(Degrees);
    double Minute = Math.Truncate((Degrees - Degree) * 100);
    double Second = ((Degrees - Degree) * 100 - Minute) * 100;
    double Rad = (Degree + Minute / 60 + Second / 3600) / 180 * Math.PI;
    return Rad;
}

注意这里采用的是没有添加任何字段和属性的类。两者调用时区别如下:

// 静态方法调用举例
double Angel = 30.1124;
double Rad = AngCal.AngCal.Ang2Rad(Angel);

// 非静态方法调用举例
double Angel = 30.1124;
AngCal.AngCal angcal = new AngCal.AngCal();
double Rad = angcal.Ang2Rad(Angel);

注意此处如果对namespace AngCal进行using,则可简化为

using AngCal;

......

// 静态方法调用举例
double Angel = 30.1124;
double Rad = AngCal.Ang2Rad(Angel);

// 非静态方法调用举例
double Angel = 30.1124;
AngCal angcal = new AngCal();
double Rad = angcal.Ang2Rad(Angel);

方法在事件中调用

之后可在工具箱拖动一个按钮控件进入窗体,对按钮属性进行调整,一切就绪后,双击Design界面的按钮,即可添加单击事件。假设此时需要将name为Degree的文本框内的内容计算弧度并返回给name为Rad的文本框,则可如此处理:

private void 计算_Click(object sender, EventArgs e)
{
    AngCal angcal = new AngCal();
    string degree = Degree.Text;
    Rad.Text = Convert.ToString(Math.Round(angcal.Ang2Rad(Convert.ToDouble(degree)), 5));
}

如此即可实现以上所述功能。由此可以看出:

1.事件确实作为一种方法出现在窗体类中,但不需要程序员编写代码调用,系统已经设定了调用的方式;

2.如果调用不属于同一个命名空间的类中的方法,需要在类前缀以命名空间或对对应的命名空间进行using,如果方法所属类不仅命名空间与窗体类不同,也不属于窗体类所属的解决方案,则还需要添加引用;

3.调用类时需要注意返回值类型,灵活的进行值类型转换。在调试时建议使用Parse或ToType方法,因为TryParse可能会产生误导。

控件窗体交互型事件

此处仍然举例说明。例如要通过单击按钮隐藏窗体或关闭程序:

// 隐藏窗体
private void 隐藏_Click(object sender, EventArgs e)
{
    Form1.Hide();
}

// 退出程序
private void 退出_Click(object sender, EventArgs e)
{
    Application.Exit();
}

一般控件和窗体交互时很少使用其他类的方法。

方法中值的返回

对于有返回值的方法,其返回值类型即是方法前类型关键字对应的类型。例如:

/// <summary>
/// 弧度转角度
/// </summary>
public double Rad2Ang(double Rad)
{
    double dd = Rad / Math.PI * 180;
    double Degree = Math.Truncate(dd);
    double Minute = Math.Truncate((dd - Degree) * 60);
    double Second = Math.Round(((dd - Degree) * 60 - Minute) * 60, 10);//返回10位小数
    double Degrees = Degree + Minute / 100 + Second / 10000;
    return Degrees;
}

/// <summary>
/// dd.mmssss转换为°'"格式
/// </summary>
public string Ang2Str(double Degrees)
{
    string symbol = "";
    if (Degrees < 0)
    {
        Degrees = Math.Abs(Degrees);
        symbol = "-";
    }
    double Degree = Math.Truncate(Degrees);
    double Minute = Math.Truncate((Degrees - Degree) * 100);
    double Second = ((Degrees - Degree) * 100 - Minute) * 100;
    string AngStr = symbol + Degree.ToString() + "°" + Minute.ToString() + "′" +             
    Second.ToString() + "″";
    return AngStr;
}

Rad2Ang方法返回的数值是dd.mmss格式的度分秒,可以以double,也可以以string类型返回。但是Ang2Str方法返回的是含有特殊符号的度分秒,只能以string类型返回,在调用两种方法时,要时刻注意输入参数的类型以及返回值的类型。

如果是void方法,或者需要返回多个参数值的有返回值的方法,则可以通过ref关键字来返回值。

ref并不是一种值类型,它对应参数的值类型与调用时传入的参数的值类型相同。这里以导线网近似平差为例说明:

/// <summary>
/// 导线近似平差计算,当返回值为1时,说明所给数据超限
/// <param name="a">导线类型(闭合或附合)</param>
/// <param name="b">选择观测左角或观测右角</param>
/// <param name="XY">点坐标(包括已知点及待求点)</param>
/// <param name="angle">观测角度</param>
/// <param name="distance">观测距离</param>
public int TraverseNetworkAdjust(int a, int b, ref double[,] XY, double[] angle, double[] distance)
{
    if (a == 2) //闭合路线
    {
        AngCal.AngCal angcal = new AngCal.AngCal();
        double Az = CoCal.CoCal.GetAzi(XY[0, 0], XY[0, 1], XY[1, 0], XY[1, 1]); //计算初始坐标方位角
        int n1 = XY.GetLength(0); //总点数
        int n2 = angle.Length; //观测角度数
        double sum = 0;
        // 求角度和
        for (int i = 0; i < n2; i++)
        {
            angle[i] = angcal.Ang2Dec(angle[i]);
            sum += angle[i];
        }
        double closure = Math.Floor(sum);
        closure = sum - closure; ;
        // 检查角度闭合差
        if (closure < ((40 * Math.Sqrt(n1 - 1)) / 3600))
        {
            // 分配角度闭合差
            if (closure < 0.5)
            {
                double dangle = -1 * closure / (n1 - 1);
                for (int i = 0; i < n2; i++)
                {
                    angle[i] = angle[i] + dangle;
                }
            }
            else
            {
                double dangle = closure / (n1 - 1);
                for (int i = 0; i < n2; i++)
                {
                    angle[i] = angle[i] + dangle;
                }
            }
            // 计算方位角
            double[] az = new double[n2];
            az[0] = Az * 180 / Math.PI;
            if (b == 1) //左角
            {
                for (int i = 1; i < n2; i++)
                {
                        az[i] = az[i - 1] + angle[i - 1] - 180;
                        if (az[i] < 0) { az[i] = az[i] + 360; }
                        if (az[i] > 360) { az[i] = az[i] - 360; }
                }
            }
            else //右角
            {
                for (int i = 1; i < n2; i++)
                {
                    az[i] = az[i - 1] - angle[i - 1] + 180;
                    if (az[i] < 0) { az[i] = az[i] + 360; }
                    if (az[i] > 360) { az[i] = az[i] - 360; }
                }
            }
            // 计算坐标增量
            double[] dx = new double[n2 - 1];
            double[] dy = new double[n2 - 1];
            double flag1 = 0;
            double flag2 = 0;
            double s = 0;
            double K = 5000;
            for (int i = 0; i < (n2 - 1); i++)
            {
                az[i + 1] = az[i + 1] * Math.PI / 180;
                dx[i] = distance[i] * Math.Cos(az[i + 1]);
                dy[i] = distance[i] * Math.Sin(az[i + 1]);
                flag1 += dx[i];
                flag2 += dy[i];
                s += distance[i];
            }
            az[n2 - 1] = az[n2 - 1] * Math.PI / 180;
            // 检查坐标闭合差
            if (s / Math.Sqrt(flag1 * flag1 + flag2 * flag2) > K)
            {
                double dxx = -1.0 * flag1 / (n2 - 1);
                double dyy = -1.0 * flag2 / (n2 - 1);
                for (int i = 0; i < (n2 - 1); i++)
                {
                    dx[i] = dx[i] + dxx;
                    dy[i] = dy[i] + dyy;
                }
                // 计算坐标xy
                for (int i = 2; i < n1; i++)
                {
                    XY[i, 0] = XY[i - 1, 0] + dx[i - 2];
                    XY[i, 1] = XY[i - 1, 1] + dy[i - 2];
                }
                return 0;
                }
                else
                {
                    return 1;//即超限
                }
            }
            else
            {
                return 1;//即超限
            }
        }
        else
        {
            AngCal.AngCal angcal = new AngCal.AngCal();
            double Az1 = CoCal.CoCal.GetAzi(XY[0, 0], XY[0, 1], XY[1, 0], XY[1, 1]); //起始端初始坐标方位角
            double Az2 = CoCal.CoCal.GetAzi(XY[2, 0], XY[2, 1], XY[3, 0], XY[3, 1]); //结束端初始坐标方位角
            Az1 = Az1 * 180 / Math.PI;
            Az2 = Az2 * 180 / Math.PI;
            int n1 = XY.GetLength(0); //总点数
            int n2 = angle.Length; //观测角度数
            double sum = 0;
            // 计算观测角度总和
            for (int i = 0; i < n2; i++)
            {
                angle[i] = angcal.Ang2Dec(angle[i]);
                sum += angle[i];
            }
            // 计算闭合差
            double closure = Az1 - sum + n2 * 180 - Az2;
            // 检查角度闭合差
            if (closure < ((40 * Math.Sqrt(n1 - 1)) / 3600))
            {
                //分配角度闭合差
                if (closure < 0.5)
                {
                    double dangle = -1 * closure / (n1 - 1);
                    for (int i = 0; i < n2; i++)
                    {
                        angle[i] = angle[i] + dangle;
                    }
                }
                else
                {
                    double dangle = closure / (n1 - 1);
                    for (int i = 0; i < n2; i++)
                    {
                        angle[i] = angle[i] + dangle;
                    }
                }
                // 计算方位角
                double[] az = new double[n2 + 1];
                az[0] = Az1;
                if (b == 1) //左角
                {
                    for (int i = 1; i < n2 + 1; i++)
                    {
                        az[i] = az[i - 1] + angle[i - 1] - 180;
                        if (az[i] < 0) { az[i] = az[i] + 360; }
                        if (az[i] > 360) { az[i] = az[i] - 360; }
                    }
                }
                else //右角
                {
                    for (int i = 1; i < n2 + 1; i++)
                    {
                        az[i] = az[i - 1] - angle[i - 1] + 180;
                        if (az[i] < 0) { az[i] = az[i] + 360; }
                        if (az[i] > 360) { az[i] = az[i] - 360; }
                    }
                }
                //计算坐标增量
                double[] dx = new double[n2 - 1];
                double[] dy = new double[n2 - 1];
                double flag1 = 0;
                double flag2 = 0;
                double s = 0;
                double K = 5000;
                for (int i = 0; i < (n2 - 1); i++)
                {
                    az[i + 1] = az[i + 1] * Math.PI / 180;
                    dx[i] = distance[i] * Math.Cos(az[i + 1]);
                    dy[i] = distance[i] * Math.Sin(az[i + 1]);
                    flag1 += dx[i];
                    flag2 += dy[i];
                    s += distance[i];
                }
                az[n2 - 1] = az[n2 - 1] * Math.PI / 180;
                az[n2] = az[n2] * Math.PI / 180;
                flag1 = flag1 - (XY[2, 0] - XY[1, 0]); //dx
                flag2 = flag2 - (XY[2, 1] - XY[1, 1]); //dy
                //检查坐标闭合差
                if (s / Math.Sqrt(flag1 * flag1 + flag2 * flag2) > K)
                {
                    double dxx = -1.0 * flag1 / (n2 - 1);
                    double dyy = -1.0 * flag2 / (n2 - 1);
                    for (int i = 0; i < (n2 - 1); i++)
                    {
                        dx[i] = dx[i] + dxx;
                        dy[i] = dy[i] + dyy;
                    }
                    // 计算坐标xy
                    for (int i = 4; i < n1; i++)
                    {
                        XY[i, 0] = XY[i - 1, 0] + dx[i - 4];
                        XY[i, 1] = XY[i - 1, 1] + dy[i - 4];
                    }
                    return 0;
                }
                else
                {
                    return 1;
                }
            }
            else
            {
                return 1;
            }
        }
    }
}

在调用时,ref的值从外部获取,并在方法代码段运行完毕后将值返回给对应的参数:

private void 平差计算_Click(object sender, EventArgs e)
{
    double[,] XY = new double[x + 2, 2];
    int q = tr.TraverseNetworkAdjust(2, b, ref XY, angle, distance);
}

这样既得到了返回值q,也得到了返回值XY。

注意此处仅仅是举例说明,实际调用是应关注实际问题的需求。

本期到此为止。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值