how to disable WM_ONPAINT message to be recieved by my window in C++ Builder?
i'am doing painting in another thread on my window and when my form recieves WM_PAINT (or WM_ERASE...) the form is erased to begin paint. I need to stop this message's from recieving by my window. How this can be accomplished?
This code just paint's current time and day of week in string type on main form when it recieves WM_APP+1 message.
void __fastcall TForm1::handleCustomMessage(TMessage &Message)
{
static long id = 0;
static DWORD sttick = 0;
char tm[1024];
DWORD curtick = GetTickCount()-sttick;
SYSTEMTIME st;
GetLocalTime(&st);
static char sep[2] = ":";
curtick = GetTickCount();
if (curtick >= sttick+300)
{
sttick = curtick;
sep[0] = (sep[0] == 0x20?':':0x20);
}
sprintf(tm, "%02d%s%02d%s%02d", st.wHour, sep, st.wMinute, sep, st.wSecond);
// cnv->TextOutA(0, 0, tm);
PAINTSTRUCT ps;
// BeginPaint(hwnd,&ps);
// if (!TextOutA(cnv->Handle, 0, 500, tm, strlen(tm)))
// deb("textout: %s", fmterr());
LOGFONT logFont;
logFont.lfHeight = -(0.5 + 1.0 * Form1->Font->Size * 96 / 72);
logFont.lfWidth = 0;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = Form1->Font->Style.Contains(fsBold) ? 700:400;
logFont.lfItalic = Form1->Font->Style.Contains(fsItalic) ? TRUE:FALSE;
logFont.lfUnderline = Form1->Font->Style.Contains(fsUnderline) ? TRUE:FALSE;
logFont.lfStrikeOut = Form1->Font->Style.Contains(fsStrikeOut) ? TRUE:FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_TT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = NONANTIALIASED_QUALITY; // 1
logFont.lfPitchAndFamily = FIXED_PITCH;
char str[2035];
strcpy(logFont.lfFaceName, deunicode(Form1->Font->Name.c_str(), str, sizeof(str)));
HFONT hFont = NULL, hFontOld = NULL;
hFont = CreateFontIndirect(&logFont);
if (!hFont)
deb("failed to create font: %s", fmterr());
// HDC dc = GetWindowDC(Form1->Handle);
hFontOld = (HFONT)SelectObject(Form1->pb->Canvas->Handle, hFont); // 2
// Form1->Canvas->TextOut(0, 0, tm);
//
Form1->pb->Canvas->Font->Color = clWhite;
Form1->pb->Canvas->Brush->Style = bsClear;
// Form1->pb->Canvas->TextOutA(1,1,tm);
// deb("out %s",tm);
SetTextColor(Form1->pb->Canvas->Handle, clWhite);
RECT rect;
rect.left = 0;
rect.right = Form1->pb->Width;
rect.top = 1;
rect.bottom = Form1->pb->Height;
// FillRect(Form1->pb->Canvas->Handle,&rect, (HBRUSH) (COLOR_WINDOW+1));
if(!TextOutA(Form1->pb->Canvas->Handle, 3,0,tm,strlen(tm)))
deb("textout: %s",fmterr());
//LockWindowUpdate(NULL);
//int ret = DrawText(Form1->pb->Canvas->Ha开发者_如何学编程ndle, tm, strlen(tm), &rect, DT_CENTER|DT_NOCLIP|DT_EDITCONTROL);
//if (!ret)
// deb("drawtext: %s", fmterr());
// Form1->tedit->Text = tm;
switch(st.wDayOfWeek)
{
case 1:
strcpy(tm, "Понедельник");
break;
case 2:
strcpy(tm, "Вторник");
break;
case 3:
strcpy(tm, "Среда");
break;
case 4:
strcpy(tm, "Четверг");
break;
case 5:
strcpy(tm, "Пятница");
break;
case 6:
strcpy(tm, "Суббота");
break;
case 7:
strcpy(tm, "Воскресенье");
break;
}
rect.top = Form1->Canvas->TextHeight(tm)+1;
DeleteObject(hFont);
logFont.lfHeight = -(0.5 + 1.0 * Form1->Font->Size * 96 / 90);
logFont.lfWidth = 0;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
logFont.lfWeight = Form1->Font->Style.Contains(fsBold) ? 700:400;
logFont.lfItalic = Form1->Font->Style.Contains(fsItalic) ? TRUE:FALSE;
logFont.lfUnderline = Form1->Font->Style.Contains(fsUnderline) ? TRUE:FALSE;
logFont.lfStrikeOut = Form1->Font->Style.Contains(fsStrikeOut) ? TRUE:FALSE;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfOutPrecision = OUT_TT_PRECIS;
logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
logFont.lfQuality = NONANTIALIASED_QUALITY; // 1
logFont.lfPitchAndFamily = FIXED_PITCH;
strcpy(logFont.lfFaceName, "tahoma");
hFont = CreateFontIndirect(&logFont);
if (!hFont)
deb("failed to create font: %s", fmterr());
// HDC dc = GetWindowDC(Form1->Handle);
hFontOld = (HFONT)SelectObject(Form1->pb->Canvas->Handle, hFont);
//if(!TextOutA(Form1->pb->Canvas->Handle, 0,Form1->Canvas->TextHeight(tm)+1,tm,strlen(tm)))
// deb("textout: %s",fmterr());
int ret = DrawText(Form1->pb->Canvas->Handle, tm, strlen(tm), &rect, DT_CENTER|DT_NOCLIP|DT_EDITCONTROL);
if (!ret)
deb("drawtext: %s", fmterr());
// Form1->dedit->Text = tm;
// SelectObject(dc, hFontOld);
// ReleaseDC(Form1->tedit->Handle,dc);
DeleteObject(hFont);
SelectObject(Form1->pb->Canvas->Handle, hFontOld);
Assuming you have a WIn32 application then somewhere you will have similar code: Look for my comments in the code.
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_ERASEBKGND: // NOT ONLY ON PAINT BUT EVEN HERE
case WM_PAINT:
// DO NOTHING
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
I don't know CBuilder but Win32 apps all have a Window message handler. You must find how that is done and where in your form and catch thos two messages and do nothing.
Ignoring the thread safety issues of C++ builder's canvas object...
You should always do your painting from the proper WM_PAINT method. While the window manager on Windows 7 can draw outside of BeginPaint/EndPaint, it invokes low performance code paths that exist purely for backwards compatibility.
Also, there are a number of asynchronous events that the user can trigger (by moving windows etc) that invalidate the area of a window, if the window is not updated by WM_PAINT then there will be a visible latency before the window is repainted.
The Desktop Window Manager (that implements Aero Glass) really requires that you use the proper way to redraw an animated window: use a timer that calls InvalidateRect to invalidate the area with the changing content: And simply handle WM_PAINT to handle the repainting of the new state.
you could override the paint event conditionally with something like this
protected virtual void OnPaint(PaintEventArgs e)
{
// Paint the control
// ...
// Raise the Paint event.
if (Paint != null)
Paint(this, e);
}
granted this is not c++ code, but the idea is that in C builder can you click on the events tab of the form and there should be an event called onPaint, once double clicked paint could then be disabled. I use Delphi and C++ Builder is same company so same ideas can apply. But this might not be the solution..
Generally the annoying thing with this is not the repaint as much as the repaint of the background which causes the flickering in the first place. You could enable use double-buffering on the form to prevent some flickering though. Or try to go for the erasebkgnd event and just fool windows into thinking it has been erased.
private:
void __fastcall WMEraseBkgnd(TWMEraseBkgnd &Message);
void __fastcall TParentForm::WMEraseBkgnd(TWMEraseBkgnd& Message)
{
Message.Result = true; // We didn't erase the background but we tell Windows we did
}
精彩评论