【问题标题】:Text input box in SDLSDL 中的文本输入框
【发布时间】:2016-08-05 11:47:46
【问题描述】:

我想知道 SDL 中是否有与 Javascript 的 prompt() 函数等效的功能。如果你不懂 Javascript,这里是 Javascript prompt() 的截图:

所以我想要的是 SDL 的一个函数,它打开一个类似上面的对话框并返回一个字符串,其中包含用户键入的内容(或在参数中获取指向字符串的指针并将用户键入的内容放入该字符串)。

如何在 SDL 中做到这一点?

【问题讨论】:

  • SDL 不是 GUI 小部件工具包。它可以处理绘图、整体键盘/鼠标输入、计时等。但它不提供任何现成的 GUI 控件或其他元素。使用 GUI 小部件工具包。如果你正确地指导它,任何好的“与 SDL 一起工作”。
  • @underscore_d SDL_ShowSimpleMessageBox() 是 SDL2,它做了类似的事情。为什么会有显示消息框而不显示文本输入框的方法?
  • 我怎么知道?我没写。但是,在 SDL 支持的各种平台上打开一个基本对话框要通用得多——而不是创建一个具有平台相关文本输入、平台相关按钮等的窗口以及用于检测动作的平台相关机制并获取输入的值。这就是 GUI 小部件工具包的范畴。
  • 这是我的怀疑。在评估工具包时,还请查看 GTK+/gtkmm/[在此处插入其他 GTK+ 绑定],这是一个很棒的跨平台工具包,具有许多出色的功能和各种令人兴奋的开发内容(即不要相信互联网上的恐惧,并且我没有从属关系,等等等等)。
  • @underscore_d 感谢您提供有关使用 GTK+ 的提示。我以前不知道 GTK+,我刚刚学会了如何安装和使用它,我发现它比 QT 或 WxWidgets 更容易安装。但是我在尝试将 SDL 窗口和 GTK+ 窗口组合在同一个程序中时遇到了一些问题。我就这个问题问了here 一个问题。

标签: c sdl sdl-2


【解决方案1】:

也许可以试试像 here 提到的 nanogui-sdl 这样的 SDL 特定库

【讨论】:

  • 看起来不错,但它是 C++。 OP 只标记了 C。由此,他们只能按照大体思路寻找 inside-SDL 工具包。
【解决方案2】:

这是输入小部件的代码。

#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>

int windowWidth = 240;
int windowHeight = 320;
SDL_Point mousePos;
SDL_Point realMousePos;
bool keys[SDL_NUM_SCANCODES];
bool buttons[SDL_BUTTON_X2 + 1];
SDL_Renderer* renderer;

int SDL_QueryTextureF(SDL_Texture* texture, Uint32* format, int* access, float* w, float* h)
{
    int wi, hi;
    int result = SDL_QueryTexture(texture, format, access, &wi, &hi);
    if (w) {
        *w = wi;
    }
    if (h) {
        *h = hi;
    }
    return result;
}

SDL_Texture* renderText(SDL_Texture* previousTexture, TTF_Font* font, SDL_Renderer* renderer, const std::string& text, SDL_Color color)
{
    if (previousTexture) {
        SDL_DestroyTexture(previousTexture);
    }
    SDL_Surface* surface;
    if (text.empty()) {
        surface = TTF_RenderUTF8_Blended(font, " ", color);
    }
    else {
        surface = TTF_RenderUTF8_Blended(font, text.c_str(), color);
    }
    if (surface) {
        SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
        SDL_FreeSurface(surface);
        return texture;
    }
    else {
        return 0;
    }
}

struct Text {
    std::string text;
    SDL_Surface* surface = 0;
    SDL_Texture* t = 0;
    SDL_FRect dstR{};
    bool autoAdjustW = false;
    bool autoAdjustH = false;
    float wMultiplier = 1;
    float hMultiplier = 1;

    ~Text()
    {
        if (surface) {
            SDL_FreeSurface(surface);
        }
        if (t) {
            SDL_DestroyTexture(t);
        }
    }

    Text()
    {

    }

