在SDL2,C ++中,TTF_SizeText没有为“ i”,“ j”和“ 1”到目前为止发现返回正确的值

如何解决在SDL2,C ++中,TTF_SizeText没有为“ i”,“ j”和“ 1”到目前为止发现返回正确的值

我有一个textBox类,可以很好地与a,b,c等较宽的字符配合使用,但是对于像'f'和'l'这样的字符,它似乎错误地获得了这些字符的大小,但正确地获得了其他尺寸?这是用于textBox类的文本的“突出显示代码,稍后会对其进行修正,但是应该对其进行记录以易于理解。

void TextBox::Highlight_Text(SDL_Renderer *renderer)
{
    if (clickedOn == true){


        int currentCharacterWidth = 0;
        int currentCharacterHeight = 0;
        int totalSize = 0;
        SDL_Rect currentCharacterRect;
        string currentCharacter,tempText;



        if (highlightedCharacters.size() >= 1){ ///To make sure only 1 thing is highlighted,in conjunction with next part
            highlighted = true;
        }

        if (highlighted == true){   /// if a part is highlighted,and is left highlighted,next time clicked,remove the highlighting and redo it
            if (EVENTS.mouseClicked == false){
                resetHighlightingNextClick = true;
            }
        }

        if (resetHighlightingNextClick == true){
            if (highlighted == true){
                if (EVENTS.mouseClicked == true){       ///actually remove the highlighting
                    highlightedCharacters.clear();
                    indexOfCharactersHighlighted.clear();
                    highlighted = false;
                    resetHighlightingNextClick = false;
                }
            }
        }



        for (int i=0; i < textBoxText.Get_Text().size(); i++){
            currentCharacter =  textBoxText.Get_Text()[i];
            TTF_SizeText(textBoxText.fonts[textBoxText.fontIndex],currentCharacter.c_str(),&currentCharacterWidth,&currentCharacterHeight);

            ///the totalSize added to rectangle is not making it wider,its adjusting its x value offset
            currentCharacterRect = {textBoxText.x + totalSize,textBoxText.y + int(textBoxText.textSize*0.1),currentCharacterWidth,currentCharacterHeight};
            totalSize += currentCharacterWidth; ///"current" size of text in loop to get x value of specific character clicked on

            ///If mouse is touching any of the characters in the text
            if ( SDL_PointInRect(&EVENTS.mousePos,&currentCharacterRect) ){
                EVENTS.Change_Cursor(SDL_SYstem_CURSOR_IBEAM);

                if (EVENTS.mouseClicked == true){   ///Clicking on the text to highlight
                    if (In_Array(highlightedCharacters,currentCharacterRect.x) == false  ){
                        highlightedCharacters.push_back(currentCharacterRect);  ///If there is no duplicates
                        indexOfCharactersHighlighted.push_back(i); ///Get index of text being highlighted,its always in order too

                    }

                    if (  currentCharacterRect.x != highlightedCharacters[highlightedCharacters.size()-1].x){ ///So they don't stack up highlights,ie,you can remove them
                        /// If the mouse is not highlighting the last one,say second last on the right for example,delete the one in front of it (last one)
                        ///Like when highlighting text with mouse,it adapts to how you move it,so it unhighlights text not being highlighted
                        highlightedCharacters.pop_back();
                        indexOfCharactersHighlighted.pop_back();

                    }
                }

            }

        }///End for loop




        if (highlighted == true ){
            if (EVENTS.backspacepressed == true || EVENTS.currentKey != ""){
                tempText = textBoxText.Get_Text();

                ///remove highlighted characters
                if (indexOfCharactersHighlighted.size() != 0){
                    ///the range of values highlighted will always be in a sorted order
                    tempText.erase( Min(indexOfCharactersHighlighted),Max(indexOfCharactersHighlighted)-Min(indexOfCharactersHighlighted)+1  );  ///erase the range of values highlighted
                    textBoxText.Change_Text(renderer,tempText);

                    ///once removed text,clear every highlighted related thing
                    highlightedCharacters.clear();
                    indexOfCharactersHighlighted.clear();
                    highlighted = false;
                    resetHighlightingNextClick = false;

                    EVENTS.backspacepressed = false;
                    EVENTS.currentKey = "";
                }

            }
        }



    }   ///End if for clicked on



    ///fit with scrolling offsets
    if (EVENTS.scrolled == true){
        for (int p=0; p < highlightedCharacters.size(); p++){
            highlightedCharacters[p].y += EVENTS.scrollVal;
        }
    }




    ///Drawing the highlighted text
    if (highlighted == true   &&   clickedOn == true){
        SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_BLEND);
        SDL_SetRenderDrawColor(renderer,55,60,65,75);
        for (int j=0; j < highlightedCharacters.size(); j++){
            SDL_RenderFillRect(renderer,&highlightedCharacters[j]);
        }
        SDL_SetRenderDrawBlendMode(renderer,SDL_BLENDMODE_NONE);
    }


    ///when clicked off textBox,clear everything/highlighting
    if (clickedOn == false){
        highlightedCharacters.clear();
        indexOfCharactersHighlighted.clear();
        highlighted = false;
    }



}

