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

SDL中鼠标按住时位置频繁显示(0,0)问题求助

问题描述

需求是在窗口中间放置一个红色正方形,按下该正方形后,按住鼠标按键期间持续输出鼠标位置,松开按键则停止输出。但运行代码时,单次点击会先多次输出鼠标位置为(0,0),再输出正确坐标,随后又多次输出(0,0)。

原代码如下:

#include <stdio.h>
#include <SDL.h>

#define WIDTH 760
#define HEIGHT 480


void moveRectangle(SDL_Event myEvent, SDL_Rect* pButton, SDL_Renderer* pRenderer) {

  if (myEvent.motion.x >= 330 && myEvent.motion.x <= 430 && myEvent.motion.y >= 190 && 
     myEvent.motion.y <= 290) {
     while (myEvent.type != SDL_MOUSEBUTTONUP) {
        SDL_PollEvent(&myEvent);
        printf("Mouse position is (%d, %d)\n", myEvent.motion.x, myEvent.motion.y);
     }
    printf("Mouse released!\n");
  }
} 

int main(int argc, char** args) {

   int running = 1;

   SDL_Window* window;
   SDL_Rect myButton;
   SDL_Renderer* myRenderer;
   SDL_Event event;

   myButton.x = 330;
   myButton.y = 190;
   myButton.w = 100;
   myButton.h = 100;

   SDL_Init(SDL_INIT_VIDEO);

   window = SDL_CreateWindow("Events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
   WIDTH, HEIGHT, 0);
   myRenderer = SDL_CreateRenderer(window, -1, 0);

   SDL_SetRenderDrawColor(myRenderer, 255, 0, 0, 0);
   SDL_RenderFillRect(myRenderer, &myButton);

   SDL_RenderPresent(myRenderer);

   while (running) {
      SDL_PollEvent(&event);
       switch (event.type) {
          case SDL_MOUSEBUTTONDOWN: printf("Mouse press detected!\n"); 
                moveRectangle(event, &myButton, myRenderer); break;
          case SDL_MOUSEBUTTONUP: printf("Mouse release detected!\n"); break;
          case SDL_MOUSEMOTION: printf("Mouse movement detected!\n"); break;
          case SDL_QUIT: printf("Exiting...\n"); running = 0;  break;
       }
    }

   SDL_DestroyRenderer(myRenderer);
   SDL_Quit();

   return 0;
}
问题原因
  1. 事件字段访问错误:moveRectangle函数接收的是SDL_MOUSEBUTTONDOWN事件,此时你访问的myEvent.motion.x/y是MOUSEMOTION事件专属字段,在MOUSEBUTTONDOWN事件中这些字段的值未定义(大概率是0)。判断点击区域应该用myEvent.button.x和myEvent.button.y,这才是鼠标按下时的有效坐标。
  2. 嵌套事件循环的不当处理:在moveRectangle的循环里,每次调用SDL_PollEvent后不管事件类型是什么,都直接输出motion.x/y。当事件是MOUSEBUTTONUP、SDL_QUIT或其他非MOUSEMOTION事件时,motion字段数据不会更新,输出的要么是残留值,要么是默认的0,这就导致了大量(0,0)输出。
  3. 主循环与子函数的事件冲突:主循环和moveRectangle里的循环都调用SDL_PollEvent,事件队列被两个循环交替读取,部分事件被错误处理,进一步加剧了坐标输出异常。
修复方案

放弃嵌套事件循环,改用状态标志在主循环中统一处理逻辑,同时正确访问事件字段:

#include <stdio.h>
#include <SDL.h>

#define WIDTH 760
#define HEIGHT 480

int main(int argc, char** args) {
    int running = 1;
    // 新增标志:记录是否按住正方形
    int holding_button = 0;

    SDL_Window* window;
    SDL_Rect myButton;
    SDL_Renderer* myRenderer;
    SDL_Event event;
    int mouse_x, mouse_y;

    myButton.x = 330;
    myButton.y = 190;
    myButton.w = 100;
    myButton.h = 100;

    SDL_Init(SDL_INIT_VIDEO);

    window = SDL_CreateWindow("Events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
                              WIDTH, HEIGHT, 0);
    myRenderer = SDL_CreateRenderer(window, -1, 0);

    SDL_SetRenderDrawColor(myRenderer, 255, 0, 0, 255); // 修正alpha值为255(不透明)
    SDL_RenderFillRect(myRenderer, &myButton);
    SDL_RenderPresent(myRenderer);

    while (running) {
        while (SDL_PollEvent(&event)) { // 用while处理所有待处理事件
            switch (event.type) {
                case SDL_MOUSEBUTTONDOWN:
                    printf("Mouse press detected!\n");
                    // 用button事件的坐标判断是否点击在正方形内
                    if (event.button.x >= myButton.x && event.button.x <= myButton.x + myButton.w &&
                        event.button.y >= myButton.y && event.button.y <= myButton.y + myButton.h) {
                        holding_button = 1;
                        // 获取初始按下位置
                        SDL_GetMouseState(&mouse_x, &mouse_y);
                        printf("Mouse position is (%d, %d)\n", mouse_x, mouse_y);
                    }
                    break;
                case SDL_MOUSEBUTTONUP:
                    printf("Mouse release detected!\n");
                    if (holding_button) {
                        holding_button = 0;
                        printf("Mouse released!\n");
                    }
                    break;
                case SDL_QUIT:
                    printf("Exiting...\n");
                    running = 0;
                    break;
            }
        }

        // 如果按住按钮,持续获取并输出鼠标位置
        if (holding_button) {
            SDL_GetMouseState(&mouse_x, &mouse_y);
            printf("Mouse position is (%d, %d)\n", mouse_x, mouse_y);
            // 可选:添加延迟避免输出过快
            SDL_Delay(10);
        }
    }

    SDL_DestroyRenderer(myRenderer);
    SDL_DestroyWindow(window); // 补原代码遗漏的窗口销毁
    SDL_Quit();

    return 0;
}

修改说明:

  • 新增holding_button标志,在主循环统一管理状态,避免嵌套事件循环。
  • 判断点击区域时使用SDL_MOUSEBUTTONDOWN事件的button.x/y字段,确保坐标有效。
  • 按住按钮时,用SDL_GetMouseState直接获取当前鼠标位置,而非依赖事件的motion字段,保证坐标实时正确。
  • 修复原代码中alpha值为0的问题(原红色正方形透明,改为255才会显示红色)。
  • 补上原代码遗漏的SDL_DestroyWindow调用,避免资源泄漏。

内容的提问来源于stack exchange,提问作者Alexander Jonsson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:05:03