2019-01-08 00:27:19 weixin_34375233 阅读数 62
  • 【在线峰会】物联网全栈开发之道视频教程

    智能化的物联网时代,开发者该如何顺势而为?本次峰会从易于上手、高效的“物联网全栈开发”着手,集结一线讲师,基于 JavaScript、Python,详勘物联网技术架构、技术栈、应用开发平台、安全等实战经验,希望通过一天的时间,帮助开发者掌握物联网全栈开发之道。具体内容包括:现代物联网应用系统架构与技术栈、lOT应用开发,物联网开发平台的选择、基于JavaScript、Python等编程语言进行物联网开发,物联网安全防守之道等。

    1744 人正在学习 去看看 CSDN讲师
2019-09-11 18:04:07 qq_44658169 阅读数 101
  • 【在线峰会】物联网全栈开发之道视频教程

    智能化的物联网时代,开发者该如何顺势而为?本次峰会从易于上手、高效的“物联网全栈开发”着手,集结一线讲师,基于 JavaScript、Python,详勘物联网技术架构、技术栈、应用开发平台、安全等实战经验,希望通过一天的时间,帮助开发者掌握物联网全栈开发之道。具体内容包括:现代物联网应用系统架构与技术栈、lOT应用开发,物联网开发平台的选择、基于JavaScript、Python等编程语言进行物联网开发,物联网安全防守之道等。

    1744 人正在学习 去看看 CSDN讲师

使用C#开发数据库应用数据系统

技术内容

1.1 第一个 Windows 程序

1.1.1 创建 Windows 程序

1.1.2 认识 Windows 程序

1.1.3 基本控件

——————————————————————————————

第一章——初始Windows程序

1.1第一个Windows程序

在.NET出现之前,开发带有图形界面的Windows程序,编码量是很大的。有了.NET Framework之后,这项工作就变得非常简单了。.NET Framework提供了Windows窗体以及窗体内常用的“控件”给开发人员使用,使开发人员可以在编写极少量代码的情况下开发出功能丰富的应用程序。

1.1.1创建Windows程序

创建一个Windows应用程序,一共包括四步。
(1)打开Visual Studio 开发工具。
(2)选择“文件”→“新建”→“项目”命令。
(3)项目类型选择“Visual C#”。
(4)模板选择“Windows窗体应用程序”,如图1.1所示。


图1.1 选择“Windows窗体应用程序”
——————————————————————————————

选好位置后,为项目命名后,单机“确认”按钮,将显示如图1.2所示的Visual Studio界面。

在这里插入图片描述
图1.2 Windows应用程序的Visual Studio界面
——————————————————————————————

这时的窗体组成和控制台应用程序的窗口组成有些不同。
  • 左侧出现了一个“工具箱”窗口,里面包含了很多控件,可以直接把它们拖到窗体上。
  • 中间的部分是窗体设计器,可以放置从工具箱中拖出的控件。
  • 右下方的“属性”窗口,是用来设置窗体或控件的各种属性的,直接按F5运行,将会出现如图1.3所示的窗体

在这里插入图片描述
图1.3 第一个窗体
——————————————————————————————

不需要一行代码,就能够运行出一个窗体,这都得益于Visula Studio和.NET Framework的支持。当然这个窗体非常简单,不能实现什么具体的功能。但通过这个例子,希望同学们能熟悉创建Windows程序的步骤。

1.1.2 认识Windows程序

Windows窗体应用程序与控制台应用程序有很大区别,打开Windows窗体应用程序的解决方案资源管理器,如图1.4所示。

在这里插入图片描述
图1.4 解决方案资源管理器
——————————————————————————————

  • Form1.cs:窗体文件,程序员对窗体编写的代码一般都放在这个文件中
  • Form.Designer.cs:窗体设计文件,其中的代码是由Visual Studio自动生成的,一般不需要修改。
  • Form1.resx:资源文件,用来配置当前窗体所使用的的字符串,图片等资源等
  • Program.cs:主程序文件,其中包含程序入口的Main()方法。双击打开Program.cs文件,可以看到Windows程序的Main()方法。如示例1所示。

示例一

