子窗口如何响应其父窗口的变化

发布于 2024-09-25 22:07:01 字数 67 浏览 1 评论 0原文

在 Win32 应用程序中,当子窗口被放置到不同的父窗口中时,是否有 Windows 消息或其他一些通知将被发送到子窗口

In a Win32 app is there a Windows message or some other notification that will get sent to a child window when it is placed into a different parent

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

攀登最高峰 2024-10-02 22:07:01

这很容易在 Windows 窗体应用程序中进行测试。这就是我所看到的:

msg=0x18 (WM_SHOWWINDOW) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0x85 (WM_NCPAINT) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x14 (WM_ERASEBKGND) hwnd=0x60c60 wparam=0xffffffff930119e8 lparam=0x0 result=0x0
msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0xf (WM_PAINT) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xe (WM_GETTEXTLENGTH) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xd (WM_GETTEXT) hwnd=0x60c60 wparam=0x6 lparam=0x3fd7928 result=0x0

WM_SHOWWINDOW 是检查父级是否更改的好时机。不能 100% 确定这是否是 WF 代码处理更改的父级的副作用,但可能性相当高。否则没有专门的消息,假设程序已经知道,因为它显式调用了 SetParent 或 SetWindowLongPtr。

This is easy to test in a Windows Forms app. This is what I saw:

msg=0x18 (WM_SHOWWINDOW) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x46 (WM_WINDOWPOSCHANGING) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0x85 (WM_NCPAINT) hwnd=0x60c60 wparam=0x1 lparam=0x0 result=0x0
msg=0x14 (WM_ERASEBKGND) hwnd=0x60c60 wparam=0xffffffff930119e8 lparam=0x0 result=0x0
msg=0x47 (WM_WINDOWPOSCHANGED) hwnd=0x60c60 wparam=0x0 lparam=0x563e01c result=0x0
msg=0xf (WM_PAINT) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xe (WM_GETTEXTLENGTH) hwnd=0x60c60 wparam=0x0 lparam=0x0 result=0x0
msg=0xd (WM_GETTEXT) hwnd=0x60c60 wparam=0x6 lparam=0x3fd7928 result=0x0

WM_SHOWWINDOW would be a good time to check if the parent changed. Not 100% sure if this is a side effect of the WF code taking care of the changed parent, the odds are fairly high. There is otherwise no dedicated message for it, the assumption is that the program already knows since it called SetParent or SetWindowLongPtr explicitly.

雨轻弹 2024-10-02 22:07:01

没有专门针对此的单一通知。然而,一些框架,如 Borland 的 VCL,将窗口包装在类中,因此当类对象从一个父级移动到另一个父级时,会发出自己的通知(例如,VCL 有 CM_CONTROLLISTCHANGINGCM_CONTROLLISTCHANGECM_CONTROLCHANGE 通知)。

您能否提供更多有关通过检测父窗口的更改到底想要完成什么操作的信息?

There is no single notification specifically for this. However, some frameworks, like Borland's VCL, wrap windows in classes, and thus issue their own notifications when the class objects are moved around from one parent to another (for example, VCL has CM_CONTROLLISTCHANGING, CM_CONTROLLISTCHANGE, and CM_CONTROLCHANGE notifications).

Can you provide more information about what exactly you want to accomplish by detecting a change in parent window?

奈何桥上唱咆哮 2024-10-02 22:07:01

有点...我在使用 Windows 之间的消息传递和侦听它们的线程之前已经完成了此操作。请记住,您不想从创建它的线程之后的任何线程修改 UI...

以下是父窗口的一些示例代码,它会收到其子窗口之一的更改通知。当做你正在谈论的事情时,同样的原则也适用。当子窗口打开时,父窗口并没有真正发送消息(确实如此,但我忘记了当时它的想法)......自从我不得不做这样的事情以来已经过去了 10 年......但下面的代码是为带有网格的父窗口和打开的子“添加/编辑”窗口而设计的,当您添加或编辑项目时,它将更新模态编辑窗口后面的父网格。这是在 MFC 中设计的,所以你想象一下,你只需要在函数调用中添加一些 HWND 变量即可使其在 Win32 下工作,因为 Win32 和 MFC 是如此相互关联。

首先,在父窗口中,我设置一个线程:

