I was wondering how i get the dimensions of my text in SFML?
I tried to do it like this:
sf::Text text("Hello SFML", font, 50);
// using text.getRect()
// i also tried getScale() & getSize()
// neither are correct
text.setPosition( window.getSize().y/2 - text.getRect().y,50 );
Does any one know ?
Thanks :)
Looking at the documentation it seems like the function
getLocalBounds could be of use to you. The line would be:
float width = text.getLocalBounds().width;
I'm not sure if the sf::Text object would add any padding on the ends of the bounding rectangle.
Alternatively, you could make use of findCharacterPos with something like:
float width = text.findCharacterPos(numChars - 1).x - text.findCharacterPos(0).x;
where numChars is the number of characters in the string of your text object. However, since findCharacterPos will return global coordinates, it's probably more convenient to use getLocalBounds, this way you don't have to worry about whether your text object has any transformations applied to it.
You can use getGlobalBounds() to get the size/coordinates after a transformation (rotation, scale, move...).
Otherwise it's getLocalBounds().
Doc: http://www.sfml-dev.org/documentation/2.3.1/classsf_1_1Text.php
Related
I have this snippet of code
void Graphics::render_text(std::string bunch_of_text) {
sf::Text text;
text.setFont(font); // font is a sf::Font
text.setString(bunch_of_text);
text.setCharacterSize(text_size); // in pixels, not points!
text.setFillColor(text_color);
text.setStyle(text_style);
window.draw(text);
window.display();
}
And sometimes this text is really long, and the remainder of the text can't be seen because of bounds.
Is there an opportunity to make text perfectly fitting on the screen, such as splitting text into multiple parts or making a new line(\n) inside the text where needed?
Here's one idea (pseudocode):
While text.getLocalBounds().width > window.size().x:
Determine an appropriate place in the text to add a newline. Possibly use text.getCharacterSize() and/or text.getLetterSpacing() to do this calculation.
text.setString() to set the new string.
I have to take a photo of a sudoku grid, then I have to save all the cell of the grid.
I have to use for another algorithm, SDL_Surface of 28x28 pixels for each cell, but I don't know how to do that because the photo I took could be larger than that, or smaller than that. I had a look on SDL_BlitSurface but I have to use SDL1 so it doesn't work, and with SDL_SoftStretch I don't know how to proceed.
I found a solution here :
https://www.gamedev.net/forums/topic/640043-scaling-images/
So here is the main part of it :
double zoomx = newwidth / (float)image->w;
double zoomy = newheight / (float)image->h;
// This function assumes no smoothing, so that any colorkeys wont bleed.
SDL_Surface* sized = zoomSurface( image, zoomx, zoomy, SMOOTHING_OFF );
To use zoomSurface, it needs to :
add #include "SDL/SDL_rotozoom.h" at the beginning of the file.
use the following option with gcc : -lSDL_gfx.
I draw some text to a surface (using SDL_ttf) and then I want to change the text on the surface. If I just redraw the surface the text does not go away. I have looked at several forum posts on how to fix the problem but I just cannot seem to figure it out. In particular I cannot understand why this solution does not work: (code is long so this just gives the essentials)
In Class file declared:
SDL_Surface* box; // These two are initialised to the
SDL_Surface* boxCopy; // same image
At the start of my render function:
*box = *boxCopy; \\Reset box surface
My understanding of pointers and C++ (which is admittedly limited) suggests that this should make the surface pointed at by box equal to the surface pointed at by boxCopy. Instead the boxCopy surface becomes a copy of box. I have no idea how boxCopy can be changed by this line of code but it seems like that is what is happening.
I'm not sure i completely understand your problem but hopefully this can help.. It's easier to update the text whenever the surface it's drawn on is to be updated rather than updating it whenever the actual text is updated. It might not be as optimized performance wise but i would say it's easier in most cases.
A typical program loop would include a re-rendering of a surface representing the screen followed by an SDL_Flip of this surface. You can of course optimize your re-rendering so you only render what has actually been updated since last frame. Is that what you're working on perhaps? If so, and if you use the method below you should be aware that the new text only covers the size of the new text and not the entire old text. I usually solve this by first drawing a filled rectangle and then the new text.
Here is a TTF example showing how text can be drawn on a surface (here called m_Screen, which is the surface flipped to screen every frame) in the simple case where i have one background color only:
void drawText(const char* string, int x, int y,
int fR, int fG, int fB, int bR, int bG, int bB)
{
SDL_Color foregroundColor = { fR, fG, fB };
SDL_Color backgroundColor = { bR, bG, bB };
SDL_Surface* textSurface = TTF_RenderText_Shaded(m_Font, string,
foregroundColor,
backgroundColor);
SDL_Rect textLocation = { x, y, 0, 0 };
SDL_BlitSurface(textSurface, NULL, m_Screen, &textLocation);
SDL_FreeSurface(textSurface);
}
Notice that this has been done before calling drawText (with some suitable font size):
m_Font = TTF_OpenFont("arial.ttf", size);
And this is done at cleanup:
TTF_CloseFont(m_Font);
I'm working on a GUI-Project with d3d9 & d3dx9. I create fonts using the D3DXCreateFont function (C++). Everything is working fine. But I need a function that determines the width in pixel for a specific text.
Something like this:
char text[64] = "Heyho - Blablabla";
GUIFont* hFont = gui->fonts->CreateFont("DefaultFont", "Arial", 18);
int width = hFont->GetTextWidth(text);
[...]
The part with gui->fonts->CreateFont is all working fine. It's my way of creating and storing fonts. Ignore that part, it's all about the GetTextWidth. My CreateFont function initalizes the GUIFont object. The actual D3D-Font is stored in a LPD3DXFONT.
I really hope you can help me with this one, I am pretty sure it's possible - I just don't know how. Thanks for reading, and I hope you have a clue.
You can use the DT_CALCRECT flag on the ID3DXFont function DrawText to return the required size of the rectangle enclosing the text.
So, if you want to get just the width, you might have a function something like this:
int GetTextWidth(const char *szText, LPD3DXFont pFont)
{
RECT rcRect = {0,0,0,0};
if (pFont)
{
// calculate required rect
pFont->DrawText(NULL, szText, strlen(szText), &rcRect, DT_CALCRECT,
D3DCOLOR_XRGB(0, 0, 0));
}
// return width
return rcRect.right - rcRect.left;
}
Obviously, you can also extract the height too if you need it.
I have QGraphicsTextItem objects on a QGraphicsScene. The user can scale the QGraphicsTextItem objects by dragging the corners. (I am using a custom "transformation editor" to do this.) The user can also change the size of the QGraphicsTextItem by changing the font size from a property panel. What I would like to do is unify these so that when the user scales the object by dragging the corner with the mouse, behind the scenes it actually is calculating "What size font is necessary to make the resulting object fit the target size and keep the scale factor at 1.0?"
What I am doing now is letting the object scale as normal using QGraphicsItem::mouseMoveEvent and then triggering a FinalizeMapScale method in QGraphicsItem::mouseReleaseEvent once the mouse scale is complete. This method should then change the font to the appropriate size and set the scale back to 1.0.
I have a solution that appears to be working, but I'm not crazy about it. I'm relatively new to both Qt and C++, so would appreciate any comments or corrections.
Is there a better way to architect this whole thing?
Are there Qt methods that already do this?
Is my method on the right track but has some Qt or C++ errors?
Feel free to comment on my answer below on submit your own preferred solution. Thanks!
[EDIT] As requested in comment, here is the basics of the scaling code. We actually went a different direction with this, so this code (and the code below) is no longer being used. This code is in the mouseMoveEvent method, having previously set a "scaling_" flag to true in mousePressEvent if the mouse was clicked in the bottom-right "hot spot". Note that this code is in a decorator QGraphicsItem that holds a pointer to the target it is scaling. This abstraction was necessary for our project, but is probably overkill for most uses.
void TransformDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
...
if (scaling_) {
QGraphicsItem *target_item = target_->AsQGraphicsItem();
target_item->setTransformOriginPoint(0.0, 0.0);
QPointF origin_scene = mapToScene(target_item->transformOriginPoint());
QPointF scale_position_scene = mapToScene(event->pos());
qreal unscaled_width = target_item->boundingRect().width();
qreal scale_x = (scale_position_scene.x() - origin_scene.x()) / unscaled_width;
if (scale_x * unscaled_width < kMinimumSize) {
scale_x = kMinimumSize / unscaled_width;
}
target_item->setScale(scale_x);
} else {
QGraphicsObject::mouseMoveEvent(event);
}
}
Please no holy wars about the loop-with-exit construct. We're comfortable with it.
void MapTextElement::FinalizeMapScale() {
// scene_document_width is the width of the text document as it appears in
// the scene after scaling. After we are finished with this method, we want
// the document to be as close as possible to this width with a scale of 1.0.
qreal scene_document_width = document()->size().width() * scale();
QString text = toPlainText();
// Once the difference between scene_document_width and the calculated width
// is below this value, we accept the new font size.
const qreal acceptable_delta = 1.0;
// If the difference between scene_document_width and the calculated width is
// more than this value, we guess at the new font size by calculating a new
// scale factor. Once it is beneath this value, we creep up (or down) by tiny
// increments. Without this, we would sometimes incur long "back and forth"
// loops when using the scale factor.
const qreal creep_delta = 8.0;
const qreal creep_increment = 0.1;
QScopedPointer<QTextDocument> test_document(document()->clone());
QFont new_font = this->font();
qreal delta = 0.0;
// To prevent infinite loops, we store the font size values that we try.
// Because of the unpredictable (at least to me) relationship between font
// point size and rendering size, this was the only way I could get it to
// work reliably.
QList<qreal> attempted_font_sizes;
while (true) {
test_document->setDefaultFont(new_font);
delta = scene_document_width - test_document->size().width();
if (std::abs(delta) <= acceptable_delta ||
attempted_font_sizes.contains(new_font.pointSizeF())) {
break;
}
attempted_font_sizes.append(new_font.pointSizeF());
qreal new_font_size = 0.0;
if (std::abs(delta) <= creep_delta) {
new_font_size = delta > 0.0 ? new_font.pointSizeF() + creep_increment
: new_font.pointSizeF() - creep_increment;
} else {
new_font_size = new_font.pointSizeF()
* scene_document_width
/ test_document->size().width();
}
new_font.setPointSizeF(new_font_size);
}
this->setFont(new_font);
this->setScale(1.0);
}
Another way to look at the problem is: Qt has scaled the font, what is the effective font size (as it appears to the user, not the font size set in the text item) that I need to display to the user as their choice of new font size? This is just an alternative, you still need a calculation similar to yours.
I have a similar problem. I have a text item that I want to be unit size (one pixel size) like my other unit graphic items (and then the user can scale them.) What font (setPointSize) needs to be set? (Also what setTextWidth and what setDocumentMargin?) The advantage of this design is that you don't need to treat the scaling of text items different than the scaling of any other shape of graphics item. (But I don't have it working yet.)
Also, a user interface issue: if the user changes the font size, does the item change size? Or does it stay the same size and the text wrap differently, leaving more or less blank space at the end of the text? When the user appends new text, does the font size change so all the text fits in the size of the shape, or does the shape size grow to accommodate more text? In other words, is it more like a flowchart app (where the shape size is fixed and the font shrinks), or like a word processor app (where the font size is constant and the shape (number of pages) grows?