namespace Myschool1
{
static class Program
{
///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
——————————————————————————————

Main()方法中的代码也是Visual Studio 自动生成的,一般情况下只会修改第三句代码,“Application.Run(new Form1());” 的含义是应用程序启动时运行的窗体。

在 Visual Studio 中,Winforms 应用程序的窗体文件有两种编辑视图,分别是窗体设计器(图1.5)和代码编辑器(图1.6)。

在这里插入图片描述
图 1.5 窗体设计器
——————————————————————————————
在这里插入图片描述
图1.6 代码编辑器
——————————————————————————————

窗体设计器是进行窗体界面设计,拖放控件,设置窗体及控件属性时使用的,不需要编写代码,用鼠标就可以进行可视化操作,如 图 1.5 所示。

代码编辑器是手动编写代码时用到的,在 图 1.6 中可以看到,Visual Studio 已经自动生成了一些代码,我们重点关注已下代码。

using System;

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Myschool1
{
static class Program
{
///
/// 应用程序的主入口点。
///
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

这里面包含两个新内容:partial和Form。

1.partial

在图1.6中,窗体类的前面多了一个partial。partial是“部分的”意思。在C#中,为了方便对代码的管理和编辑,可以使用 partial 关键字将同一个类的代码分开放在多个文件夹中。每个文件都是类的一部分代码,叫做分布类。编译代码时,编辑器再将各个分布类的代码的代码合并到一起处理。

利用 Visual Studio 创建的窗体都是分布类。例如,在图1.4中,Form1这个类的代码就分布在两个文件中:From1.cs和Form1.Designer.cs。我们编写的代码在From1.cs中,而Form1.Designer.cs中的代码中的代码都是 Visual Studio 自动生成的。它负责定义窗体以及控件的位置,大小等,我们一般不直接操作这个文件。Form1.cs和Form1.Designer.cs的代码具有相同的命名空间和相同的类名,并且都在类名前面增加了 partial 关键字。在编译时, Visual Studio 会识别出来,并把它们合并成一个类来进行处理。这样做的好处是分离关注点,即使使用分布类把程序员不需要关心的那些自动生成的代码剥离出去,可以使程序员的关注点更集中,使代码看起来更加简洁。

2. Form

Form是 .NET Framework 定义好的一个最基本的窗体类,具有窗体的一些最基本的属性和方法。冒号表示继承,我们创建的窗体都继承自 Form 类,那么它就具有了 Form 类中定义的属性和方法。窗体的主要属性和方法见表1.1。

表1.1 窗体的主要属性和方法

属性 方法
BackColor 窗体的背景色
BackGroundImage 窗体的背景图像
FormBorderStyle 窗体显示的边框样式,有七个可选的值,默认为 Sizable
MaximizeBox 确定窗体标题栏的右上角是否有最大化框,默认为 True
ShowInTaskbar 确认窗体是否出现在 Windows 任务栏中,默认为 True
StartPosition 确认窗体第一次出现时的位置
Text 窗体标题栏中显示的文本
TopMost 指示窗体是否始终显示在此属性未设置为 True 的所有窗体之上,默认为 False
WindowState 确认窗体的初始可视状态,包括 Normal(普通),Maximized(最大化),Minimized(最小化),默认为 Normal
方法 说明
Close() 关闭窗体
Show() 显示窗体
ShowDialog() 模式化显示窗体
Hide() 隐藏窗体窗体

这些属性都可以在视图设计中修改,每修改一个属性, VisualStudio 就会在窗体的 Designer 文件中自动生成相应的代码。打开窗体设计器,修改示例一种窗体的部分属性,制作 MySchool 项目的登录窗体,修改后运行的效果如图 1.7 所示。

在这里插入图片描述
图 1.7 登录窗体
——————————————————————————————

打开窗体的 Designer 文件,查看 VisualStudio 自动生成的代码,如示例2所示。

示例二

namespace Myschool1

{
partial class Form1
{
///
/// 必需的设计器变量。
///
private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows 窗体设计器生成的代码

    /// <summary>
    /// 设计器支持所需的方法 - 不要
    /// 使用代码编辑器修改此方法的内容。
    /// </summary>
    private void InitializeComponent()
    {
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
        this.SuspendLayout();
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.BackgroundImage = global::Myschool1.Properties.Resources.login_bj;
        this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
        this.ClientSize = new System.Drawing.Size(484, 261);
        this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
        this.Name = "Form1";
        this.Text = "Form1";
        this.Load += new System.EventHandler(this.Form1_Load);
        this.ResumeLayout(false);

    }

    #endregion
}

}

示例二 中的部分代码就是在设计器中设置窗体属性时自动生成的代码。大家只需要读懂这些代码即可,不需要做任何修改。

注意:

FormBorderStyle 用于设置窗体的边框样式,在设计窗体时要根据实际需要,选择合适的属性值。如果不希望在窗体运行后,用户通过鼠标拖拽改变窗体大小,则在设计时需要将窗体的 FormBorderStyle 属性值设为 FixedSingle。

1.1.3基本控件

在 HTML 课程中,我们学过表单元素,如< input > ,< select > 等。这些元素能够显示信息,获取用户的输入。在 Windows程序中,.NET 也提供了很多窗体控件用来设置窗体。下面介绍几个基本控件,将用它们设计 MySchool 的登录窗体。如图 1.8 所示。

在这里插入图片描述
图 1.8 登录界面
——————————————————————————————

标签(Label,如图1.9所示):用于显示用户不能编辑的文本后图像。常使用它对窗体上的其它各种控件进行标注或说明。在图1.8中,“用户名”,“密码”,“登录类型”,等都是标签。标签的主要属性见表1-2.

表1-2 标签的主要属性

属性 说明
Image 在标签上显示的图像
Text 在标签上显示的文本

在这里插入图片描述
图1.9 标签控件
——————————————————————————————

文本框(TextBox,如图1.10所示):用于获取用户输入的信息或向用户显示的文本。在图1.8中,“用户名:”,“密码:”标签后面的空白框就是文本框。文本框的主要属性见表1-3.

表1-3 文本框的主要属性

属性 说明
MaxLength 指定可以在文本框中输入的最大字符数
Multiline 表示是否可在文本框中输入多行文本
PasswordChar 指示在作为密码框时,文本框中显示的字符,而不是实际输入的文本
ReadOnly 指定是否允许编辑文本框中的文本
Text 与文本框关联的文本

在这里插入图片描述
图 1.10 文本框控件
——————————————————————————————

组合框(ComboBox,如图1.11所示):它结合了文本框和列表框的特点,允许用户在组合框内输入文本或从列表中进行选择。在图1.8中,“登录类型”:标签后的控件就是组合框。组合框的属性和事件见表1-4.

表1.4 组合框的主要属性和事件

属性 说明
Items 组合框中的项
DropDownStyle 定义组合框的风格,指示是否显示列表框部分,是否允许用户编辑文本框部分
Text 与组合框关联的文本
SelectedInedx 当前选定项目的索引号,列表框中的每个项都有一个索引号,从0开始
SelectdeItem 获取当前选定的项
事件 说明
Click 单机控件时发生
SelectedIndexChanged 在SelectedIndex属性修改后发生

在这里插入图片描述
图 1.11 组合框控件
——————————————————————————————

按钮(Button,如图1.12所示):允许用户通过单机来执行操作。在图1.8中,“登录”,“取消”就是按钮。按钮的主要属性和事件见表1-5.

表1-5 按钮的主要属性和事件

属性 说明
Enable 布尔值,表示控件是否可用。True 表示可用,False 表示不可用。如果控件不可用,运行后显示为灰色
Text 按钮上显示的文本
TextAlign 按钮上文本的对其方式
事件 说明
Click 单机控件时发生

在这里插入图片描述
图 1.12 按钮控件
——————————————————————————————

控件的属性中有一些是控件的通用的属性,如Text,Name,Enable 等。这些属性在不同的控件中表示的含义是一样的。

规范:

控件命名要遵循一定的规范,比较通用的规范为控件类名的缩写+有含义的英文单词。例如,Button 控件的缩写是btn,那么“登录”按钮就可以命名为btnLogin。关于控件类名缩写的对照表情请参照附录。

现在利用上面介绍的四个控件设计登录窗体。从工具箱中拖出三个Lable 控件,两个TextBox控件,一个ComBoBox控件,两个Button控件到窗体上,并设置相应的属性,实现图1.8所示的效果。在设置属性时,Visual Studio 自动生成的关键代码如示例三所示。通过 TextBox的BoderStyle 属性可以设置文本框的边框样式:通过Button的BackgroundImang属性可以设置按钮的背景。

示例三

namespace Myschool1

{
partial class Form1
{
///
/// 必需的设计器变量。
///
private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// 清理所有正在使用的资源。
    /// </summary>
    /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows 窗体设计器生成的代码

    /// <summary>
    /// 设计器支持所需的方法 - 不要
    /// 使用代码编辑器修改此方法的内容。
    /// </summary>
    private void InitializeComponent()
    {
        System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
        this.label1 = new System.Windows.Forms.Label();
        this.label2 = new System.Windows.Forms.Label();
        this.label3 = new System.Windows.Forms.Label();
        this.textBox1 = new System.Windows.Forms.TextBox();
        this.textBox2 = new System.Windows.Forms.TextBox();
        this.comboBox1 = new System.Windows.Forms.ComboBox();
        this.button1 = new System.Windows.Forms.Button();
        this.button2 = new System.Windows.Forms.Button();
        this.SuspendLayout();
        // 
        // label1
        // 
        this.label1.AutoSize = true;
        this.label1.Location = new System.Drawing.Point(179, 134);
        this.label1.Name = "label1";
        this.label1.Size = new System.Drawing.Size(53, 12);
        this.label1.TabIndex = 0;
        this.label1.Text = "用户名:";
        // 
        // label2
        // 
        this.label2.AutoSize = true;
        this.label2.Location = new System.Drawing.Point(180, 161);
        this.label2.Name = "label2";
        this.label2.Size = new System.Drawing.Size(41, 12);
        this.label2.TabIndex = 0;
        this.label2.Text = "密码:";
        // 
        // label3
        // 
        this.label3.AutoSize = true;
        this.label3.Location = new System.Drawing.Point(180, 186);
        this.label3.Name = "label3";
        this.label3.Size = new System.Drawing.Size(65, 12);
        this.label3.TabIndex = 0;
        this.label3.Text = "登录类型:";
        // 
        // textBox1
        // 
        this.textBox1.Location = new System.Drawing.Point(238, 125);
        this.textBox1.Name = "textBox1";
        this.textBox1.Size = new System.Drawing.Size(122, 21);
        this.textBox1.TabIndex = 1;
        // 
        // textBox2
        // 
        this.textBox2.Location = new System.Drawing.Point(238, 152);
        this.textBox2.Name = "textBox2";
        this.textBox2.Size = new System.Drawing.Size(122, 21);
        this.textBox2.TabIndex = 1;
        // 
        // comboBox1
        // 
        this.comboBox1.FormattingEnabled = true;
        this.comboBox1.Location = new System.Drawing.Point(239, 178);
        this.comboBox1.Name = "comboBox1";
        this.comboBox1.Size = new System.Drawing.Size(121, 20);
        this.comboBox1.TabIndex = 2;
        // 
        // button1
        // 
        this.button1.Location = new System.Drawing.Point(193, 204);
        this.button1.Name = "button1";
        this.button1.Size = new System.Drawing.Size(75, 23);
        this.button1.TabIndex = 3;
        this.button1.Text = "登录";
        this.button1.UseVisualStyleBackColor = true;
        // 
        // button2
        // 
        this.button2.Location = new System.Drawing.Point(285, 204);
        this.button2.Name = "button2";
        this.button2.Size = new System.Drawing.Size(75, 23);
        this.button2.TabIndex = 3;
        this.button2.Text = "取消";
        this.button2.UseVisualStyleBackColor = true;
        // 
        // Form1
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.BackgroundImage = global::Myschool1.Properties.Resources.login_bj;
        this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
        this.ClientSize = new System.Drawing.Size(484, 261);
        this.Controls.Add(this.button2);
        this.Controls.Add(this.button1);
        this.Controls.Add(this.comboBox1);
        this.Controls.Add(this.textBox2);
        this.Controls.Add(this.textBox1);
        this.Controls.Add(this.label3);
        this.Controls.Add(this.label2);
        this.Controls.Add(this.label1);
        this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
        this.Name = "Form1";
        this.Text = "Form1";
        this.Load += new System.EventHandler(this.Form1_Load);
        this.ResumeLayout(false);
        this.PerformLayout();

    }

    #endregion

    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Label label2;
    private System.Windows.Forms.Label label3;
    private System.Windows.Forms.TextBox textBox1;
    private System.Windows.Forms.TextBox textBox2;
    private System.Windows.Forms.ComboBox comboBox1;
    private System.Windows.Forms.Button button1;
    private System.Windows.Forms.Button button2;
}

}

从 示例三 中可以看到,项窗体放置一个控件,Visual Studio 生成的代码用 new 关键字创建该控件对象。而在窗体设计器的“属性”窗口中设置的属性,都有对应的自动生成代码。注意最后几行的this.Controls.Add()代码,this代表当前的窗体对象,这句代码的含义是将控件对象添加到窗体的控件集合中。这样控件就能在窗体上显示。

本章一共有5个小结——现在学习的是1.1——第一个 Windows 程序

————郑州北大青鸟一名学生——不喜勿喷。我会一直更新的。加油!!!

右下角 放大150观看最佳!

在这里插入图片描述

2019-12-22 15:40:47 gd1984812 阅读数 38
  • 【在线峰会】物联网全栈开发之道视频教程

    智能化的物联网时代,开发者该如何顺势而为?本次峰会从易于上手、高效的“物联网全栈开发”着手,集结一线讲师,基于 JavaScript、Python,详勘物联网技术架构、技术栈、应用开发平台、安全等实战经验,希望通过一天的时间,帮助开发者掌握物联网全栈开发之道。具体内容包括:现代物联网应用系统架构与技术栈、lOT应用开发,物联网开发平台的选择、基于JavaScript、Python等编程语言进行物联网开发,物联网安全防守之道等。

    1744 人正在学习 去看看 CSDN讲师

GPS定位发展很快,随着物联网的推广,衍生出很多GPS相关的应用万变不离其宗,主要应用的技术是GPS信号的采集、解析、将GPS信号通过4G或GPRS等传至服务器,客户端与服务器通信,获取设备位置信息,实现定位轨迹跟踪等。大概都包含这三大部分,设备、服务器后台、客户端。

设备如下

C#编写服务器后台

C#客户端

下面逐个介绍

设备采用STM32串口接收GPS模块输出的位置信息,解析出经纬度,通过AT指令控制GPRS模块与服务器通信。硬件电路如下

单片机解析GPS模块的位置信息,一般解析GPRMC这一条就可以,解析的方法很多,可以用找字头,数逗号的方式例如下面的信息。

$GPRMC,092927.000,A,2235.9058,N,11400.0518,E,0.000,74.11,151216,,D*49 
$GPVTG,74.11,T,,M,0.000,N,0.000,K,D*0B 
$GPGGA,092927.000,2235.9058,N,11400.0518,E,2,9,1.03,53.1,M,-2.4,M,0.0,0*6B 
$GPGSA,A,3,29,18,12,25,10,193,32,14,31,,,,1.34,1.03,0.85*31 
$GPGSV,3,1,12,10,77,192,17,25,59,077,42,32,51,359,39,193,49,157,36*48 
$GPGSV,3,2,12,31,47,274,25,50,46,122,37,18,45,158,37,14,36,326,18*70 
$GPGSV,3,3,12,12,24,045,45,26,17,200,18,29,07,128,38,21,02,174,*79
 

char *gpsdata;
	int i,count;
	if(USART_GetITStatus(USART2,USART_IT_IDLE) == SET)     
	{                                                 
		USART2->SR;        
		USART2->DR;
		USART_ClearITPendingBit(USART2,USART_IT_IDLE); 
		DMA_Cmd(DMA1_Channel6,DISABLE);                      //??DMA        
		U2_Rx_Counter = 1024 - DMA_GetCurrDataCounter(DMA1_Channel6);  //??????????          		
		gpsdata = strstr(U2_RX_data,"$GNRMC");
		if(gpsdata)	
		{ 
			for(i=0;i<strlen(gpsdata);i++)
			{
				if(gpsdata[i]==',')
				{
					count++;
					if(count==2)
					{
							
							if(gpsdata[i+1]=='A')
							{
								gps_flag=1;
								
							}
							else
							{
								gps_n=0;
								gps_e=0;
								break;
							} 
					}	
					if(gps_flag==1)
					{
						if((count==3)&&(gpsdata[i+1]!=','))
						{
							gps_n=((gpsdata[i+1]-0x30)*100000+(gpsdata[i+2]-0x30)*10000+((gpsdata[i+3]-0x30)*100000+(gpsdata[i+4]-0x30)*10000+(gpsdata[i+6]-0x30)*1000+(gpsdata[i+7]-0x30)*100+(gpsdata[i+8]-0x30)*10+(gpsdata[i+9]-0x30))/60);
						}
						if((count==5)&&(gpsdata[i+1]!=','))
						{
							gps_e=((gpsdata[i+1]-0x30)*1000000+(gpsdata[i+2]-0x30)*100000+(gpsdata[i+3]-0x30)*10000+((gpsdata[i+4]-0x30)*100000+(gpsdata[i+5]-0x30)*10000+(gpsdata[i+7]-0x30)*1000+(gpsdata[i+8]-0x30)*100+(gpsdata[i+9]-0x30)*10+(gpsdata[i+10]-0x30))/60);			
						}		
						if(count>=13)
						{
							count=0;
							gps_flag=0;
							break;
						}
					}	
				}	
			}
		}
		memset(U2_RX_data,0, 1024);		
		DMA1_Channel6->CNDTR = 1024;                            //??????????           
		DMA_Cmd(DMA1_Channel6,ENABLE);                       //??DMA             
	}

单片机与服务器通过AT指令控制GPRS模块与服务器通信,AT指令是比较难的,开发过的会有感受,AT指令返回的状态比较多,并不是返回一种或两种结果。不但要按照正常流程一步一步发送AT指令,还要有错误返回处理。AT指令挺复杂的,特别适合用状态机处理这些流程。

switch (M26_info.state)             
	{
		case GPRS_state_Poweroff :
				if(AT_Delay_Timer>5)
				{
					GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_SET);
					GPIO_SetBits(GPIOA,GPIO_Pin_1);
					GPIO_ResetBits(GPIOA, GPIO_Pin_7);
					GPIO_ResetBits(GPIOA, GPIO_Pin_4);             // Sleep
				}
				if(AT_Delay_Timer>25)
				{
					GPIO_ResetBits(GPIOA,GPIO_Pin_1);
					GPIO_SetBits(GPIOA, GPIO_Pin_7);
				}				
				if(AT_Delay_Timer>45)
				{
					GPIO_WriteBit(GPIOC, GPIO_Pin_14, Bit_RESET);
					M26_info.state=GPRS_state_AT;
					AT_Timeslimite=0;
					AT_Delay_Timer=0;
					AT_overtime=0;
					ZC_DATA_flog=1;
				}		
			break; 
		case GPRS_state_AT :
				M26_ATTR(5,30,50,"AT+IPR=115200&W\r\n","OK","","","","",GPRS_state_CREG,GPRS_state_AT);
			break; 
		case GPRS_state_CREG :
				M26_ATTR(5,30,100,"AT+CREG?\r\n","+CREG: 0,1","+CREG: 0,5","+CREG: 0,2","+CREG: 0,3","+CREG: 0,4",GPRS_state_CSQ,GPRS_state_CREG);
			break;
		case GPRS_state_CSQ :
				M26_ATTR(2,30,20,"AT+CSQ\r\n","+CSQ:","","","","",GPRS_state_QIDNSIP,GPRS_state_CSQ);
		case GPRS_state_QIDNSIP:
				M26_ATTR(2,30,5,"AT+QIFGCNT=0\r\n","OK","","","","",GPRS_state_QIDEACT,GPRS_state_Poweroff);
			break;
		case GPRS_state_QIDEACT:
				M26_ATTR(2,2,50,"AT+QICSGP=1,\"CMMTM\"\r\n","OK","","ERROR","","",GPRS_state_QIREGAPP,GPRS_state_Poweroff);
				break;
		case GPRS_state_QIREGAPP:
				M26_ATTR(2,2,50,"AT+QIREGAPP\r\n","OK","","ERROR","","",GPRS_state_QIACT,GPRS_state_Poweroff);
			break;
		case GPRS_state_QIACT:
				M26_ATTR(10,2,300,"AT+QIACT\r\n","OK","","ERROR","","",GPRS_state_QIOPEN,GPRS_state_Poweroff);
			break;
		case GPRS_state_QIOPEN:
				M26_ATTR(20,10,50,"AT+QIOPEN=\"TCP\",\"122.51.33.246\",\"8888\"\r\n","CONNECT OK","ALREADY CONNECT","ERROR","CONNECT FAIL","",GPRS_state_QISEND,GPRS_state_QIACT);
			break;
		case GPRS_state_QISTAT:
				M26_ATTR(10,10,500,"AT+QISTAT\r\n","STATE: CONNECT OK","","STATE: IP INITIAL","","",GPRS_state_QISEND,GPRS_state_QIOPEN);
			break;
		case GPRS_state_QISEND:
				////GPRS_DATA_flog=1;
				M26_ATTR(50,20,100,"AT+QISEND=27\r\n",">",">","ERROR","ERROR","ERROR",GPRS_state_QISENDDATA,GPRS_state_QISENDDATA);
			break;
		case GPRS_state_QISENDDATA:
				M26_senddata(10,10,100,"12345678","SEND OK","","ERROR","ERROR","ERROR",GPRS_state_QISEND,GPRS_state_Poweroff);
			break;
		
		default:  ; 
	}

服务器后台

用C#编写服务器后台程序,他负责接收所有设备发来数据,把与客户端有关的设备数据转发给客户端。这样局域网里的客户端可以通过网关获取服务器的数据。服务器程序用到多线程技术,可以同时处理多个设备发来的数据。用到了Dictionary数据类型,实现设备ID与socket对应,关键代码如下

private void ReceiveClient(object obj)
        {
            Socket _ClientSocket = (Socket)obj;
            while (true)
            {
                try
                {
                    byte[] result = new byte[1024];
                    int receiveLength = _ClientSocket.Receive(result);             
                    string clientMessage = Encoding.UTF8.GetString(result, 0, receiveLength);
                    string Destination_Address;
                    string Data_Rcve;
                    if (receiveLength == 0)
                    {
                        ClientSocketDictionary.Remove(_ClientSocket);
                        _ClientSocket.Shutdown(SocketShutdown.Both);
                        _ClientSocket.Close();
                        SetText2box();
                        break;
                    }
                    else
                    {
                        if ((result[0] == '$') && (result[1] == '2'))//发送数据 目的地址
                        {
                            Destination_Address = clientMessage.Substring(2, 10);
                            Data_Rcve = clientMessage.Substring(12, clientMessage.Length-12);
                            temp = DateTime.Now.ToString()+ " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve;
                            SetTextbox();
                            SendMessage(clientMessage);
                        }
                        if ((result[0] == '$') && (result[1] == '1'))//注册ID  源地址
                        {
                            if (!ClientSocketDictionary.ContainsKey(_ClientSocket))
                            {
                                ClientSocketDictionary.Add(_ClientSocket, clientMessage.Substring(2, 10));
                                SetText2box();
                            }
                            else
                            {
                                ClientSocketDictionary.Remove(_ClientSocket);
                                ClientSocketDictionary.Add(_ClientSocket, clientMessage.Substring(2, 10));
                                SetText2box();
                            }                                        
                        }
                    }
                                                       
                }
                catch (Exception e)
                {
                    ClientSocketDictionary.Remove(_ClientSocket);
                    _ClientSocket.Shutdown(SocketShutdown.Both);
                    _ClientSocket.Close();
                    SetText2box();
                    SetText3box(e);

                    break;
                }
            }
        }
public void SendMessage(string msg)
        {
            if (msg == string.Empty || this.ClientSocketDictionary.Count <= 0) return;
            string Destination_Address = msg.Substring(2, 10);
            string Data_Rcve = msg.Substring(12, msg.Length-12);
            msg = "$3" + Destination_Address + Data_Rcve;

            
            try
            {
                foreach (KeyValuePair<Socket, string> kvp in ClientSocketDictionary)
                {
                   if(kvp.Value.Substring(0,10)== Destination_Address)
                   {
                       kvp.Key.Send(Encoding.UTF8.GetBytes(msg));
                   }              
                }
            }
            catch (Exception e)
            {
                SetText3box(e);
            }
        }      

客户端

C#编写客户端程序,调用百度地图API,实现地图打标,绘制轨迹。客户端工作流程是这样的,首先向服务器发送注册自身ID,然后向服务器获取相关设备ID的数据,解析数据,调用百度地图API实现打标定位等。关键代码如下

 private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                clientScoket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                clientScoket.Connect(new IPEndPoint(IPAddress.Parse(textBox1.Text.ToString()), 8888));
                t = new Thread(ReceiveMessage);//开启线程执行循环接收消息
                t.IsBackground=true;
                t.Start();
                button1.Text = "已连接服务器";
                button1.Enabled = false;
            }
            catch (Exception ex)
            {
                SetText3box(ex);
                button1.Text = "无法连接服务器";
                button1.Enabled = true;
            }
                   
        }
       
