使用WINAPI示例(不使用MFC)的对话框中的属性表



有人能给我举一个使用WINAPI(而不是MFC)在对话框中嵌入属性表的WINAPI示例吗?

下面是我在调查这个问题。我从在这里或通过搜索网页提问。感谢所有你的帮助!

我写了一个类来封装我所发现的一切;如果有兴趣获得副本,请给我发电子邮件mdorl@wisc.edu.

在中传递属性表的父窗口的HWND创建属性表时PROPSHETHEADER的.hwindParent使用PropertySheet页面函数。

我使用对话框上的图片控件作为属性的父项表,所以这就是我用作hwndParent的HWND。

使用回调更改属性表的样式pfnCallback字段在标头中,不要忘记包含dwFlags中的PSH_USECALLBACK。请参阅中的PropSheetProc函数MSDN。在回调的PSCB_ PRECREATE处理程序中,通过删除来调整属性表的窗口样式并添加WS_CHILD。我不想要边界或头衔栏,所以我还删除了WS_CAPTION、WS_SYSEMNU,&DS_MODALFRAME

LONG L = ((LPDLGTEMPLATE)lParam)->style;
L &= ~WS_POPUP; 
L &= ~WS_CAPTION;       // gets rid of title bar
L &= ~WS_SYSMENU;       
L &= ~DS_MODALFRAME;        // gets rid of border
L |=  WS_CHILD;         // 40000000
((LPDLGTEMPLATE)lParam)->style = L;

使用子窗口而不是弹出窗口巧妙地解决了问题一些问题,例如当父级移动,正确保持父窗口的蓝色/灰色状态彩色和剪辑问题。也就是说,你不必担心这些事情。

如果你停在这里,你将面临另一个问题。对话框支持WIN32中的代码会进入cpu循环,试图找到属性表控件。参见

什么是WS_EX_CONTROLPARENT和DS_CONTROL?

对于这个问题。解决方案是添加扩展的WS_EX_CONTROLPARENT样式添加到属性表。您可以找到有关此的信息在web上搜索WS_EX_CONTROLPARENT你找不到的东西给我带来了很大的悲痛。如果使用对话框上的控件作为父级,还必须设置其WS_EX_CONTROLPARENT

我不知道WS_EX_CONTROLPARENT和DS_CONTROL之间的区别,也不知道是否可以用DS_CONTROL代替WS_EX_CONTROLPARENT。从网上我了解到DS_CONTROL与选项卡有关。我的测试应用程序在有或没有DS_CONTROL的选项卡上都能正常工作。

我在调用PropertySheet函数来创建属性表。我不知道是否可以在回叫程序中执行此操作。我想可以在回调中使用GetParent来获取控制

LONG S;
S = GetWindowLong (hwndPS, GWL_EXSTYLE) | WS_EX_CONTROLPARENT;
SetWindowLong (hwndPS, GWL_EXSTYLE, S);
S = GetWindowLong (hwndPS_Area, GWL_EXSTYLE) | WS_EX_CONTROLPARENT;
SetWindowLong (hwndPS_Area, GWL_EXSTYLE, S);

在使用PropertySheet函数创建属性表之后,你必须正确定位:

SetWindowPos(hwndPS, HWND_TOP, 2, 2, -1, -1,
SWP_NOSIZE | SWP_NOACTIVATE); 

我允许边界使用几个像素。

如果你想去掉所有的属性表按钮及其占用的空间:

RECT rectWnd;
RECT rectButton;
GetWindowRect(hwndPS, &rectWnd);
HWND hWnd = ::GetDlgItem(hwndPS, IDOK);
if(!hWnd)
{
DebugBreak();
}
GetWindowRect(hWnd, &rectButton);
SetWindowPos (hwndPS, NULL, 0, 0,
rectWnd.right - rectWnd.left, rectButton.top - rectWnd.top,
SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);

可以取消单个按钮:

hwndOk = GetDlgItem (hwndPS,IDOK);              // Hide the OK button
ShowWindow (hwndOk, SW_HIDE);
EnableWindow (hwndOk, FALSE);

您可以使用PSH_NOAPPLYNOW取消APPLY按钮创建属性表时PROPERTYSHEETHEADER中的dwFlags。

只有用户第一次创建属性页激活它们。我希望它们都能在房产工作表已创建。

unsigned int iP;
for (iP=0; iP<Header.nPages; iP++)
{
if (iP != Header.nStartPage)
SendMessage (hwndPS, PSM_SETCURSEL,iP,NULL);
}
SendMessage (hwndPS, PSM_SETCURSEL,Header.nStartPage,NULL);

有一个PROPSHEETPAGE标志做同样的事情(来自MSDN)

PSP_REMATURE 4.71版。当属性表已创建。如果未指定此标志,则页面在第一次选择之前不会创建。

但我担心4.71版本的业务,所以我自己做了。

您可以更改任何按钮上的文本:

SetDlgItemText (hwndPS,ButtonID,Text);

其中ButtonID是IDOK IDCANCEL IDHELP IDAPPLYNOW 之一

IDAPPLYNOW在我的系统上未定义,因此

#define IDAPPLYNOW     0x3021   

以下是我打算如何使用我的财产清单。我要把所有的初始化和包含属性表的对话框中的终止代码,并删除所有属性表按钮。当用户按下一些DO IT按钮时,我可以在那里设置所有的初始值,并检索所有的最终值。我注意到,例如,设置文本框的行为会导致包含页面对话框获得WM_COMMAND/EN_CHANGE。如果使用此消息启用APPLY按钮,则可能需要在设置任何列表框后禁用页面的更改标志。我通过在设置初始值后清除所有更改的标志来解决这个问题。(我怀疑在发送完所有INITDIALOG消息后,属性表会清除已更改的标志。在任何情况下,如果在页面INITDIALOG处理程序中设置了文本框,则APPLY都不会启用。)如果我发现错误,我会选择该属性表页面,并在父对话框中放入一些红色文本来描述错误。属性表对话框过程唯一需要做的就是操作它们的控件。

令我困惑的一件事是,如何确定是否所有页面都从其WS_NOTIFY/PSN_APPLY消息中返回了PSNRET_NOERROR。我在数当报告PSNRET_INVALID或接收到PSN_KILLACTIVE时,将计数设置为零的连续PSNRET_NOERROR回复的数目。如果计数达到属性表标题中的页数,我假设所有页面都返回了PSNRET_NOERROR。但我担心诸如禁用和不可见页面之类的事情。

最新更新