DWORD WINAPI PopulateGridThread(void *ptr)
{
   CMeterReadings *pThis = (CMeterReadings*)ptr;
   pThis->hGridMutex = CreateMutex(NULL, FALSE, "Wims.MeterReadingGridUpdateMutex");
   WaitForSingleObject(pThis->hGridMutex, 0);
   if(WaitForSingleObject(pThis->hGridMutex, 0) != WAIT_OBJECT_0) {
      return -2;
   }
   try {
      if(pThis->m_Get.GetCheck() == FALSE)
      {
         if(pThis->m_Grid.IsEmpty())
         {
            CloseHandle(pThis->hGridMutex);
            CloseHandle(pThis->hThreadHandle);
            pThis->hThreadHandle = INVALID_HANDLE_VALUE;
            pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
            pThis->m_UseDate.EnableWindow(TRUE);
            pThis->m_MeterFilter.EnableWindow(TRUE);
            return -3;
         }
      }

      pThis->hCursor = LoadCursor(NULL, IDC_APPSTARTING);
      pThis->m_Get.SetCheck(FALSE);
      pThis->m_DateFilter.EnableWindow(FALSE);
      pThis->m_UseDate.EnableWindow(FALSE);
      pThis->m_MeterFilter.EnableWindow(FALSE);
      pThis->m_Grid.PushRow();
      pThis->m_Grid.ResetContent();
      bool        bSuccess = false;
      long        nId = CCommonDialog::GetItemData(pThis->m_MeterFilter);
      bool        bUseDate = pThis->m_UseDate.GetCheck() == TRUE;
      CProDate   dtFilterDate;
      pThis->m_DateFilter.GetTime(dtFilterDate);

      if(nId == NULLCONSTANT || nId == LB_ERR)
      {
          bSuccess  = pThis->m_EquipmentPtr.LoadFirstMeterReading(bUseDate ?   CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate(), true);
      }
      else
      {
          bSuccess = pThis->m_EquipmentPtr.LoadFirstMeterReadingByMeterId(nId, bUseDate ? CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate());
   }      
   if(pThis->m_EquipmentPtr.GetRecordsReturned() > 5000) 
   {
      if(ThrowQuestion("This expansion could take a long time.  Do you wish to continue?", pThis) == IDNO)
      {
         bSuccess = false;
      }
   }      
   pThis->m_Get.SetWindowText("&Stop");
   if(bSuccess)
   {
      pThis->m_Grid.Redraw(false);
      do
      {
         pThis->m_Grid.AddGridRow();
         pThis->m_Grid.SetCellFormat(COLUMN_ADJUSTMENT,               "Yes;No");
         pThis->m_Grid.SetCheck(COLUMN_ADJUSTMENT,                    pThis->m_EquipmentPtr.AdjustmentIndc);
         pThis->m_Grid.AddDatesToGrid(pThis->m_EquipmentPtr.ReadingDate,     pThis->m_EquipmentPtr.EffectiveDate);
         pThis->m_Grid.AddTextToGrid(COLUMN_METER,                    pThis->m_EquipmentPtr.MeterDesc);
         /* Cut the rest of the fields, as they aren't important... */
      }
      while(pThis->m_EquipmentPtr.LoadNextMeterReading());
   }
   pThis->m_Grid.FinishGrid();
   pThis->m_Grid.Redraw(true);
   pThis->m_Grid.PopRow();
   pThis->m_Grid.RedrawWindow();
}
CATCH_COM_ERROR("CMeterReadings::PopulateGridThread()")
CloseHandle(pThis->hGridMutex);
CloseHandle(pThis->hThreadHandle);
pThis->hThreadHandle = INVALID_HANDLE_VALUE;
pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
pThis->m_UseDate.EnableWindow(TRUE);
pThis->m_MeterFilter.EnableWindow(TRUE);
pThis->hCursor = LoadCursor(NULL, IDC_ARROW);
pThis->m_Get.SetWindowText("&Get");
return 1;

}

然后,在子窗口中,当需要更新时,我会向父窗口发送一条消息。我通过创建一个仅发送消息的线程来完成此操作,以便对话框的其余部分将继续运行...(或者在您的情况下,您可以直接向子 Windows HWND 发送消息以使其更新.. .)

void _cdecl GridUpdateThread(void *ptr)
{
   CEnterMeterReadingsDlg *pthis = (CEnterMeterReadingsDlg*)ptr;
   if(pthis->NotifyParent())
   {
      pthis->NotifyParent()->SendMessage(CMeterReadings::GRID_UPDATE_MESSAGE, 0, 0);
   }
}

然后,当用户在对话框中选择“下一步”而不是“确定”或“取消”时,所有这一切都开始启动...

_beginthread(GridUpdateThread, NULL, this);

好吧,希望这会对您有所帮助,或者给您一些想法...

Sort-of... I've done this before using messaging between Windows, and a thread to listen on them. Remember, you do NOT want to modify the UI from any thread then the one that CREATED it...

Here is some example code of a Parent Window, which gets notified of a change by one of its children Windows. The same principle applies when doing what you are talking about. The parent Windows isn't really pumping messages while the child is open, (it IS, but I forget what is going through its mind at the time)... It's been 10 years since I had to do anything like this... But the code below is designed for a parent Window with a grid, and a child "Add/Edit" window that opens, and when you add or edit an item, it will update the parent GRID behind the Modal Edit window. This was designed in MFC, so you an imagine, you just need to add some HWND vars to the function calls to make it work under Win32, since Win32 and MFC are so inter-related.

First, in the parent Window, I setup a thread:

DWORD WINAPI PopulateGridThread(void *ptr)
{
   CMeterReadings *pThis = (CMeterReadings*)ptr;
   pThis->hGridMutex = CreateMutex(NULL, FALSE, "Wims.MeterReadingGridUpdateMutex");
   WaitForSingleObject(pThis->hGridMutex, 0);
   if(WaitForSingleObject(pThis->hGridMutex, 0) != WAIT_OBJECT_0) {
      return -2;
   }
   try {
      if(pThis->m_Get.GetCheck() == FALSE)
      {
         if(pThis->m_Grid.IsEmpty())
         {
            CloseHandle(pThis->hGridMutex);
            CloseHandle(pThis->hThreadHandle);
            pThis->hThreadHandle = INVALID_HANDLE_VALUE;
            pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
            pThis->m_UseDate.EnableWindow(TRUE);
            pThis->m_MeterFilter.EnableWindow(TRUE);
            return -3;
         }
      }

      pThis->hCursor = LoadCursor(NULL, IDC_APPSTARTING);
      pThis->m_Get.SetCheck(FALSE);
      pThis->m_DateFilter.EnableWindow(FALSE);
      pThis->m_UseDate.EnableWindow(FALSE);
      pThis->m_MeterFilter.EnableWindow(FALSE);
      pThis->m_Grid.PushRow();
      pThis->m_Grid.ResetContent();
      bool        bSuccess = false;
      long        nId = CCommonDialog::GetItemData(pThis->m_MeterFilter);
      bool        bUseDate = pThis->m_UseDate.GetCheck() == TRUE;
      CProDate   dtFilterDate;
      pThis->m_DateFilter.GetTime(dtFilterDate);

      if(nId == NULLCONSTANT || nId == LB_ERR)
      {
          bSuccess  = pThis->m_EquipmentPtr.LoadFirstMeterReading(bUseDate ?   CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate(), true);
      }
      else
      {
          bSuccess = pThis->m_EquipmentPtr.LoadFirstMeterReadingByMeterId(nId, bUseDate ? CProDate::GetDateOnly(dtFilterDate) : CProDate::NullDate());
   }      
   if(pThis->m_EquipmentPtr.GetRecordsReturned() > 5000) 
   {
      if(ThrowQuestion("This expansion could take a long time.  Do you wish to continue?", pThis) == IDNO)
      {
         bSuccess = false;
      }
   }      
   pThis->m_Get.SetWindowText("&Stop");
   if(bSuccess)
   {
      pThis->m_Grid.Redraw(false);
      do
      {
         pThis->m_Grid.AddGridRow();
         pThis->m_Grid.SetCellFormat(COLUMN_ADJUSTMENT,               "Yes;No");
         pThis->m_Grid.SetCheck(COLUMN_ADJUSTMENT,                    pThis->m_EquipmentPtr.AdjustmentIndc);
         pThis->m_Grid.AddDatesToGrid(pThis->m_EquipmentPtr.ReadingDate,     pThis->m_EquipmentPtr.EffectiveDate);
         pThis->m_Grid.AddTextToGrid(COLUMN_METER,                    pThis->m_EquipmentPtr.MeterDesc);
         /* Cut the rest of the fields, as they aren't important... */
      }
      while(pThis->m_EquipmentPtr.LoadNextMeterReading());
   }
   pThis->m_Grid.FinishGrid();
   pThis->m_Grid.Redraw(true);
   pThis->m_Grid.PopRow();
   pThis->m_Grid.RedrawWindow();
}
CATCH_COM_ERROR("CMeterReadings::PopulateGridThread()")
CloseHandle(pThis->hGridMutex);
CloseHandle(pThis->hThreadHandle);
pThis->hThreadHandle = INVALID_HANDLE_VALUE;
pThis->m_DateFilter.EnableWindow(pThis->m_UseDate.GetCheck());
pThis->m_UseDate.EnableWindow(TRUE);
pThis->m_MeterFilter.EnableWindow(TRUE);
pThis->hCursor = LoadCursor(NULL, IDC_ARROW);
pThis->m_Get.SetWindowText("&Get");
return 1;

}

Then, in the child Window, I would send a message back to the parent, when it was time to update. I did this by creating a thread that simply sent the message, so that the rest of the dialog would continue to function... (Or in your case, you could send a message directly to the Child Windows HWND to make it update...)

void _cdecl GridUpdateThread(void *ptr)
{
   CEnterMeterReadingsDlg *pthis = (CEnterMeterReadingsDlg*)ptr;
   if(pthis->NotifyParent())
   {
      pthis->NotifyParent()->SendMessage(CMeterReadings::GRID_UPDATE_MESSAGE, 0, 0);
   }
}

Then, all this was set into motion when the user selected "NEXT" on the dialog, instead of OK, or CANCEL...

_beginthread(GridUpdateThread, NULL, this);

Well, hopefully this will help you some, or give you some ideas...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文