    Text(const Text& rightText)
    {
        text = rightText.text;
        if (surface) {
            SDL_FreeSurface(surface);
        }
        if (t) {
            SDL_DestroyTexture(t);
        }
        if (rightText.surface) {
            surface = SDL_ConvertSurface(rightText.surface, rightText.surface->format, SDL_SWSURFACE);
        }
        if (rightText.t) {
            t = SDL_CreateTextureFromSurface(renderer, surface);
        }
        dstR = rightText.dstR;
        autoAdjustW = rightText.autoAdjustW;
        autoAdjustH = rightText.autoAdjustH;
        wMultiplier = rightText.wMultiplier;
        hMultiplier = rightText.hMultiplier;
    }

    Text& operator=(const Text& rightText)
    {
        text = rightText.text;
        if (surface) {
            SDL_FreeSurface(surface);
        }
        if (t) {
            SDL_DestroyTexture(t);
        }
        if (rightText.surface) {
            surface = SDL_ConvertSurface(rightText.surface, rightText.surface->format, SDL_SWSURFACE);
        }
        if (rightText.t) {
            t = SDL_CreateTextureFromSurface(renderer, surface);
        }
        dstR = rightText.dstR;
        autoAdjustW = rightText.autoAdjustW;
        autoAdjustH = rightText.autoAdjustH;
        wMultiplier = rightText.wMultiplier;
        hMultiplier = rightText.hMultiplier;
        return *this;
    }

    void setText(SDL_Renderer* renderer, TTF_Font* font, std::string text, SDL_Color c = { 255,255,255 })
    {
        this->text = text;
#if 1 // NOTE: renderText
        if (surface) {
            SDL_FreeSurface(surface);
        }
        if (t) {
            SDL_DestroyTexture(t);
        }
        if (text.empty()) {
            surface = TTF_RenderUTF8_Blended(font, " ", c);
        }
        else {
            surface = TTF_RenderUTF8_Blended(font, text.c_str(), c);
        }
        if (surface) {
            t = SDL_CreateTextureFromSurface(renderer, surface);
        }
#endif
        if (autoAdjustW) {
            SDL_QueryTextureF(t, 0, 0, &dstR.w, 0);
        }
        if (autoAdjustH) {
            SDL_QueryTextureF(t, 0, 0, 0, &dstR.h);
        }
        dstR.w *= wMultiplier;
        dstR.h *= hMultiplier;
    }

    void setText(SDL_Renderer* renderer, TTF_Font* font, int value, SDL_Color c = { 255,255,255 })
    {
        setText(renderer, font, std::to_string(value), c);
    }

    void draw(SDL_Renderer* renderer)
    {
        if (t) {
            SDL_RenderCopyF(renderer, t, 0, &dstR);
        }
    }
};

std::string ucs4ToUtf8(const std::u32string& in)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
    return conv.to_bytes(in);
}

std::u32string utf8ToUcs4(const std::string& in)
{
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv;
    return conv.from_bytes(in);
}

void utf8Insert(std::string& buffer, int index, std::string text)
{
    std::u32string u32Buffer = utf8ToUcs4(buffer);
    if (index > u32Buffer.size()) {
        index = u32Buffer.size();
    }
    u32Buffer.insert(index, utf8ToUcs4(text));
    buffer = ucs4ToUtf8(u32Buffer);
}

std::string utf8Substr(const std::string& str, unsigned int start, unsigned int leng)
{
    std::u32string s = utf8ToUcs4(str);
    return ucs4ToUtf8(s.substr(start, leng));
}

std::size_t utf8GetSize(std::string buffer)
{
    std::u32string str = utf8ToUcs4(buffer);
    return str.size();
}

void utf8Erase(std::string& buffer, int index)
{
    buffer = utf8Substr(buffer, 0, index) + utf8Substr(buffer, index + 1, std::string::npos);
}

struct Input {
    SDL_Rect r{};
    Text text;
    SDL_Rect cursorR{};
    int currentLetter = 0;
    std::u32string left;
    std::u32string right;
    bool isPassword = false;
    bool isSelected = false;