要以传入的字体作为参考,这是我在文本类中获取它的方式

    fontIndex = textSize-lowestFontSize  -1;

    ///One time setups
    if (numOfInstances == 1){
        try{
            TTF_Init();
            //cout << "Initialised ttf" << endl;
        }
        catch (exception &err){
            cout << "Could not initialise ttf for text \"" << text << "\". Error from SDL is: " << TTF_GetError() << ". Error from C++ is: " << err.what() << endl;
        }

        for (int i=lowestFontSize; i <= highestFontSize; i++){
            TTF_Font *currentFont = TTF_OpenFont(fontType.c_str(),i);
            if (!currentFont){
                cout << "Error with font in text \"" << txt << "\" Error is: " << SDL_GetError() << endl;
            }

            fonts.push_back(currentFont);
        }

    }

,所以如果我传入,例如说25作为我的文本大小,则我有我的lowestFontSize = 10和highestFontSize = 100,所以我需要25号的索引是(25-10 -1 = 14)从0开始,这是我在文本类中创建字体的静态向量之前的第一行。这是我要解释的摘录:

enter image description here

这显然可以正常工作。

enter image description here

但是现在,这是完全不准确的。如果我在文本末尾选择了一个随机字符,则该字符没有正确突出显示,只是从头开始看起来就很完美,但随后看起来好像不准确了,因此使总的灰色突出显示范围更宽了比预期的要好。

解决方法

您的方法存在的问题是单个字符的宽度没有意义。渲染器根据上下文(渲染字符串中的它们的邻居)对其进行调整。因此,呈现的字符串ibit的宽度不必与呈现的字符串ifil的宽度相同。

查找文本选择坐标的方法需要考虑上下文。

说我们有三个字符串的宽度:

  • prefixWidth是前缀的大小(文本的原始行,直到但不包括所选内容)
  • selWidth是所选内容的宽度
  • totalWidth是前缀和所选内容串联的宽度

(我们不在乎选择后的部分)。前两个宽度将接近第三个宽度,但由于前缀的最后一个字符与所选内容的第一个字符之间的字距调整而不会相加。区别在于您需要对渲染的选择的X坐标应用校正。因此,我们需要从X坐标开始渲染选择,该坐标不是prefixWidth,而是

prefixWidth + (totalWidth - (prefixWidth + selWidth))

相同
totalWidth - selWidth

因此您实际上根本不需要计算prefixWidth。

下面是一个完整的(半)工作示例程序。参数是(1)字体文件的完整路径(2)字体大小(3)要呈现的字符串(4)选择开始(5)选择长度。选择内容将显示在原始文本的顶部,并向右和向右移动1个像素,因此很容易查看是否存在偏差。

#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

