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; }
问题原因
- 事件字段访问错误:
moveRectangle函数接收的是SDL_MOUSEBUTTONDOWN事件,此时你访问的myEvent.motion.x/y是MOUSEMOTION事件专属字段,在MOUSEBUTTONDOWN事件中这些字段的值未定义(大概率是0)。判断点击区域应该用myEvent.button.x和myEvent.button.y,这才是鼠标按下时的有效坐标。 - 嵌套事件循环的不当处理:在
moveRectangle的循环里,每次调用SDL_PollEvent后不管事件类型是什么,都直接输出motion.x/y。当事件是MOUSEBUTTONUP、SDL_QUIT或其他非MOUSEMOTION事件时,motion字段数据不会更新,输出的要么是残留值,要么是默认的0,这就导致了大量(0,0)输出。 - 主循环与子函数的事件冲突:主循环和
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
相关产品推荐
相关产品推荐

