【问题标题】:SDL2: How to keep aspect ratio when resizing the windowSDL2:调整窗口大小时如何保持纵横比
【发布时间】:2015-02-18 15:45:00
【问题描述】:

我正在尝试创建一个在调整大小事件发生时保持其纵横比的 SDL 窗口。如果用户加宽窗口,则高度增加,反之亦然。我捕捉到 SDL_WINDOWEVENT_RESIZED 事件,计算保持纵横比的新宽度或高度,然后使用计算值调用 SDL_SetWindowSize()。

问题是在事件轮询循环中调用 SDL_SetWindowSize() 函数在屏幕上没有任何作用。 SDL 确实更新了窗口大小变量(在我的主循环中调用 SDL_GetWindowSize() 返回更新的窗口尺寸)。但是,实际窗口没有更新。

我可以让它工作的唯一方法是在主循环中不断调用 SDL_SetWindowSize(),但我认为这是错误的做事方式。下面的代码说明了我的问题。有没有更好、更清洁的方法来让它发挥作用?

我在 GNOME 桌面上使用 SDL 2.0.3 和 64 位 Ubuntu Linux。

#include <SDL2/SDL.h>

static const float ASPECT_RATIO = 16.f/9.f;

SDL_Window* window;
SDL_Renderer* renderer;

uint32_t windowID;
SDL_Rect screen;
bool done = false;
bool resizeDone = false;

void handle_events()
{
    SDL_Event e;
    while (SDL_PollEvent(&e)) {
        switch (e.type) {

        case SDL_WINDOWEVENT: 
            if(e.window.windowID == windowID) {
                switch(e.window.event) {
                    case SDL_WINDOWEVENT_RESIZED: { 
                        int width = e.window.data1;
                        int height = e.window.data2;
                        float aspectRatio = (float)width/(float)height;

                        if(aspectRatio != ASPECT_RATIO) {
                            if(aspectRatio > ASPECT_RATIO) {
                                height = (1.f / ASPECT_RATIO) * width; 
                            }
                            else {
                                width = ASPECT_RATIO * height; 
                            }

                            printf("Setting window size to %d, %d, aspect ratio: %f\n", 
                                width, height, (float)width/(float)height);
                    }
                    screen.w = width;
                    screen.h = height; 

                    SDL_SetWindowSize(window, width, height); // <-- does not work
                    resizeDone = true;
                    break;
                    }
                }
             }
             break;

        case SDL_QUIT:
            done = true;
            break;

        default:
            break;
        }
    }   
}

void run() {
    while(!done) {
        //SDL_SetWindowSize(window, screen.w, screen.h); // <-- works
        handle_events();
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);

        if(resizeDone) {
            int w, h;
            SDL_GetWindowSize(window, &w, &h);
            printf("SDL_GetWindowSize: %d, %d\n", w, h);
            resizeDone = false;
        }
    }
}

int main(int, char**) {
    SDL_Init(SDL_INIT_VIDEO);
    uint32_t window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
    window = SDL_CreateWindow("Test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
    windowID = SDL_GetWindowID(window);
    renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    run();
    SDL_Quit();
    return 0;
}

【问题讨论】:

  • 对我有用,但它可能依赖于窗口管理器(甚至是合成)。无论如何,您的 if(resizeDone) 看起来是一个更好的地方来进行实际调整大小;事件处理应该只引发需要执行调整大小的标志。
  • @keltar:你用什么系统测试过这个?无论如何,感谢您的建议,我尝试与其他窗口管理器一起使用。 if (resizeDone) 确实是调整大小的更好地方,但在我当前的设置下,如果从那里进行调用,窗口的大小不会调整为正确的纵横比。

标签: c++ linux sdl sdl-2


【解决方案1】:

一些窗口管理器似乎忽略了 WM 本身调整窗口大小时发出的调整大小请求(例如,在按住鼠标按钮时)。相反,SDL_GetWindowSize 返回缓存值,在这种特定情况下,有时恰好是错误的。

除了在每一帧上不断调用SDL_SetWindowSize 以防万一之外,我没有看到任何独立于平台的方法来实现这一点。不过,它可以使用特定于平台的 API 来实现(例如 SDL_GetWindowSysWMInfo,然后使用 Xlib)。

【讨论】:

  • 我用示例代码快速测试了一些窗口管理器。 GNOME 和 XFCE 不能正常工作,Unity 工作正常。
  • 是的,我最初的测试是使用 openbox。
  • 有什么例子吗?
【解决方案2】:

ma​​cOS 上,我是这样解决的:

可可.m:

#import <Cocoa/Cocoa.h>

void SetWindowRatio(void *window) {
    NSWindow *win = (__bridge NSWindow*) window;
    win.aspectRatio = NSMakeSize( 1280, 720 );
}

main.cpp:

#include <SDL.h>
#include <SDL_syswm.h>

extern "C" void SetWindowRatio(void *window);

// and later..

SDL_SysWMinfo wmInfo;
SDL_VERSION(&wmInfo.version);
SDL_GetWindowWMInfo(sdl.window, &wmInfo);
SetWindowRatio(wmInfo.info.cocoa.window);

也许可以在 Linux 上做类似的事情,只访问 wmInfo.info 的不同部分。并调用原生函数?

【讨论】:

    猜你喜欢
    • 2021-10-05
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多