使用SDL2调整无边框窗口大小时出错

时间:2014-03-29 00:06:01

标签: c++ winapi sdl x11 sdl-2

我正在尝试使用SDL2中的无边框窗口创建应用程序。

我通过拖动实现了移动和调整大小。移动工作非常好。通过拖动底部和右边框来调整大小也很正常。

通过拖动顶部和左侧边框功能来调整大小,但它有一个装饰性的错误。

基本上,如果我从左边框拖动,窗口的右侧在移动时会产生很小的跳跃(可能是1-2个像素)。从顶部边框拖动会导致底部跳跃。当我停止拖动窗口总是在正确的位置,但这个错误使它看起来非常不优雅。

Linux(多个WM / DE)和Windows上存在该错误。我没有在OS X上测试过。

我正在使用SDL_SetWindowPositionSDL_SetWindowSize。我试过绕过SDL并使用XMoveResizeWindow,但它会导致同样的错误。

虽然我强烈不想绕过SDL,但如果需要,我愿意使用Xlib和/或WinAPI。

以下是我的代码片段:

// mousePos is initialized to current mouse pos
// newWindowSize initilized to current window size
// newWindowPos initialized to current window position
// mWindowResizeOffset variable is where the mouse grabbed the window

// omitted code for right and bottom borders because the bug doesn't exist there

// Logic for the top border is the same
if (mLeftBorderGrabbed)
{
    newWindowPos.x = mousePos.x - mWindowResizeOffset.x;
    newWindowSize.x += windowPos.x - newWindowPos.x;
}

SDL_SetWindowPosition(mInternalWindow, newWindowPos.x, newWindowPos.y);
SDL_SetWindowSize(mInternalWindow, newWindowSize.x, newWindowSize.y);

1 个答案:

答案 0 :(得分:5)

我选择了SDL2并花了最后几个小时尝试不同的窗口移动/大小调整/重绘API:

SDL_SetWindowPosition(window, newWindowPos.x, newWindowPos.y);
SDL_SetWindowSize(window, newWindowSize.x, newWindowSize.y);

SetWindowPos(windowHandle, nullptr, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, SWP_SHOWWINDOW);

MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);

MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);
InvalidateRect(windowHandle, &windowRect, TRUE);

我已经了解到SDL API可以通过缓慢的小拖动来实现,但更大,更快的拖动会触发您描述的视觉故障。

SetWindowPosMoveWindow似乎几乎完全相同 - 在我的系统上都能正常工作。在拖动过程中窗口的左边缘会出现一些毛刺,但这与我系统上其他窗口的行为一致。右边缘在视觉上固定在原位,没有毛刺。我可能会选择MoveWindow调用永久解决方案,尽管这主要是基于不同API设置如何运行的直觉。 YMMV。

InvalidateRect似乎没有对事物的绘制方式产生任何影响。它不会加剧我提到的左边界故障,也不会减轻它。我猜这是因为我为MoveWindow调用指定了重绘标记。

供参考,这是我用于测试的代码。我只是评论/取消评论相关API并根据需要重建项目。对于混乱感到抱歉 - 我更感兴趣的是获得一些东西,而不是让代码看起来更完美。如果您想要我清理它,请告诉我。

//Using SDL and standard IO
#include <windows.h>
#include <SDL.h>
#include <SDL_syswm.h>
#include <stdio.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

struct Point
{
  int x;
  int y;
};

int main(int argc, char* args[])
{
  bool quit = false, dragging = false;
  //The window we'll be rendering to
  SDL_Window* window = NULL;

  //The surface contained by the window
  SDL_Surface* screenSurface = NULL;

  SDL_Event e;

  SDL_SysWMinfo windowInfo;
  HWND windowHandle;

  Point mousePos, windowPos, newWindowPos, newWindowSize, mWindowResizeOffset;

  //Initialize SDL
  if(SDL_Init(SDL_INIT_VIDEO) < 0)
  {
    printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
  }
  else
  {
    //Create window
    window = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS);   // | SDL_WINDOW_RESIZABLE
    if(window == NULL)
    {
      printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
    }
    else
    {
      //Get window surface
      screenSurface = SDL_GetWindowSurface(window);

      SDL_VERSION(&windowInfo.version);
      SDL_GetWindowWMInfo(window, &windowInfo);
      windowHandle = windowInfo.info.win.window;

      //While application is running
      while(!quit)
      {
        //Handle events on queue
        while(SDL_PollEvent(&e) != 0)
        {
          //process events
          switch(e.type)
          {
          case SDL_QUIT:
            quit = true;
            break;
          case SDL_WINDOWEVENT:
            if(e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)
            {
              screenSurface = SDL_GetWindowSurface(window);
            }
            //Fill the surface blue
            SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0x00, 0xA2, 0xE8));

            //Update the surface
            SDL_UpdateWindowSurface(window);
            break;
          case SDL_MOUSEBUTTONDOWN:
            SDL_GetMouseState(&mWindowResizeOffset.x, &mWindowResizeOffset.y);
            SDL_GetWindowPosition(window, &windowPos.x, &windowPos.y);
            dragging = true;
            break;
          case SDL_MOUSEBUTTONUP:
            dragging = false;
            break;
          case SDL_MOUSEMOTION:
            if(dragging)
            {
              SDL_GetMouseState(&mousePos.x, &mousePos.y);
              SDL_GetWindowPosition(window, &newWindowPos.x, &newWindowPos.y);
              SDL_GetWindowSize(window, &newWindowSize.x, &newWindowSize.y);

              newWindowPos.x = newWindowPos.x + mousePos.x - mWindowResizeOffset.x;
              newWindowSize.x += windowPos.x - newWindowPos.x;

              //SDL_SetWindowPosition(window, newWindowPos.x, newWindowPos.y);
              //SDL_SetWindowSize(window, newWindowSize.x, newWindowSize.y);
              //SetWindowPos(windowHandle, nullptr, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, SWP_SHOWWINDOW);
              MoveWindow(windowHandle, newWindowPos.x, newWindowPos.y, newWindowSize.x, newWindowSize.y, TRUE);

              /*RECT drawRect;
              drawRect.left = windowPos.x;
              drawRect.top = windowPos.y;
              drawRect.right = windowPos.x + newWindowSize.x;
              drawRect.bottom = windowPos.y + newWindowSize.y;

              InvalidateRect(windowHandle, &drawRect, TRUE);*/

              windowPos = newWindowPos;
            }
            break;
          }
        }

        SDL_Delay(1);
      }
    }
  }

  //Destroy window
  SDL_DestroyWindow(window);

  //Quit SDL subsystems
  SDL_Quit();

  return 0;
}