【问题标题】:How to respond to a PropertySheet's OK or Apply button after the pages have processed it?页面处理后如何响应 PropertySheet 的 OK 或 Apply 按钮?
【发布时间】:2010-12-02 19:14:49
【问题描述】:

PropertySheet API 允许您定义一个PropSheetProc,它可以(在 Windows XP 及更高版本上)在按下“确定”或“应用”按钮时接收消息。这使您可以在单击这些按钮之一时进行处理。

但是,在各个属性页通过其各自的对话过程接收PSN_APPLY 通知之前调用此处理程序。我想在处理完这些通知之后处理,最好没有丑陋的黑客攻击。我该怎么做?

背景:我将我的配置存储在单个struct 中,并且各个页面在应用时都会修改此struct 的部分内容。然后,在写入这些值之后,我想一次性应用 struct 中的设置,而不是从每个属性页重新应用所有设置。

【问题讨论】:

    标签: winapi button propertysheet


    【解决方案1】:

    我最终使用PropSheetProc 回调来捕获属性表的窗口句柄,然后连接一个子类窗口过程,如下所示:

    // This is not officially defined, but the whole world uses it.
    #define ID_APPLY_NOW 0x3021
    
    WNDPROC origWinProc;
    
    LRESULT CALLBACK MyWinProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) {
      // Call the original window procedure.
      LRESULT retVal = CallWindowProc(origWinProc, hwndDlg, msg, wParam, lParam);
      // Now, and only now, do our own stuff.
      switch (msg) {
        case WM_COMMAND:
          switch (LOWORD(wParam)) {
            case IDOK:
            case ID_APPLY_NOW:
              applyConfig();
              saveConfig();
              break;
          }
          break;
      }
      // Return the original winproc's result.
      return retVal;
    }
    
    int CALLBACK myPropSheetProc(HWND hwndDlg, UINT msg, LPARAM lParam) {
      switch (msg) {
        case PSCB_INITIALIZED:
          // Override the property sheet's window procedure with our own.
          origWinProc = (WNDPROC)SetWindowLongPtr(hwndDlg, GWLP_WNDPROC, (LONG_PTR)&MyWinProc);
          break;
      }
      return 0;
    }
    

    (是的,即使只有一种情况需要考虑,我也会使用switch 语句。这样我很奇怪。)

    【讨论】:

      【解决方案2】:

      您不能只拦截 IDOK、IDAPPLY 和 IDCANCEL 的 WM_COMMAND 的 BL_CLICKED 消息吗?

      您在使用 MFC 吗?还是 ATL?

      虽然我想不出有什么时候我无法拦截 BM_CLICKED...

      编辑:嗯,从来没有通过该功能使用过属性页...只是读过它。你设置了pfnCallback函数和PSH_USECALLBACK标志设置了吗?

      每个页面也有一个对话过程。你不能从那里截取确定、取消和申请吗?不过,我认为另一个计划似乎更适合。

      【讨论】:

      • 我必须在我的主消息循环中执行此操作,该循环位于应用程序的一个完全不相关的部分中。而且我什至不确定这些消息是否流经那里,因为PropertySheet() 直到属性表对话框关闭后才会返回。
      • @Edit:我正在使用pfnCallback,它被调用得很好,但是任何单个属性表的对话框过程之前。我想所有这些都完成他们的工作之后再做一些事情。
      【解决方案3】:

      您不需要从任何对话框处理程序中应用结构。所以,如果它是一个模态属性表,你可以做一些简单的事情,比如:

      // Display the property sheet.
      PropertySheet(&theSheet);
      // The peroperty sheets PSN_APPLY notification sets this bool to true in the struct.
      if(theStruct.fApply)
        ApplyTheStruct(&theStruct);
      

      另外,我不明白为什么,鉴于“结构”只是收集在页面上输入的信息,您不会在用户与页面交互时更改结构。忽略每页的PSN_APPLY 消息并在调用 PropSheetProc 时应用该结构。或者如果通知是PSN_CANCEL,则完全丢弃它。

      【讨论】:

      • 那行不通。如果用户点击应用,则需要应用东西,但PropertySheet 函数尚未返回。
      • PropertySheet函数会先发送PSN_APPLY消息PRopSheetProc,然后到每个页面,然后返回。现在将设置结构,您可以应用它吗?在属性表明显关闭之前“应用”结构真的很重要吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-02
      • 2016-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多