结构体指针类型转换及跨函数传递:鼠标悬停检测场景问题
鼠标悬停检测功能的正确实现方案
问题说明
已定义存储圆形、矩形数据的shapeCircle、shapeRect结构体,以及标识图形类型的objlist枚举,需要实现统一的isMouseHovering函数,接收不同图形的结构体指针并根据枚举值转发到对应检测函数,但当前写法无法正常工作,需修正实现。
原代码片段
结构体与枚举定义
typedef struct _circledata{ FCOORD center; float radius; BOOL filled; COLORREF color; FCOORD *points; }shapeCircle; typedef struct _rectdata{ FCOORD start; FCOORD end; FCOORD points; float length,breadth; BOOL filled; COLORREF color; }shapeRect; typedef enum {Circle, Rect, Triangle} objlist;
WinMain中的调用代码
//In WinMain I initialize two circles shapeCircle newCirc[2]; //gave them values for(int i=0;i<2;i++){ if(isMouseHovering( //have to send pointer to struct and enum value ){ //I tried like this //if(isMouseHovering((void*)newCirc+i,Circle)) newCirc[i].color=red; newCirc[i].radius=55; //Do stuffs }else{ //Do something else } }
isMouseHovering函数实现
BOOL isMouseHovering(void *obj,int objnum){ //I did like this and tried to typecast the pointer int val=0; switch(objnum){ //diverting the checking code based on shape type case Circle: return checkCircleHover( (shapeCircle*) obj ); //sending the pointer of struct break; case Rect: /* * * * */ break; case Triangle: /* * * * */ break; default: /* * * * */ return -1; } return 0; }
错误原因分析
调用isMouseHovering时的指针传递错误:(void*)newCirc+i会将newCirc转为void*后偏移i个字节,但newCirc是shapeCircle数组,每个元素的大小是sizeof(shapeCircle),正确的指针应该指向数组的第i个元素,而非偏移i个字节。
正确实现步骤
1. 修正WinMain中的调用代码
将指针传递改为正确的形式,确保传入的是指向对应shapeCircle元素的指针:
for(int i=0;i<2;i++){ // 正确的指针传递方式:取第i个元素的地址并转为void* if(isMouseHovering((void*)&newCirc[i], Circle)){ newCirc[i].color = RGB(255,0,0); // 用RGB宏定义红色,避免未定义的red变量 newCirc[i].radius = 55; // 执行其他操作 }else{ // 执行其他逻辑 } }
等价写法:(void*)(newCirc + i),因为newCirc+i本身就是指向第i个元素的shapeCircle*,转为void*即可。
2. 实现checkCircleHover函数
补充圆形悬停检测的具体逻辑,判断鼠标坐标是否在圆内:
// 假设FCOORD包含x、y两个浮点型成员 BOOL checkCircleHover(shapeCircle *circle){ // 获取当前鼠标坐标 POINT mousePos; GetCursorPos(&mousePos); // 转换为FCOORD类型 FCOORD mouseCoord = { (float)mousePos.x, (float)mousePos.y }; // 计算鼠标到圆心的距离平方 float dx = mouseCoord.x - circle->center.x; float dy = mouseCoord.y - circle->center.y; float distSq = dx*dx + dy*dy; // 距离平方小于等于半径平方则判定为悬停 return distSq <= circle->radius * circle->radius; }
3. 可选优化:使用通用结构体封装类型与数据
为避免每次调用都传递枚举类型,可定义包含类型标识的通用结构体,让代码更简洁安全:
// 通用图形结构体 typedef struct _shape{ objlist type; union{ shapeCircle circle; shapeRect rect; // 后续可添加Triangle类型 }data; }Shape; // 修改isMouseHovering函数 BOOL isMouseHovering(Shape *shape){ switch(shape->type){ case Circle: return checkCircleHover(&shape->data.circle); case Rect: return checkRectHover(&shape->data.rect); case Triangle: return checkTriangleHover(&shape->data.triangle); default: return FALSE; } } // WinMain中的使用示例 Shape shapes[2]; // 初始化圆形 shapes[0].type = Circle; shapes[0].data.circle.center = (FCOORD){100.0f, 100.0f}; shapes[0].data.circle.radius = 50.0f; // ...其他初始化 for(int i=0;i<2;i++){ if(isMouseHovering(&shapes[i])){ // 处理悬停逻辑 shapes[i].data.circle.color = RGB(255,0,0); } }
注意事项
- 确保
FCOORD结构体的成员定义正确,与鼠标坐标的转换逻辑匹配 - 若使用Win32 API获取鼠标坐标,注意屏幕坐标与客户区坐标的转换(可使用
ScreenToClient函数) BOOL类型在Win32中定义为int,返回值应使用TRUE/FALSE而非-1,避免逻辑判断错误
内容的提问来源于stack exchange,提问作者Sammy1410
相关产品推荐
相关产品推荐