char* substr(const char* src,int fromChar,int subLen)
{
    if (subLen < 0 || fromChar < 0 || fromChar + subLen > (int)strlen(src))
    {
        fprintf (stderr,"invalid substring\n");
        exit (EXIT_FAILURE);
    }

    char* z = (char*)malloc(subLen);
    strncpy(z,src + fromChar,subLen);
    z[subLen] = '\0';
    return z;
}

void textExtent(TTF_Font* font,const char* text,int subLen,int* w,int* h)
{
    int l = strlen(text);
    if (subLen == -1) subLen = l;
    if (fromChar < 0 || subLen > l)
    {
        fprintf (stderr,"Bad text extent\n");
        exit (EXIT_FAILURE);
    }

    char* z = substr(text,fromChar,subLen);

    TTF_SizeUTF8(font,z,w,h);

    free(z);
}

int textWidth(TTF_Font* font,int subLen)
{
    int w,h;
    textExtent(font,text,subLen,&w,&h);
    return w;
};

int main(int argc,char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    TTF_Init();

    if (argc != 6)
    {
        fprintf (stderr,"usage: %s font text from length\n",argv[0]);
        exit(EXIT_FAILURE);
    }

    const char* fontpath = argv[1];
    int fontSz = atoi(argv[2]);
    const char* txt = argv[3];
    int from = atoi(argv[4]);
    int len = atoi(argv[5]);

    int tsize = strlen(txt);
    if (from < 0 || from + len >= tsize)
    {
        fprintf (stderr,"Invalid text portion to highlight\n");
        exit (EXIT_FAILURE);
    }

    if (fontSz < 2 || fontSz > 300)
    {
        fprintf (stderr,"Invalid font size\n");
        exit (EXIT_FAILURE);
    }

    // open font to render with

    TTF_Font * font = TTF_OpenFont(fontpath,fontSz);
    if (!font)
    {
        fprintf (stderr,"Could not open font %s\n",fontpath);
        exit (EXIT_FAILURE);
    }

    // Query text size
    int textW,textH;
    textExtent(font,txt,-1,&textW,&textH);

    SDL_Window * window = SDL_CreateWindow("SDL_ttf in SDL2",SDL_WINDOWPOS_UNDEFINED,textW,textH,0);

    // Query selection coords
    //
    int selWidth = textWidth(font,from,len);
    int totalWidth = textWidth(font,from+len);

    // Render portions of text

    SDL_Renderer * renderer = SDL_CreateRenderer(window,0);
    SDL_Color color = { 255,128,0 };
    SDL_Surface * surface = TTF_RenderUTF8_Blended(font,color);
    SDL_SetSurfaceBlendMode(surface,SDL_BLENDMODE_BLEND);
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,surface);
    SDL_SetTextureBlendMode(texture,SDL_BLENDMODE_BLEND);

    SDL_Rect dstrect = { 0,textH };

    SDL_Color color2 = { 0,255,128 };

    char* s = substr(txt,len);
    SDL_Surface * surface2 = TTF_RenderUTF8_Blended(font,s,color2);
    free(s);
    SDL_SetSurfaceBlendMode(surface,SDL_BLENDMODE_BLEND);
    SDL_Texture * texture2 = SDL_CreateTextureFromSurface(renderer,surface2);
    SDL_SetTextureAlphaMod(texture2,128);
    SDL_SetTextureBlendMode(texture2,SDL_BLENDMODE_BLEND);
    SDL_Rect dstrect2 = {totalWidth - selWidth + 1,1,selWidth,textH };

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
            case SDL_QUIT:
                quit = true;
                break;
        }

        SDL_SetRenderDrawColor(renderer,0);
        SDL_RenderClear(renderer);

        SDL_RenderCopy(renderer,texture,NULL,&dstrect);
        SDL_RenderCopy(renderer,texture2,&dstrect2);

        //Update screen
        SDL_RenderPresent(renderer);

    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_DestroyTexture(texture);
    SDL_FreeSurface(surface);
    TTF_CloseFont(font);
    TTF_Quit();
    SDL_Quit();

    return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?