        public delegate void CallSetTextbox(string ms);
        void ReceiveMessage()//接收消息
        {
            
            string Destination_Address;
            string Data_Rcve;
            send_flog = 1;
            while (true)
            {
                if (clientScoket.Connected == true)
                {
                    
                    
                        if (send_flog == 1)
                        {
                            send_flog = 0;
                            message = "$1" + textBox4.Text;
                            SendMessage(message);
                        }
                        int length = 0;

                        try
                        {
                            length = clientScoket.Receive(data);
                         }
                        catch (Exception e)
                        {
                            SetText3box(e);
                       
                        break;

                        }

                        if (length != 0)
                        {
                            message = Encoding.UTF8.GetString(data, 0, length);
                            if ((data[0] == '$') && (data[1] == '3'))//配置ID
                            {
                                Destination_Address = message.Substring(2, 10);
                                Data_Rcve = message.Substring(12, message.Length - 12);

                                Longitude = Data_Rcve.Substring(0, 8);
                                Latitude = Data_Rcve.Substring(8, 7);
                                if ((Longitude != "000.0000") && (Latitude != "00.0000"))
                                {
                                    SetTextbox(DateTime.Now.ToString() + " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve);
                                }
                                SetText2box(DateTime.Now.ToString() + " Dest is : " + Destination_Address + "  Data is : " + Data_Rcve);

                        }
                        }
                 
                    
                }
                else
                {
                    break;
                }
            }

 

2017-06-26 18:00:02 tangxiaoyin 阅读数 22180
  • 【在线峰会】物联网全栈开发之道视频教程

    智能化的物联网时代,开发者该如何顺势而为?本次峰会从易于上手、高效的“物联网全栈开发”着手,集结一线讲师,基于 JavaScript、Python,详勘物联网技术架构、技术栈、应用开发平台、安全等实战经验,希望通过一天的时间,帮助开发者掌握物联网全栈开发之道。具体内容包括:现代物联网应用系统架构与技术栈、lOT应用开发,物联网开发平台的选择、基于JavaScript、Python等编程语言进行物联网开发,物联网安全防守之道等。

    1744 人正在学习 去看看 CSDN讲师

如果说Java和C#哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说JavaScript是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持JavaScript,JavaScript在硬件端以及物联网领域有了新的机会。

IoT应用开发的数据链路

图1是一个智能家居物联平台的数据链路。

这里写图片描述

图1 智能家居物联平台的数据链路

一般来说,可以把IoT应用分为如图所示的四层。

  • client层:指的是IoT设备,可以是冰箱、空调,也可以是一些温湿度传感器。

  • gateway层:大多数场景中gateway是家里的WiFi路由器,也有小部分是基于Zigbee或蓝牙的网关设备。智能生活场景中的gateway数量相对于工业领域要少很多,在工业领域存在大量的边缘计算放在gateway层进行处理(雾计算)。

  • cloud云层:这里是集中处理业务的地方。

  • 应用层:这一层是直接与用户打交道的地方,可以是通过电脑的Web浏览器、手机App,也可以是有屏幕的智能设备的显示器。随着语音技术的发展,无屏设备也可以通过语音交互,作为一个应用存在于物联网的交互层。

物联设备(下文统称为client),可以是单个设备或多个设备组成的应用场景。比如冰箱把运行的功耗数据、库存数据、温度数据采集,通过gateway发送到cloud层,cloud层收集数据后进行异常判断,做智能模式推荐等业务处理后到application层进行展现和交互。用户可以通过冰箱的设备数据进行模式选择,还可以做一些与设备无关的增值服务,比如听音乐、买菜等,这就是一个智能冰箱的数据链路。还有些client是成组智能场景的,比如温湿度传感器将数据上传到cloud,经过处理和加工,动态控制家中空调的温度,调节空气净化器的运行模式等。这么描述好像没有体现出cloud层的作用,那如果运行模式是用户预先配置好的呢?如“当温度超过25度,请帮我打开空调”,这些业务都可以通过cloud层进行处理。

client层的连接方式有WiFi、Bluetooth、Zigbee,而MQTT是为了让物联网设备更加互联互通而出现的应用层数据协议。

MQTT+JavaScript

MQTT是一个长连接的通讯应用层协议,最大的特点是数据精简、消息可靠、Publish-Subscribe模式灵活易用。MQTT已经成为IoT传输的标准协议,应用非常广泛。

图2中Client指的是物联网设备。Client通过对Topic的订阅和发布数据管理应用中的数据流动,而Broker是MQTT应用中用于管理Topic的角色。Server是物联网应用中的服务端,用于处理业务逻辑。

这里写图片描述
图2 MQTT的数据链路图

MQTT被广泛使用的一个重要的原因是MQTT的生态非常完善,同时也支持JavaScript。因此图2所示的所有链路和模块,都可以通过JavaScript实现。

这里写图片描述
图3 JavaScript在MQTT架构中常用的架构

JavaScript在MQTT架构中常用的框架

mosca(https://github.com/mcollina/mosca
mosca是一个用JavaScript实现的MQTT Broker。不仅如此,mosca还增加了对数据库,如Redis、MongoDB的支持,用来实现消息数据的存储。

MQTT.js(https://github.com/mqttjs/MQTT.js
MQTT.js是官网推荐的JavaScript实现的Client端。

KOA和Express
这两者都是非常主流的Node版本的Server,简单易用。

实战物联网应用

这节我们运用之前介绍的框架,自己动手完成一个简单的物联网应用。应用场景如图4所示,温度传感器用于接收温度,并把文档通过MQTT发送到Server端,在Server端进行业务处理,根据温度计算出穿衣提示,通过MQTT把数据发送到特定的Topic,App订阅Topic获取数据后进行展现。

这里写图片描述
图4 “穿衣提示”业务场景框架

Broker端的实现

Broker端使用mosca,参考网页https://github.com/mcollina/mosca

  • 安装mosca。
nmp install mosca --save
  • 启动mosca。这里需要注意,如果本地没有配置MongoDB,则需要把ascoltatore中的内容全部注释掉。
var mosca = require('mosca');

var ascoltatore = {
  //using ascoltatore
  // type: 'mongo',
  // url: 'mongodb://localhost:27017/mqtt',
  // pubsubCollection: 'ascoltatori',
  // mongo: {}
};

var settings = {
  port: 1883,
  backend: ascoltatore
};

var server = new mosca.Server(settings);

server.on('clientConnected', function(client) {
    console.log('client connected', client.id);
});

// fired when a message is received
server.on('published', function(packet, client) {
  console.log('Published', packet.payload); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}
  // console.log('>>>packet', packet); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}
});

server.on('ready', setup);

// fired when the mqtt server is ready
function setup() {
  console.log('Mosca server is up and running');
}

代码完成后,启动文件,本地的一个Broker就跑在localhost的1883端口上了。

Client端的温度传感器实现

Client使用MQTT.js实现,参考网页https://github.com/mqttjs/MQTT.js

  • 安装
npm install mqtt --save
  • 启动
var mqtt = require('mqtt');
var client  = mqtt.connect('mqtt://localhost:1883');

client.on('connect', function () {
   console.log('>>> connected')
   // client.subscribe('/tips')
   setInterval(
        ()=>{client.publish('/temperature', '30');},
        3000
    );

})

client.on('message', function (topic, message) {
  // message is Buffer
  console.log(message.toString())
})

// client.end();

执行Node index后Client就启动了,可以看到在MQTT.connect方法中连接了上一节中启动的Broker地址,连接成功后,Client会输出日志,“>>> connected”,Broker的控制台也会输出Client的连接信息。

这里模拟了温度传感器,定时3秒向/temperature的Topic中发送温度数据。

本节的温度器可以在电脑中使用Node方式运行,也可以运行在支持JavaScript的开发板中,如RUFF、NodeMCU、Raspberry Pi,并且可以使用真实的传感器。

Server的实现

Server使用MQTT.js订阅Client发送到/temperature Topic的数据进行处理,把处理后的数据转译成JSON发送到另一业务主题/tips中。

实现代码如下:

'use strict'

const mqtt = require('mqtt');
var client  = mqtt.connect('mqtt://localhost:1883');

client.on('connect', function () {
   console.log('>>> connected');
   client.subscribe('/temperature');
})

client.on('message', function (topic, message) {
  var temperature = parseInt(message.toString());
  var data = {temperature};

  if (temperature >= 60) {
        data.tips = "热... 500服务器故障";
  }
  else if (temperature >= 50) {
        data.tips = "今天天气非常热,建议不要穿衣服了";
  }
  else if (temperature >= 40) {
        data.tips = "今天天气十分的热,建议穿短袖T恤+短裤";
  }
  else if (temperature >= 30) {
        data.tips = "今天天气有点的热,建议穿短袖T恤";
  }
  else if (temperature >= 0) {
        data.tips = "今天天气正好,可以穿上一件薄衣服";
  }
  else if (temperature >= -10) {
        data.tips = "今天天气十分寒冷,棉袄可以穿上一件";    
  }
  else {
        data.tips = "今天天气十分十分寒冷,棉袄可以穿上二件";  
  }
  client.publish('/tips', JSON.stringify(data));
  // if (temperature+1) {}
  // message is Buffer
  console.log(JSON.stringify(data));
})

App的实现

Demo的App使用KOA启动一个Web,在Web中展现当前温度对应的穿衣提示,通过订阅tips获取数据。

  • 安装koa
$ npm install koa
  • 实现代码
'use strict'

const Koa = require('koa');
const mqtt = require('mqtt');
const app = new Koa();


var msg = {temperature:"-",tips:""};
// response
app.use(ctx => {
  ctx.body = "当前温度:" + msg.temperature + "度" + "\n" + '穿衣提示:'+msg.tips + "\n"  ;
});

app.listen(3000);

//mqtt
var client  = mqtt.connect('mqtt://localhost:1883');

client.on('connect', function () {
   console.log('>>> connected');
   client.subscribe('/tips');
})

client.on('message', function (topic, message) {
  var data = JSON.parse(message.toString());
  console.log(message.toString()); 
  console.log(data.tips); 
  msg = data;

  // if (temperature+1) {}
  // message is Buffer
  // let str = message.toString();
  // let data = JSON.parse(message);
  // console.log(data.tips);
  // msg =  message.toString();
})

Demo小节

本章给出了一个简单的物联网业务的业务场景和实现逻辑,其中Client也可以运行在电脑上进行Demo查看,或是跑在真实物联设备或开发版上。如图5,笔者使用RUFF开发板实现了一次。

这里写图片描述
图5 Demo硬件演示

完整Demo代码已经分享在github中,大家可以输入URL下载。
https://github.com/coolnameismy/javascript-mqtt-demo-wearingTip

总结

本文和大家交流了物联网应用的一般数据链路、MQTT协议的架构,并基于MQTT实现了一个简单的物联网应用。

现在正是前端工程师的大好机会,越来越多的嵌入式设备都开始支持JavaScript,原因是现在有很多JavaScript引擎可以把JavaScript转换成各种平台的底层代码,比较有名的有Jerryscript、Duktape等。随着越来越多的JavaScript工程师进入嵌入式开发的领域,嵌入式应用开发也会出现前后端分离的情况(应用开发或是驱动开发),类似于Web开发的前后端分离。前端关注在应用、创意、数据链路、用户体现上,而后端则关心GPIO、I2C的底层数据接口和驱动,平台兼容性等方向。

这里写图片描述

2019-09-13 22:02:51 qq_44658169 阅读数 43
  • 【在线峰会】物联网全栈开发之道视频教程

    智能化的物联网时代,开发者该如何顺势而为?本次峰会从易于上手、高效的“物联网全栈开发”着手,集结一线讲师,基于 JavaScript、Python,详勘物联网技术架构、技术栈、应用开发平台、安全等实战经验,希望通过一天的时间,帮助开发者掌握物联网全栈开发之道。具体内容包括:现代物联网应用系统架构与技术栈、lOT应用开发,物联网开发平台的选择、基于JavaScript、Python等编程语言进行物联网开发,物联网安全防守之道等。

    1744 人正在学习 去看看 CSDN讲师

使用C#开发数据库应用数据系统

技术内容

1.2 事件处理

1.2.1 编写事件处理程序

1.2.2 技能训练

——————————————————————————————

第一章——初始Windows程序

1.2 事件处理

平时我们在计算机上的操作基本都是通过鼠标或者敲击键盘,系统就会有相应的反应。这些鼠标单击,鼠标释放,键盘键按下,键盘键释放都是 Windows 操作系统中的事件。Windows 操作系统本身就是通过事件来处理用户请求的。例如,单击 “开始” 按钮就会显示 “开始” 菜单,双击某文件夹图标,就会打开该文件夹窗口等。Windows 的这种随时响应用户的触发事件,并作出相应处理的机制就叫做事件驱动机制。

使用 Visual Studio 创建的 Windows 程序也是由事件驱动的。那么,怎么才能让程序知道发生了什么事件呢? .NET Framework 为窗体和控件定义了很多常用的事件,我们只要针对用户触发的事件,编写相应的事件处理程序即可。

1.2.1 编写事件处理程序

窗体和控件都有很多定义好的事件,比较常用的有窗体的 Load 事件,按钮的 Click 事件等。有关控件的具体事件,可以在 Visual Studio 中选择控件,在 “属性” 窗口中查看事件列表。

在 Visual Studio 中编写事件处理程序非常方便,步骤如下:

(1)单击要创建事件处理程序的窗体或控件。

(2)在 “属性” 窗口单击 “事件” 按钮。

(3)双击要处理的事件定位到事件处理方法。

(4)编写处理代码。

问题:如何实现 MySchool 窗体中 ”取消“ 按钮的功能,即单击 ”取消“ 按钮时,关闭登录窗体?

分析:当单击按钮时,会触发按钮的 Click 事件;当该事件发生时,将执行关闭登陆窗体的功能。这样,Click 事件方法中需要添加关闭窗体的代码。因此,需要处理 ”取消 “ 按钮的 Click 事件,编写事件处理代码,关闭窗体。

按照上述步骤,编写 ”取消“ 按钮 Click 事件的处理程序,代码如 示例四 所示。

示例四

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

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

    private void Form1_Load(object sender, EventArgs e)
    {

    }
    /// <summary>
    /// 响应“取消”按钮事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btncancel_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}

}

再次运行程序,当单击 ”取消“ 按钮时,窗体将关闭。

下面分析一下 示例四 的代码,其中事件处理方法的定义是自动生成的,它接收了两个参数。

Sender 是事件源,表示发生了这个事件的对象,如在这个事件中,事件源就是按钮。不同的控件可能会公用同一个事件处理方法,我们可以通过 sender 得到发生事件的控件,这需要进行强制类型转换。

e 是事件参数(EventArgs)对象,不同的对象会有不同的事件参数。在方法中,只使用一句代码实现窗体关闭。

this 是一个关键字,代表当前窗体对象。在 示例四 中,this.Close()方法通过 this 调用当前窗体对象的 Close()方法关闭窗体。

在生成事件处理代码时, Visual Studio 实际上自动完成了事件注册工作,这样才能保证事件发生时调用相应的方法,打开窗体的 Designer 文件,可以看到事件注册的代码:

部分代码:

        // btncancel
        // 
        this.btncancel.Location = new System.Drawing.Point(285, 204);
        this.btncancel.Name = "btncancel";
        this.btncancel.Size = new System.Drawing.Size(75, 23);
        this.btncancel.TabIndex = 3;
        this.btncancel.Text = "取消";
        this.btncancel.UseVisualStyleBackColor = true;
        this.btncancel.Click += new System.EventHandler(this.btncancel_Click);

规范

从 示例四 可以看到,事件处理方法的方法名是根据控件名生成的。因此,在生成事件处理方法之前,应该先为控件指定一个有意义的名称,以增加代码的可读性。

1.2.2 技能训练

上机练习1. 练习——设置 MySchool 登录窗体

需求说明: 使用图片素材,设计出 如图1.8 所示的登陆窗体。

登录类型中提供两个选项:系统管理员,学生。

提示: 新建 Windows 程序,命名为 MySchool,使用 Label,TextBox,ComboBox,Button 设计窗体。

——————————————————————————————

上级练习2:练习——实现取消登录功能

需求说明:单击 MySchool 登录窗体的 “取消” 按钮,窗体关闭。

——————————————————————————————

上机练习3:指导——单击改变窗体背景色

训练要点:窗体的背景色属性,编写事件处理程序。

需求说明:新建窗体,设置背景色为红色。当单击窗体时,变换窗体的背景色。

如果为红色,则变成黄色。

如果为黄色,则变成绿色。

如果为绿色,则变成红色。

实现思路及关键代码

1.新建项目,选择 Windwos 窗体应用程序。

2.通过 BackColor 属性将窗体背景色设置为红色。

3.处理窗体的单击事件,切换窗体的背景色。

——————————————————————————————

上机练习1.——设计 MySchool 登录窗体

在这里插入图片描述

需要用到三个Label,两个TextBox,一个ComboBox,两个Button

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
——————————————————————————————

上机练习2.——实现登录取消功能

双击取消按钮,在事件里面编写代码

    /// 响应“取消”按钮事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void btncancel_Click(object sender, EventArgs e)
    {
        this.Close();
    }

——————————————————————————————

上机练习3.——单机改变窗体背景色

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

右击窗口属性打开MouseClick事件双击进去,然后编写代码

    /// 鼠标单击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void frmchange_MouseClick(object sender, MouseEventArgs e)
    {
        if (this.BackColor == Color.Red)  //如果当前窗口的背景颜色是红色
        {
            this.BackColor = Color.Yellow;  //窗口颜色改变为黄色
        }
        else if (this.BackColor == Color.Yellow) //如果当前窗口的背景颜色是黄色
        {
            this.BackColor = Color.Green; //窗口颜色改变为绿色
        }
        else
        {
            this.BackColor = Color.Red; //窗口颜色改变为红色
        }
    }

——————————————————————————————

下节学习 1.3 增加窗体友好性

1.3.1 MessageBox 消息框

1.3.2 用户输入验证

1.3.3 窗体间的跳转

1.3.4 窗体间的数据传递

——————————————————————————————

右下角 放大150观看最佳!

.NET入门介绍

阅读数 44

没有更多推荐了,返回首页