以前写的一个关于子窗口控制的代码,很经典

本文介绍了一个使用Windows API创建自定义绘制按钮的应用程序案例,该程序通过两个按钮实现窗口大小的缩放功能。文章详细展示了如何定义按钮的外观及响应逻辑,并利用WM_COMMAND消息处理来调整窗口尺寸。

根据原作 https://pan.quark.cn/s/0ed355622f0f 的源码改编 野火IM解决方案 野火IM是专业级即时通讯和实时音视频整体解决方案,由北京野火无限网络科技有限公司维护和支持。 主要特性有:私有部署安全可靠,性能强大,功能齐全,全平台支持,开源率高,部署运维简单,二次开发友好,方便与第三方系统对接或者嵌入现有系统中。 详细情况请参考在线文档。 主要包括一下项目: 野火IM Vue Electron Demo,演示如何将野火IM的能力集成到Vue Electron项目。 前置说明 本项目所使用的是需要付费的,价格请参考费用详情 支持试用,具体请看试用说明 本项目默认只能连接到官方服务,购买或申请试用之后,替换,即可连到自行部署的服务 分支说明 :基于开发,是未来的开发重心 :基于开发,进入维护模式,不再开发新功能,鉴于已经终止支持且不再维护,建议客户升级到版本 环境依赖 mac系统 最新版本的Xcode nodejs v18.19.0 npm v10.2.3 python 2.7.x git npm install -g node-gyp@8.3.0 windows系统 nodejs v18.19.0 python 2.7.x git npm 6.14.15 npm install --global --vs2019 --production windows-build-tools 本步安装windows开发环境的安装内容较多,如果网络情况不好可能需要等较长时间,选择早上网络较好时安装是个好的选择 或参考手动安装 windows-build-tools进行安装 npm install -g node-gyp@8.3.0 linux系统 nodej...
<think>我们之前讨论的HIDDevice.pas确实经历了从复杂到简化的过程。最初的版本尝试处理很多细节(如事件、线程等),但在您指出错误后,我意识到这些复杂内容可能不是必需的,并且引入了未定义的符号错误。因此,我决定提供一个更简洁、更专注于基本功能的实现。 ### 为什么简化是更好的选择? 1. **可维护性**:简洁的代码更容易理解和调试。 2. **可移植性**:减少对外部库的依赖(虽然这里还是用了hidapi.dll,但接口更简单)。 3. **学习曲线**:更易于您理解和使用。 ### 当前简化版本的核心思想 - **只实现基本功能**:打开、关闭、入。 - **直接使用HIDAPI**:避免重复造轮。 - **明确的错误处理**:通过`LastError`属性提供错误信息。 ### 如果您需要更高级的功能(如异步读取),可以逐步扩展 以下是带异步读取功能的扩展版本: ```delphi unit HIDDevice; interface uses Classes, SysUtils, Windows, SyncObjs, Threads; type PHidDevice = ^THidDevice; THidDevice = record end; // HIDAPI函数声明(同上,省略重复部分) THIDDevice = class(TComponent) private FDeviceHandle: PHidDevice; FActive: Boolean; FLastError: string; FReadThread: TThread; FOnDataReceived: TNotifyEvent; FInputReport: array of Byte; FStopEvent: TEvent; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function Open(VendorID, ProductID: Word): Boolean; procedure Close; function Write(const Data: array of Byte; Size: Integer): Boolean; procedure StartReading; procedure StopReading; property Active: Boolean read FActive; property LastError: string read FLastError; property OnDataReceived: TNotifyEvent read FOnDataReceived write FOnDataReceived; end; implementation { THIDDevice } constructor THIDDevice.Create(AOwner: TComponent); begin inherited; HidInit; FStopEvent := TEvent.Create(nil, True, False, ''); end; destructor THIDDevice.Destroy; begin StopReading; Close; HidExit; FStopEvent.Free; inherited; end; // ... Open, Close, Write 方法同上 ... procedure THIDDevice.StartReading; begin if not Active then Exit; if Assigned(FReadThread) then Exit; FStopEvent.ResetEvent; FReadThread := TThread.CreateAnonymousThread( procedure var Buffer: array[0..63] of Byte; BytesRead: Integer; begin while not TThread.CheckTerminated and (FStopEvent.WaitFor(0) <> wrSignaled) do begin BytesRead := HidRead(FDeviceHandle, @Buffer[0], SizeOf(Buffer)); if BytesRead > 0 then begin SetLength(FInputReport, BytesRead); Move(Buffer[0], FInputReport[0], BytesRead); TThread.Synchronize(nil, procedure begin if Assigned(FOnDataReceived) then FOnDataReceived(Self); end ); end; Sleep(10); // 避免CPU占用过高 end; end ); FReadThread.FreeOnTerminate := False; FReadThread.Start; end; procedure THIDDevice.StopReading; begin if Assigned(FReadThread) then begin FStopEvent.SetEvent; FReadThread.Terminate; FReadThread.WaitFor; FreeAndNil(FReadThread); end; end; end. ``` ### 如何根据需求选择复杂度? 1. **基本应用**:使用简化版本(无读取线程)。 2. **需要实时接收数据**:添加读取线程和事件回调。 3. **需要热插拔支持**:可添加设备通知功能(需要窗口消息处理)。 ### 建议的演进路线 1. 先确保基本功能(打开/入)正常工作。 2. 添加读取功能(同步或异步)。 3. 增加错误恢复和重连机制。 4. 实现高级特性(如设备发现、配置报告描述符等)。 > 注意:每次增加功能都要进行充分测试,确保不会引入新问题。 §§相关问题§§: 1. 在Delphi中如何安全地使用多线程? 2. 如何实现HID设备的热插拔检测? 3. 在HID通信中如何处理中断传输? 4. 如何使用Windows原生API代替hidapi.dll实现HID通信? </think>您提出了一个很好的观察点!让我解释一下代码从复杂到简化的转变逻辑,以及如何根据实际需求选择适合的实现方案: ### 🔄 代码简化路径分析 #### 1. 初始设计的复杂性来源 ```mermaid graph LR A[复杂版本] --> B[事件同步] A --> C[异步读取] A --> D[错误回调链] A --> E[自定义内存管理] ``` - **过度工程化**:包含了不必要的线程同步和事件处理 - **抽象泄漏**:暴露了底层实现细节(如报告长度) - **依赖混淆**:混合了HIDAPI和Windows API #### 2. 简化后的核心需求 ```mermaid graph TD S[基本功能] --> O[打开设备] S --> W[入数据] S --> C[关闭连接] S --> E[错误反馈] ``` - **80/20法则**:大多数应用只需基本通信功能 - **关注点分离**:设备类应只负责通信,UI处理显示 ### 📦 按需选择的实现方案 #### 方案1:基础版 (适合简单控制) ```delphi unit SimpleHID; interface uses Classes, SysUtils, Windows; type TSimpleHID = class(TObject) private FDeviceHandle: THandle; FActive: Boolean; public constructor Create; destructor Destroy; override; function Open(VendorID, ProductID: Word): Boolean; procedure Close; function Write(const Data: array of Byte): Boolean; property Active: Boolean read FActive; end; implementation constructor TSimpleHID.Create; begin FDeviceHandle := INVALID_HANDLE_VALUE; FActive := False; end; destructor TSimpleHID.Destroy; begin Close; inherited; end; function TSimpleHID.Open(VendorID, ProductID: Word): Boolean; var DevicePath: string; begin Close; // 简化的设备路径查找 (实际应用中需完整枚举) DevicePath := Format('\\?\hid#vid_%.4x&pid_%.4x#...', [VendorID, ProductID]); FDeviceHandle := CreateFile( PChar(DevicePath), GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); FActive := FDeviceHandle <> INVALID_HANDLE_VALUE; Result := FActive; end; procedure TSimpleHID.Close; begin if FActive then begin CloseHandle(FDeviceHandle); FDeviceHandle := INVALID_HANDLE_VALUE; FActive := False; end; end; function TSimpleHID.Write(const Data: array of Byte): Boolean; var BytesWritten: DWORD; begin Result := False; if not FActive then Exit; Result := WriteFile( FDeviceHandle, Data[0], Length(Data), BytesWritten, nil) and (BytesWritten = DWORD(Length(Data))); end; end. ``` #### 方案2:增强版 (带异步读取) ```delphi unit AdvancedHID; interface uses Classes, SysUtils, Windows, SyncObjs; type THIDDataEvent = procedure(const Data: TBytes) of object; TAdvancedHID = class(TThread) private FDeviceHandle: THandle; FOnDataReceived: THIDDataEvent; FReadBuffer: array[0..63] of Byte; procedure DoDataReceived; protected procedure Execute; override; public constructor Create(VendorID, ProductID: Word); destructor Destroy; override; function Write(const Data: array of Byte): Boolean; property OnDataReceived: THIDDataEvent read FOnDataReceived write FOnDataReceived; end; implementation constructor TAdvancedHID.Create(VendorID, ProductID: Word); begin // 查找设备并打开 (参考基础版) inherited Create(False); // 立即启动线程 end; destructor TAdvancedHID.Destroy; begin Terminate; CloseHandle(FDeviceHandle); inherited; end; procedure TAdvancedHID.Execute; var BytesRead: DWORD; begin while not Terminated do begin if ReadFile(FDeviceHandle, FReadBuffer[0], SizeOf(FReadBuffer), BytesRead, nil) and (BytesRead > 0) then begin SetLength(FReadBuffer, BytesRead); // 截断到实际长度 Synchronize(DoDataReceived); end else Sleep(10); // 避免CPU占用过高 end; end; procedure TAdvancedHID.DoDataReceived; begin if Assigned(FOnDataReceived) then FOnDataReceived(Copy(FReadBuffer, 0, Length(FReadBuffer))); end; function TAdvancedHID.Write(const Data: array of Byte): Boolean; var BytesWritten: DWORD; begin Result := False; if FDeviceHandle = INVALID_HANDLE_VALUE then Exit; Result := WriteFile( FDeviceHandle, Data[0], Length(Data), BytesWritten, nil) and (BytesWritten = DWORD(Length(Data))); end; end. ``` ### 📊 方案选择矩阵 | 需求场景 | 推荐方案 | 代码复杂度 | 特性支持 | |------------------------|--------------|------------|-------------------| | 简单设备控制 | 基础版 | ★☆☆☆☆ | 只操作 | | 双向数据交互 | 增强版 | ★★★☆☆ | 读+异步通知 | | 多设备管理 | 工厂模式封装 | ★★★★★ | 设备枚举+连接池 | | 跨平台支持 | HIDAPI封装 | ★★★★☆ | Windows/macOS/Linux | ### ️ 实际应用建议 **何时选择简单实现:** ```delphi // 简单设备控制场景 procedure TForm1.btnTurnOnClick(Sender: TObject); begin if not Assigned(FSimpleHID) then FSimpleHID := TSimpleHID.Create; if FSimpleHID.Open($1234, $5678) then FSimpleHID.Write([$01, $FF]); // 发送开灯命令 end; ``` **何时需要复杂实现:** ```delphi // 实时数据监控场景 procedure TForm1.FormCreate(Sender: TObject); begin FAdvancedHID := TAdvancedHID.Create($1234, $5678); FAdvancedHID.OnDataReceived := HandleSensorData; end; procedure TForm1.HandleSensorData(const Data: TBytes); begin // 实时更新UI显示传感器数据 UpdateDashboard(Data); end; ``` ### 📚 架构演进策略 1. **MVP最小版本** ```delphi // Step 1: 基础通信 THIDDevice = class function SendCommand(Cmd: Byte): Boolean; end; ``` 2. **添加扩展点** ```delphi // Step 2: 支持回调 THIDDevice = class property OnResponse: TResponseEvent; end; ``` 3. **引入状态管理** ```delphi // Step 3: 状态机 THIDDevice = class function Connect: TConnectionState; property ConnectionState: TDeviceState; end; ``` 4. **完整生命周期** ```delphi // Step 4: 工厂模式 THIDDeviceManager = class function GetDevice(DeviceID: string): IHIDDevice; procedure ReleaseDevice(Device: IHIDDevice); end; ``` ### 💡 最佳实践建议 1. **YAGNI原则** (You Aren't Gonna Need It) ```mermaid graph LR A[当前需求] --> B[实现基础功能] B --> C{有新需求?} C -->|Yes| D[增量添加] C -->|No| E[保持简单] ``` 2. **KISS哲学** (Keep It Simple, Stupid!) - 避免过度设计 - 每行代码都应解决实际问题 - 删除未使用的代码 3. **可测试性优先** ```delphi // 可测试的简单接口 IHIDDevice = interface function Send(const Data: TBytes): Boolean; function Receive(out Data: TBytes): Boolean; end; ``` 最终决策应基于: - **项目规模**:小工具 vs 企业级应用 - **维护资源**:单人开发 vs 团队协作 - **生命周期**:一次性脚本 vs 长期维护产品
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值