To whom it may concern,
GetTextExtentPoint and GetTextExtentPoint32 is giving me a bad day.
They are the only method MSDN offers for measuring text but they have two flaws, but nobody else seems to have these problems.
Firstly, they dont take into account newline. They treat the measurement as one long one liner.
Secondly and most importantly, they are causing aliasing when I do DrawText(). I am using ClearType for HFONT but still get aliasing text being drawn.
Kindly let me know precisely what is the problem. Or I might have to create my own measuring text function.
EDIT_________
// note font is created with CLEAR_TYPE_QUALITY
// so it should be antialiased
HFONT createFont(const char *face_name,int height)
{
return CreateFont(height,cHeight,0,0,0,FW_NORMAL,false,false,false,0,0,0,CLEAR_TYPE_QUALITY,0,face_name);
}
RECT box{0,0,640,480);
POINT pos{};
HFONT font = createFont("MyFavouriteFont",30);
HDC canvas = CreateCompatableDC(NULL);
HBITMAP bmp = CreateCompatibleBitmap(NULL,640,480);
SelectBitmap(canvas,bmp);
SelectFont(canvas,font);
SelectBrush(canvas,GetStockObject(DC_BRUSH));
SetDCBrushColor(RGB(255,255,255));
SetBkMode(TRANSPARENT);
SIZE measureText_Msdn(const char *s,HDC font)
{
SIZE sz;
GetTextExtentPoint(font,s,strlen(s),&sz);
return sz;
}
SIZE measureText_Custom(const char *s,HDC font)
{
SIZE sz;
TEXTMETRICSA metrics;
INT char_width, line_width;
// get char height
GetTextMetrics(font,&metrics);
while(*it)
{
if(*it == '\n' || *it == '\r')
{
if(line_width > sz.cx) sz.cx = line_width; // sz.cx stores max width
sz.cy += metrics.tmHeight;
line_width = 0;
}
else
{
GetCharWidth32(font,*it,*it,&char_width);
line_width += char_width;
}
++it;
}
if(line_width > sz.cx) sz.cx = line_width;
if(line_width > 0) sz.cy += metrics.tmHeight; // If there are no chars on this line, the line has no size
return sz;
}
void drawText(HDC dest_ctx)
{
auto s = ,"Text will look blocky";
measureText_Msdn(s,font);
// or measureText_Custom(s,font); will cause font to look blocky and ugly
// If you comment out measureText_* text will be drawn smooth.
FillRect(canvas, &box,(HBRUSH)GetCurrentObject(canvas,OBJ_BRUSH));
DrawTextA(canvas,s,-1,&box,DT_LEFT);
BitBlt(dest_ctx,pos.x,pos.y,box.right,box.bottom,
canvas,0,0,SRCCOPY);
}
SOLUTION_____
I have posted a solution as an answer. I dont like to have to do it. As I said earlier, nobody else seems to have this problem so nobody else would need the solution.
As I said earlier nobody seems to get blocky text when using any of the text measuring functions. I get it when using any of them.
What I noticed is that calling these functions require a context, and the functions seems to be currupting the context. Even if I select a new font into the context I still get blocky text output.
Thus I create a context on the fly and add the desired font into it. And measure with that context, collect the result and delete that context. I tested this and my text are drawn smooth as my original context is unaffected.
Reasons I hate this method:
- I am afraid of the expense of creating and deleting context on the fly.
- I dont think GetTextExtent should currupt my context in the first place.
If you guys have a better way, or know my problem, or why I shouldnt be having this problem kindly post.
EDIT_________
After looking at using keyboard tutorial on MSDN, I saw where the author using a window context instead of memory context for calls to GetTextExtent. It appears that GetTextExtent and the other measurement functions are only meant to be used with window contexts. Which is perfectly fine for me as I dont like Creating Memory Context anyhow.
Related
I've been writing a simple Stock Market program to help me learn Win32 programming, but I am struggling to learn how to retrieve integers from an edit control. I've learned how to retrieve strings from an edit control using GetWindowText. According to the MSDN documentation I need to use the GetDlgItemInt function.
The code below I have the user select a company(which I got working for strings) to show company stock information. I have another edit control to have the user type in the amount of shares they'd want to purchase. I want to take this value to calculate the cost of shares and display the result to the user.
HWND hEditSearchCompanies;
HWND mainWindow; //Parent Window
RECT rect;
BOOL fRelative;
BOOL fError;
rect.left = 200;
rect.right = 600;
rect.top = 50;
rect.bottom = 400;
case WM_COMMAND:
{
case IDC_CALCULATETYPESHARES:
{
int sharesInputed = GetDlgItemInt(hEditSearchCompanies, IDC_EDITTYPESHARES, &fError, fRelative);
swprintf_s(SharesInputedBuffer, 20, L"%d", sharesInputed);
InvalidateRect(mainWindow, &rect, FALSE);
}
break;
case IDC_COMPANYINFOBUTTON:
{
int len = GetWindowTextLength(GetDlgItem(hwnd, IDC_COMPANYCODEDIT));
if (len > 0)
{
wchar_t wcEditBuffer[256];
GetWindowTextW(hEditSearchCompanies, wcEditBuffer, len + 1);
Company SearchForCompany = SearchStrings(hwnd, wcEditBuffer);
PrintCompanySearchResults(ChildHDC, SearchForCompany, inputRect);
}
}
}
break;
case WM_PAINT:
{
TextOutW(ChildHDC, x, y, sharesInputedBuffer, wcslen(sharesInputedBuffer));
}
I then want to use the sharesInputed value to display the numbers like so:
int purchaseCost = sharesInputed * company.PricePerShare;
...//Display result to the user
However sharesInputed is always returning zero. I'll put in, say 50 shares. If a company's price per share cost is $63.13, my program should be printing $3,156.50, but sharesInputed is always equal to zero whenever I hit my button to calculate the cost.
MSDN documentation doesn't really have any troubleshooting tips for GetDlgItemInt, and have debugged my program numerous times, but still get 0. Looked around and found a few reasons for this but none have worked for me.
I am not getting any error messages or warnings based on my sharesInputted value.
Hopefully I provided enough code. My control ids match for the windows and buttons.
Thanks!
Paul Sanders has correct answer. GetDlgItemInt wants the parent window. I was giving the window of my edit control instead, and now I'm getting the correct values.
Cheers!
I am using wxWidgets 3.0.2 in a static unicode build on Windows 10. I am using a wxStyledTextCtrl, which is a near 1-to-1 mapping of Scintilla.
I am looking for functionality similar to Notepad++ where upon double-clicking on something in the editor, all occurrences of that item get highlighted. It is hard to find good examples that really demonstrate styling. I've looked at wxWidgets documentation, Scintilla documentation, Notepad++ source and Code::Blocks source (the latter two use Scintilla as their text editors) and still haven't had much luck.
I've tried many different variations of the following code and it never quite works right. Either nothing is highlighted or the whole document is highlighted. I know I'm missing something, but I can't figure out what.
//textarea is a wxStyledTextCtrl*
textarea->StyleSetBackground(styleHightlightAllSelected, wxColor(80, 255, 80));
wxString selectedText = textarea->GetSelectedText();
int selSize = selectedText.size();
int selStart = textarea->GetSelectionStart();
int pos = 0;
int curr = 0;
int maxPos = textarea->GetLastPosition();
while(pos != -1){
pos = textarea->FindText(curr, maxPos, selectedText);
if(pos == selStart){ //skip the actual highlighted item
curr = pos + selSize;
} else if(pos != -1){
textarea->StartStyling(pos, 0x1F);
textarea->SetStyling(selSize, styleHightlightAllSelected);
curr = pos + selSize;
}
}
The search part of the loop does successfully find the selected text; it's just that the styling doesn't seem to take hold.
So my questions that I couldn't really find answers to are:
styleHightlightAllSelected is an int set to 100. When I had it as 0, the whole document turned green when doubleclicking. I see that styles 32-39 are predefined. Are there other styles that are predefined-but-not-really-documented; meaning, is 100 ok?
Do I have to set the entire style up, or can I just set the background color as I do above?
Is it enough to do StartStyling() and SetStyling() when I find an occurrence and be done with it, or is there more?
StartStyling() in wxWidgets has a mask argument, but the Scintilla counterpart does not. I can't clearly determine what I should set this to. It seems to be 31 (00011111) to preserve the 5 existing styling/lexer bits? Essentially, I'm not sure what to set this to if all I want to do is modify the background color of each occurrence.
My program will regularly deal with files that are dozens or more megabytes in size, so should I just be highlighting occurrences that are visible, and adjust as necessary when srolling/jumping? At the moment it searches and (fails to) set styling on each occurrence, and it takes about a second on a 50MB file. I've observed that on the same file loaded in Notepad++, it happens instantly, so I'm assuming it does it on a visible basis?
I ended up asking about this on the github issues page for the Notepad++ project, and the correct way to do this is to not use styles, but rather use indicators instead. So my code above changes to this:
int maxPos = textarea->GetLastPosition();
textarea->IndicatorClearRange(0, maxPos);
textarea->IndicatorSetStyle(styleHightlightAllSelected, wxSTC_INDIC_ROUNDBOX);
textarea->IndicatorSetAlpha(styleHightlightAllSelected, 100);
textarea->IndicatorSetUnder(styleHightlightAllSelected, true);
textarea->IndicatorSetForeground(styleHightlightAllSelected, wxColor(0, 255, 0));
wxString selectedText = textarea->GetSelectedText();
int selSize = selectedText.size();
int selStart = textarea->GetSelectionStart();
int pos = 0;
int curr = 0;
vector<int> selectionList;
while((pos = textarea->FindText(curr, maxPos, selectedText)) != -1){
selectionList.push_back(pos);
curr = pos + selSize;
}
textarea->SetIndicatorCurrent(styleHightlightAllSelected);
for(unsigned int i = 0; i < selectionList.size(); i++){
if(selectionList[i] != selStart){
textarea->IndicatorFillRange(selectionList[i], selSize);
}
}
This doesn't factor in, however, only highlighting the visible range and only highlighting new occurrences as they scroll into view (I will add this later), so for files that are dozens of megabytes in size, it will take 2-3 seconds for the highlighting to finish.
When trying to create a compass with Direct2D, I was faced with the challenge of combining 72 individual lines. My question was: how do I combine a relatively larger number of ID2D1PathGeometries?
After disappointment with Direct2D's ability to combine only two geometries at one time, I decided to set out to create a modular way to combine multiple.
Since Direct2D DOES provide the "CombineWithGeometry" function, this function just manages that, as well as temporary resources, to create a final geometry.
A few notes: this function is fairly expensive, so it should not be run during a frame render, but instead, before if possible, and the result should be cached. This version only supports path geometry, however, adding support for other geometry is easy, just change the geometry type in the parameters.
Without further ado, here's the function:
ID2D1PathGeometry* combine_multiple_path_geometries(ID2D1Factory*& srcfactory, int geo_count, ID2D1PathGeometry* geos[]) {
ID2D1PathGeometry* path_geo_1 = NULL;
ID2D1PathGeometry* path_geo_2 = NULL;
srcfactory->CreatePathGeometry(&path_geo_1);
srcfactory->CreatePathGeometry(&path_geo_2);
for (short i = 0; i < geo_count; i++) {
ID2D1GeometrySink* cmpl_s1 = NULL;
ID2D1GeometrySink* cmpl_s2 = NULL;
if (i % 2 == 0) {
//copying into 1
path_geo_1->Open(&cmpl_s1);
if (i == 0)
geos[i]->CombineWithGeometry(geos[i], D2D1_COMBINE_MODE_UNION, NULL, cmpl_s1);
else
geos[i]->CombineWithGeometry(path_geo_2, D2D1_COMBINE_MODE_UNION, NULL, NULL, cmpl_s1);
cmpl_s1->Close();
cmpl_s1->Release();
if (i != 0) {
path_geo_2->Release();
srcfactory->CreatePathGeometry(&path_geo_2);
}
//cmpl_g1 now contains the geometry so far
}
else {
//copying into 2
path_geo_2->Open(&cmpl_s2);
geos[i]->CombineWithGeometry(path_geo_1, D2D1_COMBINE_MODE_UNION, NULL, cmpl_s2);
cmpl_s2->Close();
cmpl_s2->Release();
path_geo_1->Release();
srcfactory->CreatePathGeometry(&path_geo_1);
//cmpl_g2 now contains the geometry so far
}
}
if (geo_count % 2 == 0) {
if (path_geo_1)
path_geo_1->Release();
return path_geo_2;
}
else {
if (path_geo_2)
path_geo_2->Release();
return path_geo_1;
}
}
You can wrap this into a class, keep it as a standalone, or however you see fit. As mentioned before, you can easily support different geometry types, or, even with a little tweaking, multiple geometry types. As well, you can easily change the combination mode from union just by changing the D2D1_COMBINE_MODE_UNION to whatever you need.
MSDN - Direct2D Geometry Combination Modes: https://msdn.microsoft.com/en-us/library/windows/desktop/dd368083%28v=vs.85%29.aspx
MSDN - Direct2D Geometries: https://msdn.microsoft.com/en-us/library/windows/desktop/dd756653%28v=vs.85%29.aspx
MSDN - Direct2D Geometry Combinations: https://msdn.microsoft.com/en-us/library/windows/desktop/dd756676%28v=vs.85%29.aspx
I'm writing the code for a GUI (in C++), and right now I'm concerned with the organisation of text in lines. One of the problems I'm having is that the code is getting very long and confusing, and I'm starting to get into a n^2 scenario where for every option I add in for the texts presentation, the number of functions I have to write is the square of that. In trying to deal with this, A particular design choice has come up, and I don't know the better method, or the extent of the advantages or disadvantages between them:
I have two methods which are very similar in flow, i.e, iterate through the same objects, taking into account the same constraints, but ultimately perform different operations between this flow. For anyones interest, the methods render the text, and determine if any text overflows the line due to wrapping the text around other objects or simply the end of the line respectively.
These functions need to be copied and rewritten for left, right or centred text, which have different flow, so whatever design choice I make would be repeated three times.
Basically, I could continue what I have now, which is two separate methods to handle these different actions, or I could merge them into one function, which has if statements within it to determine whether or not to render the text or figure out if any text overflows.
Is there a generally accepted right way to going about this? Otherwise, what are the tradeoffs concerned, what are the signs that might indicate one way should be used over the other? Is there some other way of doing things I've missed?
I've edited through this a few times to try and make it more understandable, but if it isn't please ask me some questions so I can edit and explain. I can also post the source code of the two different methods, but they use a lot of functions and objects that would take too long to explain.
// EDIT: Source Code //
Function 1:
void GUITextLine::renderLeftShifted(const GUIRenderInfo& renderInfo) {
if(m_renderLines.empty())
return;
Uint iL = 0;
Array2t<float> renderCoords;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[0].s_x;
renderCoords.s_y = renderInfo.s_offset.s_y + m_y;
float remainingPixelsInLine = m_renderLines[0].s_y;
for (Uint iTO= 0;iTO != m_text.size();++iTO)
{
if(m_text[iTO].s_pixelWidth <= remainingPixelsInLine)
{
string preview = m_text[iTO].s_string;
m_text[iTO].render(&renderCoords);
remainingPixelsInLine -= m_text[iTO].s_pixelWidth;
}
else
{
FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();
float characterWidth = 0;
Uint iFirstCharacterOfRenderLine = 0;
for(Uint iC = 0;;++iC)
{
if(iC == m_text[iTO].s_string.size())
{
// wrap up
string renderPart = m_text[iTO].s_string;
renderPart.erase(iC, renderPart.size());
renderPart.erase(0, iFirstCharacterOfRenderLine);
m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
&renderCoords);
break;
}
characterWidth += m_text[iTO].s_font->getWidthOfGlyph(intData,
m_text[iTO].s_string[iC]);
if(characterWidth > remainingPixelsInLine)
{
// Can't push in the last character
// No more space in this line
// First though, render what we already have:
string renderPart = m_text[iTO].s_string;
renderPart.erase(iC, renderPart.size());
renderPart.erase(0, iFirstCharacterOfRenderLine);
m_text[iTO].s_font->renderString(renderPart.c_str(), intData,
&renderCoords);
if(++iL != m_renderLines.size())
{
remainingPixelsInLine = m_renderLines[iL].s_y;
renderCoords.s_x = renderInfo.s_offset.s_x + m_renderLines[iL].s_x;
// Cool, so now try rendering this character again
--iC;
iFirstCharacterOfRenderLine = iC;
characterWidth = 0;
}
else
{
// Quit
break;
}
}
}
}
}
// Done! }
Function 2:
vector GUITextLine::recalculateWrappingContraints_LeftShift()
{
m_pixelsOfCharacters = 0;
float pixelsRemaining = m_renderLines[0].s_y;
Uint iRL = 0;
// Go through every text object, fiting them into render lines
for(Uint iTO = 0;iTO != m_text.size();++iTO)
{
// If an entire text object fits in a single line
if(pixelsRemaining >= m_text[iTO].s_pixelWidth)
{
pixelsRemaining -= m_text[iTO].s_pixelWidth;
m_pixelsOfCharacters += m_text[iTO].s_pixelWidth;
}
// Otherwise, character by character
else
{
// Get some data now we don't get it every function call
FSInternalGlyphData intData = m_text[iTO].stealFSFastFontInternalData();
for(Uint iC = 0; iC != m_text[iTO].s_string.size();++iC)
{
float characterWidth = m_text[iTO].s_font->getWidthOfGlyph(intData, '-');
if(characterWidth < pixelsRemaining)
{
pixelsRemaining -= characterWidth;
m_pixelsOfCharacters += characterWidth;
}
else // End of render line!
{
m_pixelsOfWrapperCharacters += pixelsRemaining; // we might track how much wrapping px we use
// If this is true, then we ran out of render lines before we ran out of text. Means we have some overflow to return
if(++iRL == m_renderLines.size())
{
return harvestOverflowFrom(iTO, iC);
}
else
{
pixelsRemaining = m_renderLines[iRL].s_y;
}
}
}
}
}
vector<GUIText> emptyOverflow;
return emptyOverflow; }
So basically, render() takes renderCoordinates as a parameter and gets from it the global position of where it needs to render from. calcWrappingConstraints figures out how much text in the object goes over the allocated space, and returns that text as a function.
m_renderLines is an std::vector of a two float structure, where .s_x = where rendering can start and .s_y = how large the space for rendering is - not, its essentially width of the 'renderLine', not where it ends.
m_text is an std::vector of GUIText objects, which contain a string of text, and some data, like style, colour, size ect. It also contains under s_font, a reference to a font object, which performs rendering, calculating the width of a glyph, ect.
Hopefully this clears things up.
There is no generally accepted way in this case.
However, common practice in any programming scenario is to remove duplicated code.
I think you're getting stuck on how to divide code by direction, when direction changes the outcome too much to make this division. In these cases, focus on the common portions of the three algorithms and divide them into tasks.
I did something similar when I duplicated WinForms flow layout control for MFC. I dealt with two types of objects: fixed positional (your pictures etc.) and auto positional (your words).
In the example you provided I can list out common portions of your example.
Write Line (direction)
bool TestPlaceWord (direction) // returns false if it cannot place word next to previous word
bool WrapPastObject (direction) // returns false if it runs out of line
bool WrapLine (direction) // returns false if it runs out of space for new line.
Each of these would be performed no matter what direction you are faced with.
Ultimately, the algorithm for each direction is just too different to simplify anymore than that.
How about an implementation of the Visitor Pattern? It sounds like it might be the kind of thing you are after.
Does Qt has something to offer for the positioning of the tooltip-like windows? (or any types of windows/widgets actually).
I want to be able to update the position of the window automatically, so that it always stays on the screen (or at least fits it as much as possible).
An example of the behaviour I want can be seen in the standard Windows tooltips in the notification area. If the tooltip is big and it has some part of it going off the screen, it gets automatically repositioned.
Obviously, I can write the code myself, but I'm looking for something that has already been written.
I don't know if Qt has one single function that ensures a widget is totally inside of the screen. But with QDesktopWidget it's probably trivial to do.
void function RestrainWidgetToScreen(QWidget * w)
{
QRect screenRect = QDesktopWidget::availableGeometry(w);
if(w->frameGeometry().left() < screenRect.left()) {
w->move(screenRect.left() - w->frameGeometry().left(), 0);
} else if(w->frameGeometry().right() > screenRect.right()) {
w->move(screenRect.right() - w->frameGeometry().right(), 0);
}
if(w->frameGeometry().top() < screenRect.top()) {
w->move(0, screenRect.top() - w->frameGeometry().top());
} else if(w->frameGeometry().bottom() < screenRect.bottom()) {
w->move(0, screenRect.bottom() - w->frameGeometry().bottom());
}
}