You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

结构体指针类型转换及跨函数传递:鼠标悬停检测场景问题

鼠标悬停检测功能的正确实现方案

问题说明

已定义存储圆形、矩形数据的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 19:55:17