    void handleEvent(SDL_Event event, TTF_Font* font)
    {
        if (event.type == SDL_KEYDOWN) {
            if (event.key.keysym.scancode == SDL_SCANCODE_BACKSPACE) {
                if (currentLetter) {
                    utf8Erase(text.text, currentLetter - 1);
                    if (!right.empty()) {
                        std::u32string s = utf8ToUcs4(text.text);
                        s.push_back(right.front());
                        right.erase(0, 1);
                        text.text = ucs4ToUtf8(s);
                    }
                    else if (!left.empty()) {
                        std::u32string s = utf8ToUcs4(text.text);
                        s.insert(0, 1, left.back());
                        left.pop_back();
                        text.text = ucs4ToUtf8(s);
                    }
                    else {
                        --currentLetter;
                    }
                    text.setText(renderer, font, text.text, {});
                }
            }
            else if (event.key.keysym.scancode == SDL_SCANCODE_LEFT) {
                if (currentLetter) {
                    --currentLetter;
                }
                else {
                    if (!left.empty()) {
                        std::u32string s = utf8ToUcs4(text.text);
                        s.insert(s.begin(), left.back());
                        left.pop_back();
                        right.insert(right.begin(), s.back());
                        s.pop_back();
                        text.setText(renderer, font, ucs4ToUtf8(s), {});
                    }
                }
            }
            else if (event.key.keysym.scancode == SDL_SCANCODE_RIGHT) {
                if (currentLetter != utf8ToUcs4(text.text).size()) {
                    ++currentLetter;
                }
                else {
                    if (!right.empty()) {
                        std::u32string s = utf8ToUcs4(text.text);
                        s.push_back(right.front());
                        right.erase(0, 1);
                        left.push_back(s.front());
                        s.erase(0, 1);
                        text.setText(renderer, font, ucs4ToUtf8(s), {});
                    }
                }
            }
        }
        else if (event.type == SDL_TEXTINPUT) {
            utf8Insert(text.text, currentLetter, event.text.text);
            text.setText(renderer, font, text.text, {});
            ++currentLetter;
            while (text.dstR.x + text.dstR.w > r.x + r.w) {
                --currentLetter;
                left.push_back(utf8ToUcs4(text.text)[0]);
                utf8Erase(text.text, 0);
                text.setText(renderer, font, text.text, {});
            }
        }
    }

    void draw(SDL_Renderer* renderer, TTF_Font* font)
    {
        SDL_SetRenderDrawColor(renderer, 255, 255, 255, 0);
        SDL_RenderFillRect(renderer, &r);
        if (isPassword) {
            std::string currPassword = text.text;
            text.setText(renderer, font, std::string(utf8GetSize(currPassword), '*'), {});
            text.draw(renderer);
            text.setText(renderer, font, currPassword, {});
        }
        else {
            text.draw(renderer);
        }
        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 0);
        Text t = text;
        t.text = utf8Substr(t.text, 0, currentLetter);
        t.setText(renderer, font, t.text, {});
        if (currentLetter) {
            cursorR.x = t.dstR.x + t.dstR.w;
        }
        else {
            cursorR.x = t.dstR.x;
        }
        if (isSelected) {
            SDL_RenderFillRect(renderer, &cursorR);
        }
    }
};

int main(int argc, char* argv[])
{
    SDL_Init(SDL_INIT_EVERYTHING);
    TTF_Init();
    SDL_Window* window = SDL_CreateWindow("TextEditInput", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, SDL_WINDOW_RESIZABLE);
    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    TTF_Font* robotoF = TTF_OpenFont("res/roboto.ttf", 72);
    int w, h;
    SDL_GetWindowSize(window, &w, &h);
    SDL_RenderSetScale(renderer, w / (float)windowWidth, h / (float)windowHeight);
    bool running = true;
    Input input;
    input.r.w = 200;
    input.r.h = 30;
    input.r.x = windowWidth / 2 - input.r.w / 2;
    input.r.y = windowHeight / 2.f - input.r.h - 10;
    input.text.dstR.w = input.r.w;
    input.text.dstR.h = input.r.h;
    input.text.dstR.x = input.r.x;
    input.text.dstR.y = input.r.y;
    input.text.autoAdjustW = true;
    input.text.wMultiplier = 0.5;
    input.cursorR.w = 8;
    input.cursorR.h = input.r.h - 2;
    input.cursorR.x = input.r.x;
    input.cursorR.y = input.r.y + input.r.h / 2 - input.cursorR.h / 2;
    input.isSelected = true;
    while (running) {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            input.handleEvent(event, robotoF);
            if (event.type == SDL_QUIT || event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
                running = false;
            }
        }
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
        SDL_RenderClear(renderer);
        input.draw(renderer, robotoF);
        SDL_RenderPresent(renderer);
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 2016-05-15
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多