发动态
综合 最新发布 最新回复
图文
列表
置顶
HDI高密度互连板正式上线
在计算机编程的世界中,C++是一门备受推崇的编程语言,它的强大之处之一就是支持面向对象编程(Object-Oriented Programming,OOP)。在C++中,类和对象是面向对象编程的核心概念,它们为程序员提供了一种结构化的方式来组织和管理代码。1. 类(Class):抽象的蓝图在C++中,类是一种用户定义的数据类型,用于封装数据和方法。可以将类看作是对象的抽象蓝图,其中包含了描述对象属性和行为的成员变量和成员函数。通过定义类,程序员可以创建自己的数据类型,从而更好地组织和管理代码。 例如我们可以把人作为一个对象,他有基本的属性:性别、身高、年龄等等 也有基本的行为:吃饭、睡觉、学习、玩游戏等等。1.1 类的基本结构一个简单的类通常包含以下几个要素:class MyClass { private: // 成员变量(属性) int myInt; double myDouble; public: // 构造函数 MyClass() { myInt = 0; myDouble = 0.0; } // 成员函数(方法) void setValues(int i, double d) { myInt = i; myDouble = d; }     ~MyClass() { } }; class + 类名 的方法创建我们的类。 类中的变量可以称作成员,他们有一些访问属性:Protect:保护,private:私密,public:公开 故名思意除了public其他的变量都不可以在类外被访问。 类中有两种特殊的函数 与类名相同的名称被称作构造函数,我们在创建类的同时会调用构造函数! 同样的还有一个特殊的函数:析构函数,和析构函数差不多,但是需要多一个~符号,这个函数会在类被释放的时候调用。1.2 类的实例化通过定义类,我们可以创建类的实例,也称为对象。对象是类的具体实体,可以调用类中定义的方法,访问和修改成员变量。int main() { // 创建类的实例 MyClass myObject; // 调用成员函数     myObject.setValues(42, 3.14); return 0; } 2. 对象(Object):实体化的具体实例对象是类的实例,是具体存在的数据单元。在C++中,通过创建对象,我们可以利用类定义的结构来存储和操作数据。2.1 对象的特性对象具有以下几个重要的特性:封装性(Encapsulation): 类的内部实现对外部是不可见的,只有通过公共接口(成员函数)才能访问类的属性和方法,确保了数据的安全性和代码的模块化。继承性(Inheritance): 类可以通过继承从其他类中获取属性和方法,实现代码的重用和扩展。多态性(Polymorphism): 不同的类可以具有相同的接口,但表现出不同的行为,提高了代码的灵活性和可维护性。2.2 对象的生命周期对象的生命周期从创建到销毁,包括对象的构造、使用和析构阶段。在C++中,构造函数和析构函数负责对象的初始化和清理工作。int main() { // 创建对象,调用构造函数 MyClass obj; // 对象在main函数结束时销毁,调用析构函数 return 0; C++中的类和对象为程序提供了一种灵活而强大的编程范式,使得代码更易理解、维护和扩展。通过合理利用类和对象,程序员可以更好地组织和管理代码,提高代码的可读性和可维护性。
C++中的类和对象:面向对象编程的基石
嘉立创PCB
邮票孔拼板要求
嘉立创PCB
前面几期利用.NET MAUI我们开发了一个Android应用用来接收ESP32的图片数据以及制作了一个摇杆方便我们操控。 但是有一点,我们发送图片以及交流的IP都是固定的。 可是,IP地址会随着网络以及设备发生变换,那么我们怎么知道每次的IP地址呢。 本期我们将介绍ESP32如何开启AP模式来让手机进行连接并且获取所连接的设备的IP地址。 在ESP的AP模式下,设备像一个Wi-Fi网络中的路由器一样,允许其他设备通过Wi-Fi连接到它,从而建立本地网络。这种模式通常用于创建一个局域网(Local Area Network,LAN),其中ESP设备充当中心节点,其他设备可以通过该节点相互通信。 通过AP模式,ESP设备可以提供网络连接、数据传输和通信服务,使其他设备能够连接到互联网或者在局域网内进行数据交换。这对于构建物联网应用和连接智能设备非常有用。代码编写#includeesp_wifi.h#include <Wifi.h> 首先需要导入这两个库,分别用来连接WiFi和获取设备IP  WiFi.softAP(ssid, password);//AP模式开启Wifi ip = WiFi.softAPIP();//获取本机IP   Serial.println(ip);//打印IP   WiFi.onEvent(WiFiEvent);//创建一个事件用来监听事件 使用上述语句开启WiFi AP模式,ssid为Wifi的名字,password为Wifi的密码,注意这个密码至少八个字符!! 可以看到可以发现一个ESP32的Wifi.void WiFiEvent(WiFiEvent_t event) {   if(event == 13)   {    wifi_sta_list_t wifi_sta_list; tcpip_adapter_sta_list_t adapter_sta_list; memset(&wifi_sta_list, 0, sizeof(wifi_sta_list)); memset(&adapter_sta_list, 0, sizeof(adapter_sta_list)); esp_wifi_ap_get_sta_list(&wifi_sta_list); tcpip_adapter_get_sta_list(&wifi_sta_list, &adapter_sta_list); for (int i = 0; i < adapter_sta_list.num; i++) { tcpip_adapter_sta_info_t station = adapter_sta_list.sta[i]; Serial.print("station nr "); Serial.println(i + 1); Serial.print("MAC: "); for (int i = 0; i < 6; i++) { Serial.printf("%02X", station.mac[i]); if (i < 5) Serial.print(":"); } Serial.print("\nIP: "); ip4_addr_t ip_buf; memcpy((char *)&ip_buf, (char *)&station.ip, sizeof(ip4_addr)); String ipstr = ip4addr_ntoa(&(ip_buf)); Serial.println(ipstr); } } } 接着为Wifi添加事件回调。(这些设备包括:设备断开,设备连接,设备被分配到IP......) 当有Wifi事件触发时,我们打印连接设备的IP地址。 这里Wifi连接和赋予地址都会触发回调,我们只处理赋予IP地址的事件 wifi_sta_list_t 和 tcpip_adapter_sta_list_t 是结构体,用于存储STA(Station)列表的信息。 memset 函数用于将结构体初始化为零,以确保所有字段的初始值为零。 esp_wifi_ap_get_sta_list 用于获取与当前AP连接的STA列表,并将结果存储在 wifi_sta_list 中。 tcpip_adapter_get_sta_list 则用于将 wifi_sta_list 中的信息转换为 adapter_sta_list 结构体中。 接下来,通过循环遍历 adapter_sta_list 中的STA列表,逐个处理每个STA的信息。 最后是打印IP信息。 一个是本机地址,一个是我手机所连接的IP。String ipstr = ip4addr_ntoa(&(ip_buf)); if (ipstr== ("0.0.0.0")) { continue; } staIPAddresses[i] = ipstr; STANumber = i; Serial.println(ipstr); 我们比较一下,剔除掉自身的IP,然后保存所有设备的IP。if (ipstr== ("0.0.0.0")) { continue; } staIPAddresses[i] = ipstr; STANumber = i;
ESP32使用Arduino IDE开启Wifi AP模式并获取所连接设备地址
嘉立创PCB
上期我们利用FFImageLoad实现了图片流的显示,之前也有一期简单介绍了一下利用SkiaSharp实现绘图。 本期我们来实现一个摇杆的实现。public class DrawAble {     private readonly Rocker view; public DrawAble(Rocker view) {         this.view = view; } private void Draw_Circle(SKSurface surface, SKRect bounds) { float centerX = bounds.MidX; float centerY = bounds.MidY; Midx = centerX; Midy = centerY; // 计算圆的半径(使用ChargingRingDrawable类中的rad属性) float radius = CirCleRad; // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Blue; paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 20; // 画圆 surface.Canvas.DrawCircle(centerX, centerY, radius, paint); }     } public void Draw(SKSurface surface, SKRect bounds) { surface.Canvas.Clear();         Draw_Circle(surface, bounds);//画圆轮廓     } } 首先定义两个类,一个是画板类,他必须有最基本的Draw函数用来给Sharp实现接口。 其构造函数传入我们的Rocker类,这个类我们在下面定义。 public partial class Rocker : SKCanvasView {         private readonly DrawAble drawable; public Rocker() {             this.EnableTouchEvents = true;// this.drawable = new ChargingRingDrawable(this);         } protected override void OnPaintSurface(SKPaintSurfaceEventArgs e) { this.drawable.Draw(e.Surface, e.Info.Rect); this.InvalidateSurface(); } protected override void OnTouch(SKTouchEventArgs e) {             base.OnTouch(e);         } } } 接着定义一个类,命名为Rocker,这个类抽象自SKCanvasView(SkiaSharp的控件) 定义一个画板,构造的时候传入自身。 我们要保留两个处理函数,一个是OnPaintSurface,我们的控件刷新就会调用这个函数,还有一个是OnTouch函数,这个函数用来处理我们的触摸事件。private void Draw_Circle(SKSurface surface, SKRect bounds) {     float centerX = bounds.MidX;//获得画板中心 float centerY = bounds.MidY;     Midx = centerX;//用一个参数保存画板中心 Midy = centerY; // 计算圆的半径(使用ChargingRingDrawable类中的rad属性) float radius = CirCleRad; // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Blue; paint.Style = SKPaintStyle.Stroke; paint.StrokeWidth = 20; // 画圆 surface.Canvas.DrawCircle(centerX, centerY, radius, paint); } } 在DrawAble类中有这样子一个函数,其作用是画一个基本的圆,我设置的大小是400像素。private void Draw_InsertCircle(SKCanvas canvas, SKPoint touchLocation, float radius) { // 控件的中心点 float centerX = Midx; float centerY = Midy; // 计算手的位置与圆的交点 SKPoint intersectionPoint = CalculateIntersectionPoint(centerX, centerY, 300, touchLocation); // 使用SKPaint对象定义圆的样式(颜色、线条宽度等) using (SKPaint paint = new SKPaint()) { paint.Color = SKColors.Red; paint.Style = SKPaintStyle.Fill; // 在交点位置绘制圆 canvas.DrawCircle(intersectionPoint.X, intersectionPoint.Y, radius, paint); LocationPoint = intersectionPoint; } } private SKPoint CalculateIntersectionPoint(float centerX, float centerY, float radius, SKPoint touchLocation) { // 计算手的位置与圆的交点 float dx = touchLocation.X - centerX; float dy = touchLocation.Y - centerY; float distance = (float)Math.Sqrt(dx * dx + dy * dy); // 如果距离超出阈值,将交点移动到圆上最近的点 if (distance > radius) { float scale = radius / distance; float intersectionX = centerX + dx * scale; float intersectionY = centerY + dy * scale; return new SKPoint(intersectionX, intersectionY); } // 如果距离未超出阈值,则返回手的位置作为交点 return touchLocation; } 接着画内部的摇杆内容,我们计算这个圆和控件中心的位置,设置一个阈值,保证我们画的圆在这个阈值之内,如果超过了阈值,就计算手的位置和圆的交点,再进行画圆。 实现这样子的效果。 接着,我们补全Rocker中触摸事件protected override void OnTouch(SKTouchEventArgs e) { base.OnTouch(e); switch (e.ActionType) { case SKTouchAction.Pressed: // 处理按下事件 break; case SKTouchAction.Moved: // 处理移动事件 SKPoint touchLocation = e.Location; drawable.InsertCirclePoint = touchLocation; OnPositionChanged(new SKPoint(drawable.LocationPoint.X-drawable.Midx,drawable.LocationPoint.Y-drawable.Midy)); break; case SKTouchAction.Released: SKPoint InsertCirclePoint = new SKPoint(drawable.Midx,drawable.Midy); drawable.InsertCirclePoint = InsertCirclePoint; // 使得画布无效,触发重绘 InvalidateSurface(); OnPositionChanged(new SKPoint(0,0)); break; case SKTouchAction.Cancelled: // 处理取消事件 break; } // 标记事件已处理 e.Handled = true; } 当移动时,将位置传给DrawAble中,DrawAble会根据手的位置绘制摇杆位置。 并且在放下的时候重新归位。 同时我们定义一个事件,向MainPage中传入位置信息。private void Rocker_PositionChanged(object sender, SKPoint newPosition) {    Label.Text = $"Position: ({newPosition.X}, {newPosition.Y})"; } MainPage中打印我们的位置信息。
.NET MAUI的Android WiFi图传开发(6)——利用SkiaSharp制作一个摇杆
嘉立创PCB
1-32层pcb打样,真A级板材,最快12小时出货,自营制造,品质可靠!
打赏记录
服务时间:周一至周六 9::00-18:00 · 联系地址:中国·深圳(福田区商报路奥林匹克大厦27楼) · 媒体沟通:pr@jlc.com · 集团介绍
移动社区