CStatic透明大讨论
vc6.0中静态文本控件CStatic透明的大讨论:
初衷:窗体背景为图片,开了一个子线程AfxBeginThread(...)间隔10毫秒刷新该CStatic,来实现不断的数字变化。
为了让CStatic透明,采取如下方案:
在 WM_CTLCOLOR中用pDC->SetBackMode(TRANSPARENT)并返回空刷子来实现。
可在文字变化后出现重叠现象,所谓的黑乎乎的一堆。
有人建议用Invaldate(rect)来实现。但!!请别忘记了,我用的子线程间隔10毫秒就刷新一次,如此一来,运行不一会儿,就出现CPU利用率高且风扇狂转,虽然程序能正常运行,但仍然出现闪烁现象!这结果太差劲了。也有人建议自绘,让CStatic绘制父窗口的背景图片,再绘制文字,来实现,但我怎么也没成功!
希望有高人给出代码,或者更好的方案。我的目的是风扇不狂转,CPU不高且界面不闪烁。有人说这是不可能的,但这句话实在是难以置信。强大的VC,一个小标签控件透明都要风扇狂转?不太可能吧。
vc6.0中静态文本控件CStatic透明的大讨论:
初衷:窗体背景为图片,开了一个子线程AfxBeginThread(...)间隔10毫秒刷新该CStatic,来实现不断的数字变化。
为了让CStatic透明,采取如下方案:
在 WM_CTLCOLOR中用pDC->SetBackMode(TRANSPARENT)并返回空刷子来实现。
可在文字变化后出现重叠现象,所谓的黑乎乎的一堆。
有人建议用Invaldate(rect)来实现。但!!请别忘记了,我用的子线程间隔10毫秒就刷新一次,如此一来,运行不一会儿,就出现CPU利用率高且风扇狂转,虽然程序能正常运行,但仍然出现闪烁现象!这结果太差劲了。也有人建议自绘,让CStatic绘制父窗口的背景图片,再绘制文字,来实现,但我怎么也没成功!
希望有高人给出代码,或者更好的方案。我的目的是风扇不狂转,CPU不高且界面不闪烁。有人说这是不可能的,但这句话实在是难以置信。强大的VC,一个小标签控件透明都要风扇狂转?不太可能吧。
哪位留下邮箱或QQ,我发源代码过来,帮我解决一下
afx_msg LRESULT OnFresh(WPARAM wParam, LPARAM lParam);#define UM_FRESH WM_USER+11BEGIN_MESSAGE_MAP(CXXDlg, CDialog)
...
ON_MESSAGE(UM_FRESH, OnFresh)
END_MESSAGE_MAP()UINT __cdecl ThreadProc(LPVOID lParam)
{
HWND hWnd = (HWND)lParam;
int nCount = 0;
while(TRUE)
{
SendMessage(hWnd, UM_FRESH, (WPARAM)nCount, 0);
nCount++;
Sleep(10);
}
return 0;
}
void CXXDlg::OnOK()
{
// TODO: Add extra validation here
AfxBeginThread(ThreadProc, (LPVOID)GetSafeHwnd());
}LRESULT CXXDlg::OnFresh(WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
int nCount = (int)wParam;
CString str;
str.Format(_T("Current value: %d"), nCount);
CWnd* pWnd = GetDlgItem(IDC_STATIC1);
CRect rc;
pWnd->GetWindowRect(rc);
ScreenToClient(rc);
InvalidateRect(rc, TRUE);
SetDlgItemText(IDC_STATIC1, str); return 0;
}HBRUSH CXXDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: Change any attributes of the DC here
if(pWnd->GetDlgCtrlID() == IDC_STATIC1)
{
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextColor(RGB(255, 0, 128));
return (HBRUSH)GetStockObject(NULL_BRUSH);
}
// TODO: Return a different brush if the default is not desired
return hbr;
}
class CStaticTrans : public CStatic
在CStaticTrans的cpp文件中#define TRANS_BACK -1
CStaticTrans::CStaticTrans(void)
{
m_TextColor = RGB(0,0,0);
m_BackColor = TRANS_BACK;
}HBRUSH CStaticTrans::CtlColor(CDC* pDC, UINT mCtrlColor)
{
m_Brush.DeleteObject(); if (m_BackColor == TRANS_BACK)
{
m_Brush.CreateStockObject(HOLLOW_BRUSH);
pDC->SetBkMode(TRANSPARENT);
}
else
{
m_Brush.CreateSolidBrush(m_BackColor);
pDC->SetBkColor(m_BackColor);
} pDC->SetTextColor(m_TextColor); return (HBRUSH)m_Brush;
}void CStaticTrans::UpdateCtrl(BOOL bErase /* = FALSE */)
{
CWnd *pParent = GetParent();
CRect rect; GetWindowRect(rect);
pParent->ScreenToClient(rect); pParent->InvalidateRect(rect, bErase);
}BOOL CStaticTrans::OnEraseBkgnd(CDC* pDC)
{
return true;
}在你的工程中用CStaticTrans对象即可。应该没有你说的这些毛病。
2、在对Static SetWindowText之前,先对父窗口InvalidateRect和UpdateWindow,重画Static所占用的父窗口位置(擦除Static以前绘制的文本)。注意InvalidateRect中应该仅把Static所占用的rect送进去(通过Static的GetWindowRect和父窗口的ScreenToClient获得),而不要重画整个父窗口,否则严重影响性能,并且闪烁。
3、(重要!)由于父窗口重画会导致Static的客户区无效,因此父窗口重画完成后会自动再次引发static的重画,从而无法达到擦除的目的,因此,在父窗口重画完成后(父窗口OnPaint的最后),要调用Static的ValidateRect(NULL),使其客户区有效化,从而避免其重画。
1、背景透明
2、快速变化文字
3、CPU利用率及风扇不狂转
那些回复没有能实现的。
如果楼主要自己实现。可以用代码截取父窗口背景图,然后BitBlt到static背景上。然后在背景上写字。注意。这两步要在内存dc上实现,然后弄好后,一次性贴到OnPaint的dc上。在static的OnEraseBkgnd中直接return TRUE,以防止背景闪烁。
如果楼主不想自己写代码,可以用LibUIDK界面库,你说的都已经实现好了。你1毫秒刷新一次也没问题。闪烁与刷新频率没有关系,并且这点小事,不可能导致cpu风扇狂转的。
{
if(ParentBitmap==NULL)return;
CPaintDC dc(this);
CRect lo_rcClient;
this->GetClientRect(&lo_rcClient);
CDC lo_dcMem;
lo_dcMem.CreateCompatibleDC(&dc);
lo_dcMem.SelectObject(ParentBitmap);
lo_dcMem.SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));
lo_dcMem.Rectangle(1,1, lo_rcClient.right, lo_rcClient.bottom);
//lo_dcMem.SetBkMode(TRANSPARENT);
lo_dcMem.SetTextColor(RGB(255,0,0));
CFont* lo_pFont = this->GetFont();
lo_dcMem.SelectObject(lo_pFont);
lo_dcMem.TextOut(Bound.left, Bound.top,Caption);
::BitBlt(dc, 0, 0, lo_rcClient.Width(), lo_rcClient.Height(), lo_dcMem, Bound.left, Bound.top, SRCCOPY);
::DeleteDC(lo_dcMem);}上面就是我继承了CStatic,叫做Label类,自绘OnPaint过程的代码。
但,有一个关键的问题:
背景图片能正常绘制,但:
写文字的效果出现问题,加入
lo_dcMem.SetBkMode(TRANSPARENT);
就会出现文字部分(仅文字区域部分)重叠,黑乎乎的。
不加这句吧,文字区域部分又不透明,
下面的代码是测试通过的:void CAaaDlg::OnPaint()
{
CDialog::OnPaint();
GetDlgItem(IDC_STATIC_1)->ValidateRect(NULL);
}BOOL CAaaDlg::OnEraseBkgnd(CDC* pDC)
{
CRect rect;
CDC MemDC;
BITMAP bm;
CBitmap *pbmpOld; GetClientRect(&rect);
m_bmpBack.GetBitmap(&bm);
MemDC.CreateCompatibleDC(pDC);
pbmpOld = MemDC.SelectObject(&m_bmpBack);
pDC->SetStretchBltMode(COLORONCOLOR);
pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), &MemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
MemDC.SelectObject(pbmpOld);
MemDC.DeleteDC(); return TRUE;
}HBRUSH CAaaDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if(pWnd->GetDlgCtrlID() == IDC_STATIC_1) {
pDC->SetBkMode(TRANSPARENT);
return (HBRUSH)GetStockObject(NULL_BRUSH);
} return hbr;
}void CAaaDlg::OnTimer(UINT nIDEvent)
{
static int n = 0;
CString str; CRect rect;
GetDlgItem(IDC_STATIC_1)->GetWindowRect(&rect);
ScreenToClient(&rect);
InvalidateRect(&rect);
UpdateWindow(); str.Format("%d", n++);
GetDlgItem(IDC_STATIC_1)->SetWindowText(str);
}
你的代码,仍然是风扇狂转啊。
我是8G内存,500G硬盘,I73.6G的CPU,够强悍了吧,照样狂转。
http://topic.csdn.net/u/20100818/17/2b5209c7-b366-48d3-a657-6b321dbebae9.html
首先,在多个线程都需要访问的数据中,不能使用CString(比如你的那个Label类的成员Caption),因为CString内部所设计的算法就是不适合多线程的;
第二,即使你把CString改成字符数组也是不够的,既然有多个线程都要访问、并且至少一个线程需要写入,那么对这个变量的访问应该进行同步处理;
第三,不要在多个线程中对同一个界面元素进行操作(比如你在子线程中对主线程界面上的Label窗口进行Invalidate),否则不能保证不出问题。当然,就你目前所做的操作而言,还不至于出什么问题,但假若你以后对功能进行一些改进和调整呢?在现有的这个不安全的架构之上再添几句,就有可能出问题了。正确的方式是:谁的界面元素谁操作,其他线程如果需要改变界面的话,都应通过消息传递(PostMessage或者SendMessage)之类的机制来通知拥有界面的线程所需要进行的操作(这样的封装性也好得多,否则当你发现你的界面改变的时候,你连这段代码写在哪都很难找)。
邮件收到了吗?
帮我解决一下吧,谢谢