【发布时间】:2011-04-21 18:17:39
【问题描述】:
我正在窗口上的另一个线程中进行绘画,当我的表单收到 WM_PAINT(或 WM_ERASE...)时,表单被擦除以开始绘画。我需要阻止此消息从我的窗口接收。如何做到这一点?
当收到 WM_APP+1 消息时,此代码只是在主窗体上以字符串类型绘制当前时间和星期几。
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->Handle, 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);
【问题讨论】:
-
你能给我们一些细节吗?我会评论说,绘画需要在 VCL 应用程序的主线程中完成。
-
不一定是大卫,甚至可以从另一个进程完成。就像 DirectShow 正在画视频一样。
-
是的,我正在使用 Synchronize() 函数在线程中执行此操作,但即使没有此功能,在画布上绘画也是线程安全的。每次我有新数据要绘制时,我都会绘制,但我得到了闪烁效果。在此之后我发现这是因为窗口接收到 WM_PAINT 或 WM_ERASEBACKGROUND 消息,而我的线程在大约 100-200 毫秒内没有任何东西可以绘制,所以表格是刚刚删除。
-
如果您需要绘画,只需调用 InvalidateRect ,他们就会处理随后的绘画消息。如果您忽略绘图消息,您将遇到空白窗口和闪烁。
-
不要从单独的线程在画布上绘画!它不是线程安全的。处理此问题的正确方法是让线程将其更新绘制到内存中的位图,然后让
WM_PAINT处理程序绘制位图中当前的任何内容。
标签: c++ windows winapi c++builder