我有一个 WIN32 应用程序。它的主窗口是
hwndMain
,它的子窗口之一是 hwndView
。 hwndTab
上有一个选项卡控件 hwndView
。
当我调整
hwndMain
的大小时,hwndView
会调整大小,hwndTab
也会调整。有点闪烁,但不多。
我尝试使用
WS_EX_COMPOSITED
样式(用于 hwndView
或 hwndTab
),但它只是给了我空白窗口。我尝试使用WS_EX_TRANSPARENT
并且它解决了闪烁,但是当窗口大小调整为更大时,子级更新非常慢,例如我看到黑色区域一秒钟,然后该区域被更新。
我已经通过使用
TreeView
风格成功解决了WS_CHIPCHILDREN
的闪烁问题。 (见下面的注释)。但使用 WS_CHIPCHILDREN
stlye 代替 hwndView
并不能解决选项卡控件的闪烁问题。
我也关注了
WM_ERASEBKGND
和Not set hbrBackground
。
我想使用双缓冲区进行选项卡控制,但我找不到用于此目的的教程。我找到的所有教程都是:在
WM_PAINT
中,创建CompatibleDC
和CompatibleBitmap
后,在memdc
中画出你想要的东西......;但我不想在 WM_PAINT
中为 hwndTab
进行任何自定义绘图。我只想让选项卡控件完成这项工作,但只显示最终结果。
有人可以用
c
+ winapi
语言向我展示一个如何双缓冲选项卡控件的小示例(如果您认为这会解决选项卡控件的闪烁问题),因为我不具备以下知识: C#、Net 等
备注:对于我的 TreeView,它是窗口的子窗口
hwndContainer
。它的创建方式为:
win->hwndContainer = CreateWindowEx(
WS_CLIPCHILDREN,
_T("SUMATRA_PDF_TOCBOX"), NULL,
WS_CHILD,
0, 0, gGlobalPrefs.sidebarDx, 0,
win->hwndPanel, NULL,
ghinst, NULL);
使用
WS_CLIPCHILDREN
修复闪烁,即使我不使用双缓冲区。但奇怪的是
WS_CLIPCHILDREN
在第一个参数位置。如果我把它放在 WS_CHILD 之后,即
win->hwndContainer = CreateWindowEx(
NULL,
_T("SUMATRA_PDF_TOCBOX"), NULL,
WS_CHILD | WS_CLIPCHILDREN,
0, 0, gGlobalPrefs.sidebarDx, 0,
win->hwndPanel, NULL,
ghinst, NULL);
,然后仍然出现闪烁。
所以我在创建
hwndView
时也尝试使用第一种方法,但它只是给出了空白的白色窗口。
我真的对这些东西很困惑。
这是我使用
WS_EX_COMPOSITED
代替 hwndView
时的空白窗口图片。
我用的时候没有这个问题hwndContainer
.
hwndView
实际上有两个子控件:一个选项卡控件hwndTab
和一个拥有自己的双缓冲区和绘图的子控件。我不确定这是否会导致使用问题WS_EX_COMPOSITED
。
您正在使用
WS_EX_COMPOSITED
风格。当您将 WS_CLIPCHIDREN
作为第一个参数传递给 CreateWindowEx
时,它会将 WS_CLIPCHILDREN
的值解释为 extended 窗口样式。由于 WS_CLIPCHILDREN
的值为 0x02000000L
,与 WS_EX_COMPOSITED
相同,因此您刚刚创建了一个复合窗口。
根据文档,复合窗口的所有后代都使用双缓冲按照从下到上的绘制顺序进行绘制。
我不确定你说的是什么意思:
我尝试使用 WS_EX_COMPOSITED 样式(用于 hwndView 或 hwndTab),但它只是给了我空白窗口。
您必须发布重现此问题的代码。但是您的倒数第二个代码片段is生成了一个合成窗口。
在我的 Jav/win32 库中,我有一个类可以解决这个问题。我将在这里展示这个想法,同时为整个班级提供一点开胃菜。
namespace Jav { namespace win32 {
struct TabsBarEx : Jav::win32::TabsBar
{
.... ctor and methods ....
protected:
int prevTabIndex = -1;
RECT displayArea;
private:
static LRESULT CALLBACK proc(HWND,UINT,WPARAM,LPARAM,UINT_PTR,DWORD_PTR);
};
}}
LRESULT CALLBACK TabsBarEx::proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam,UINT_PTR subClassId,DWORD_PTR obj)
{
TabsBarEx &tabs = *((TabsBarEx*)obj);
auto getWidth = [lparam](){ return LOWORD(lparam); };
auto getHeight = [lparam](){ return HIWORD(lparam); };
auto mouseX = [lparam](){ return LOWORD(lparam); };
auto mouseY = [lparam](){ return HIWORD(lparam); };
switch(msg)
{
case WM_DESTROY:
ImageList_Destroy(win32::setImageList(tabs,NULL));
return DefSubclassProc(hwnd,msg,wparam,lparam);
case WM_NCDESTROY:
deleteObject(&tabs);
RemoveWindowSubclass(hwnd,tabsBarProc,0);
return DefSubclassProc(hwnd,msg,wparam,lparam);
case WM_SIZE:
tabs.onSize(getWidth(),getHeight());
return 0;
case WM_PAINT:
{
tabs.onDraw();
return 0;
}
case WM_MOUSEMOVE:
tabs.onMouseMove(mouseX(),mouseY());
return 0;
case WM_MOUSELEAVE:
tabs.onMouseExit();
return 0;
case WM_LBUTTONDOWN:
tabs.onLeftClick(mouseX(),mouseY(),wparam);
return 0;
case WM_RBUTTONDOWN:
tabs.onRightClick(mouseX(),mouseY());
return 0;
case TCM_SETCURSEL:
return tabs.onSelectTab(wparam);
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLOREDIT:
return SendMessage(GetParent(hwnd),msg,wparam,lparam);
case WM_COMMAND:
case WM_NOTIFY:
return DefSubclassProc(hwnd,msg,wparam,lparam);
default:
if(msg >= WM_APP && msg <= 0xBFFF) return SendMessage(GetParent(hwnd),msg,wparam,lparam);
else return DefSubclassProc(hwnd,msg,wparam,lparam);
}
}
}
TabsBarEx::TabsBarEx(HWND parent,int id,const RECT &bounds,int style,int ex_style)
: TabsBar(parent,id,{},style,ex_style)
{
HIMAGELIST imageList = newImageList(16,16,2);
addBitmapRes(imageList,"IC_CLOSE_16",RGB(255,255,255));
addBitmapRes(imageList,"IC_CLOSE_BLACK_16",RGB(255,255,255));
SetWindowSubclass(*this,proc,0,(DWORD_PTR)this);
this->setImageList(imageList);
}
void TabsBarEx::onSize(int w,int h)
{
displayArea = {0,0,w,h};
this->getDisplayArea(displayArea);
Jav::win32::Widget widget = (HWND)this->getObject(this->getActiveTab());
widget.layout(displayArea.left, displayArea.top, displayArea.right-displayArea.left, displayArea.bottom-displayArea.top);
}
void TabsBarEx::onDraw()
{
PAINTSTRUCT ps;
Jav::win32::Canvas canvas;
canvas.hwnd = this->hwnd;
canvas.win_ctx = BeginPaint(this->hwnd,&ps);
canvas.clipOutRect(displayArea);
SendMessage(this->hwnd,WM_PRINT,(WPARAM)canvas.win_ctx,PRF_CLIENT);
EndPaint(this->hwnd,&ps);
}