如何解决在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(),¤tCharacterWidth,¤tCharacterHeight);
///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,¤tCharacterRect) ){
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开始,这是我在文本类中创建字体的静态向量之前的第一行。这是我要解释的摘录:
这显然可以正常工作。
但是现在,这是完全不准确的。如果我在文本末尾选择了一个随机字符,则该字符没有正确突出显示,只是从头开始看起来就很完美,但随后看起来好像不准确了,因此使总的灰色突出显示范围更宽了比预期的要好。
解决方法
您的方法存在的问题是单个字符的宽度没有意义。渲染器根据上下文(渲染字符串中的它们的邻居)对其进行调整。因此,呈现的字符串i
中bit
的宽度不必与呈现的字符串i
中fil
的宽度相同。
查找文本选择坐标的方法需要考虑上下文。
说我们有三个字符串的宽度:
-
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 举报,一经查实,本站将立刻删除。