I'm currently experiencing an error with my program.
My program has two rectangles, each of them surrounded by a groupbox.
Currently I'm trying two place text in each of them.
I've already got text in the first rectangle - fine (with DrawText()).
If I'm trying to display text in the second rectangle (also with DrawText()), the text is not displaying.
Here's the code I'm using:
hdc = BeginPaint(hwnd, &ps);
SelectObject(hdc, font);
DrawText(hdc, lpcwstr, wcslen(lpcwstr), &rect, DT_LEFT);
DrawText(hdc, lpcwstr, wcslen(lpcwstr), &rect_2, DT_LEFT);
EndPaint(FindWindow(NULL, L"Statistik (seit dem 01.01.2015)"), &ps);
Unfortunately I have no idea why the text is not displaying as expected.
Does anybody of you have a suggestion why this doesn't work?
[SOLUTION]
I was able to figure out what the problem was.
Not visible in the snippet, I posted initially, but the coordinates I set for the rectangles, were wrong.
Sadly I were not aware that all values are coordinates.
The only difference between the two calls is the RECT that you pass. The obvious conclusion is that you initialised one of the rectangles incorrectly.
You should restore the original font before calling EndPaint. And the call to FindWindow should be removed. Pass hwnd. Finally, your code performs no error checking at all. That's always imprudent.
Related
In my small, small and humble c++ Win32 GUI application, I got to the point of being able to draw a grid :
This is in preparation for displaying spectral data, the 36 (floats) measurement points returned from my device. I still have to get the axis labeled... This is my code for drawing the grid so far :
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
FillRect(hdc, &ps.rcPaint, HBRUSH (COLOR_WINDOW + 1));
bool Retour;
pen = (HPEN)GetStockObject(TRANSPARENT);
SelectObject(hdc, pen);
Brosse = CreateSolidBrush(RGB(240, 240, 240));
SelectObject(hdc, Brosse);
Retour = LineTo(hdc, 100, 500);*/
Retour = Rectangle(hdc, 350, 150, 750, 375);
for (int i = 380; i <= 730; i=i+10) { // 36 vertical lines
MoveToEx(hdc, i, 175, NULL);
LineTo(hdc, i, 350);
}
for (int i = 175; i <= 350; i = i + 17) {
MoveToEx(hdc, 375, i, NULL);
LineTo(hdc, 730, i);
}
DeleteObject(pen);
DeleteObject(Brosse);
EndPaint(hWnd, &ps);
As you can see, I located the code to draw the grid inside the WM_PAINT procedure. It made sense to locate the code there to experiment with GDI instructions but also because the grid needs to be visible at launch time as part of the interface.
My question is how should I go "updating" the graph when, after pressing the "Measure Sample" button, I have access to the data? I gather that the code to draw on the grid does not necessarily needs to be located inside the WM_PAINT procedure, does it? According to my limited understanding, as long as I can get a Device Context handle (hDC), I should be good to go? All I need to plot is a "line" uniting the 36 data points from left to right. Not sure I should use simple MOVE_TO and LINE_TO for this purpose? I think there is a way to draw a "smoothed" line that passes through all 36 data points?
One last thing, if I may... I'm going at this in a very elementary way because I'm intimidated by the idea of using a "graphic library" and objects. But I suspect they would make my life a lot easier while offering umpteen options that will take me too long to figure out, I'll bet, and implement?
Thank you so much in advance for your kind help and patience.
You should always do all your drawing in your WM_PAINT handler. That way, the window will redraw correctly when something that was covering it is removed, for example.
When your graph data changes, call InvalidateRect to prompt a redraw.
To determine what to redraw, you will need to pass suitable variables to your WM_PAINT handler. Start with MoveTo and LineTo (or Polyline or PolyPolyline) and get that working first. You can then investigate smoothing algorithms if you think you need them.
You should place all of your custom painting code in the WM_PAINT handler of the window, yes. You can call a separate function for painting the graph if you like. Pass it the HDC you get from BeginPaint(...) and your spectral data. However, that function needs to be called from the WM_PAINT handler.
If you handle painting in WM_PAINT then to update the graph when the data changes you would call InvalidateRect(...) on the window. InvalidateRect tells Windows essentially "this window has changed and needs to be repainted". It will drive a call to the paint handler.
One problem you are going to run into is that your graph is going to flicker. It may not be too noticeable. It may not bother you, but the problem is that in each call to the WM_PAINT handler you are erasing the graph in the screen device context; this erasure will be visible. A solution to this problem would be to "double-buffer" the graph: create an offscreen bitmap, paint into that when data changes, and paint the offscreen bitmap to the screen in WM_PAINT. You could also make the graph a separate child window that manages the offscreen bitmap, etc., if you are ever going to need multiple graphs or just to add some modularity to the code.
As for whether you'd have an easier time with a graphics library ... possibly, but more to the point: you would have an easier time using a higher level GUI library than the Win32 API. If you only care about Windows, consider the .Net frameworks WinForms or WPF. Otherwise, consider Qt.
When I bitblt onto my transparent window, a bmp smaller than the client area, it draws a fussy surrounding area instead of transparent like the set colorkey from:
SetLayeredWindowAttributes(hwnd, RGB(0,255,0), 120, LWA_COLORKEY | LWA_ALPHA); //colorkey & win alpha
The blit looks like this:
The candle-like test image makes its own area transparent like it should, but the surrounding client area gets grayed out according to the window-alpha value (120). Any ideas how to fix this? I've tried:
SetBkColor(hdc, crKey); and generating a background with
FillRect(background_hdc, &background_rect, hbrush); and blitting that first
Where neither work.
I have the feeling this should be alot easier than I'm making it out to be, and I still feel something like SetBkColor(hdc,crKey); should do the trick, but it doesnt. Maybe there is a similar command that does that I'm looking for?
Isnt it funny how you solve the problem just after you formulate it properly?
Obviously the hbrBackground in the WNDCLASSEX wc;
defines the background of the window. So by setting the brush background when registering the window like so:
wc.hbrBackground=CreateSolidBrush(RGB(240, 20, 120)); //COLORREF==crKey
it gets crKey cancelled out during the blit along with the bmps crKey color. Thanks.
Using Win7 x64 c++ with MSVC2010 pro.
I have noticed a really strange bug when using the Win32 DrawText to draw some text for a custom control. Its a pretty standard thing to do I'm sure. I did see a post about something similar and the solution was to use one the TextOut calls, but that doesn't resolve my issue.
I've subclass the "Static" control using the SetWindowSubClass and I'm hanlding the wm_paint message as:
case WM_PAINT:
{
RECT rect;
PAINTSTRUCT ps;
HDC hdc = BeginPain(hWnd,&ps);
// Create a back buffer to draw to
HDC hdcBack = CreateCompatibleDC(hdc);
GetClientRect(hWnd,&rect);
HBITMAP hbmBackbuffer= CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
size_t iLength = 0;
StringCchLength(LCDText,240,&Length);
SelectObject(hdcBack,hbmBackbuffer);
// Draw a black background to clear previous text
SelectObject(hdcBack,GetSysColour(1)); // Black
Rectangle(hdcBack,rect.left,rect.top,rect.right,rect.bottom);
// Set the font, tranparency and text colour
SelectObject(hdcBack,LCDFont);
SetBkMode(hdcBack,TRANSPARENT);
SetTextColor(hdcBack,0x0000ff00);
DrawText(hdcBack,LCDText,(int)iLength,&rect,DT_LEFT);
// display
BitBlt(hdc,0,0,rect.right,rect.bottom,hdcBack,0,0,SRCCOPY);
// cleanup
DeleteObject(hbmBackbuffer);
DeleteDC(hdcBack);
EndPaint(hWnd,&ps);
break;
}
This actually works very well. The problem is that the the 'label' can display 3 lines of 40 chararcters, and after the 27 character of each line the next chars to the end of that line are 1 or 2 pixels higher up the screen. It's not immediately apparent but once you notice it then it kindof draws your attention.
Does anyone have any ideas or experience with this?
ps - I typed the code in manually into the forum so there may be some silly typos but the real code does work properly apart the alignment issue.
Regards
Dave.
I am new to using Graphics in Visual C++. I am just trying to make a rectangle filled with a color. Need help to correct this...
RECT rect;
HDC hdc;
hdc=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
rect.left=30;
rect.right=100;
rect.top=50;
rect.bottom=200;
FillRect(hdc,&rect,(HBRUSH)(RGB(40,151,151)));
The error is:
ERROR: The variable 'rect' is being used without being initialized.
This will normally be a warning, not an error. In this case, it also appears to be spurious.
It might work better if you initialize it something like:
HDC hdc=CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
RECT rect = {30, 50, 100, 200};
HBRUSH brush = CreateSolidBrush(RGB(50, 151, 151));
FillRect(hdc, &rect, brush);
DeleteObject(brush);
Do note the use of CreateSolidBrush -- casting a color to an HBRUSH seems unlikely to work.
Your code fails because of this code:
(HBRUSH)(RGB(40,151,151))
You cannot cast an RGB color to an HBRUSH in any meaningful way. The only way to obtain an HBRUSH is a ask the system to give you one.
So, you need to create a real brush using one of the API functions for that purpose. For example, CreateSolidBrush.
HBRUSH hBrush = CreateSolidBrush(RGB(40,151,151));
When you have finished with the brush, call DeleteObject to return resources to the system.
As a general rule, every time you write a cast, regard the code as very suspicious. Always endeavour to write code without casts.
I'm sort of new to c++ and i'm trying to create a game.
I have a 2d array RECT_GRID of rectangles.
I have a 2d array GRID of unsigned short.
I fill the rectangle array during WM_CREATE
The WM_PAINT event paints rectangles for all the elements in the array. The color of the rectangle is based on the value of GRID[x][y]
I made it so when the down key is pressed, It changes the color of one of the rectangles by setting GRID[1][XMOVE] = to a different color
then it invalidates the client rectangle
Basically what happens is, it works well for a while, but eventually it just stops drawing stuff. I checked my XMOVE variable during debug, I checked by grid values and stuff and everything is fine. When I remove the for loop from the paint event and focus on 1 specific rectangle, it never fails, but if I try to redraw all of them at once, after about 20 times, it stops painting things. What could cause this? I'm new to c++ and I bet I'm not painting properly and causing an overflow or something.
If anyone could explain what's going wrong, or a proper way to do this, I'd really appreciate it. I could not find anything like this example on Google.
Thanks
EDIT:
I'm using 3 global brushes
HBRUSH A;
HBRUSH B;
HBRUSH C;
and when I modify them, I always say A = MakeBrush(NUM);
ami I using brushes properly?
My first guess, if you're a total GDI/C++ newbie, is that you are probably creating a lot of Pens and Brushes. These are constrained resources in Windows. You can only create so many of them before you start to tax your resources. So either make your Brushes and Pens and Windows, etc all at once and re-use them, or dispose of them properly when you're done. I recommend getting a copy of "the Bible" (http://www.amazon.com/Programming-Windows%C2%AE-Fifth-Microsoft/dp/157231995X/ref=sr_1_1?ie=UTF8&s=books&qid=1252788457&sr=8-1) and reading the chapters in there about drawing.
EDIT: It doesn't sound like you're modifying your brushes properly, but since I can't see the code for MakeBrush, I don't know. You're probably creating a lot of brushes behind the scenes and you don't even know it. Seriously, get a copy of Petzold's book and spend an hour or two. You'll end up with more hair on your head later! ;-)
You'll notice in all GDI examples, a 'CreatePen' or 'CreateSolidBrush' will be followed by a delete object. This is because they are limited resources in windows, and you can run out of them if you don't delete them when you're finished.
PAINTSTRUCT Ps;
HDC hDC = BeginPaint(hWnd, &Ps);
HBRUSH NewBrush = CreateSolidBrush(RGB(250, 25, 5));
SelectObject(hDC, NewBrush);
Rectangle(hDC, 20, 20, 250, 125);
DeleteObject(NewBrush);
EndPaint(hWnd, &Ps);
If you forget to include the 'DeleteObject' call, then you will have problems after you use up all the brushes available. It's actually fun to try =)