子窗口如何响应其父级的更改

时间:2010-10-04 20:11:49

标签: winapi windows-messages

在Win32应用程序中有一条Windows消息或一些其他通知,当它被放入另一个父窗口时将被发送到子窗口

3 个答案:

答案 0 :(得分:2)

这很容易在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。

答案 1 :(得分:0)

没有专门针对此的通知。但是,某些框架(如Borland的VCL)会在类中包装窗口,因此当类对象从一个父项移动到另一个父项时会发出自己的通知(例如,VCL具有CM_CONTROLLISTCHANGINGCM_CONTROLLISTCHANGE,和CM_CONTROLCHANGE通知)。

您是否可以通过检测父窗口中的更改来提供有关您想要完成的内容的更多信息?

答案 2 :(得分:0)

Sort-of ...我在使用Windows之间的消息传递和一个侦听它们的线程之前完成了这个。请记住,您不希望从任何线程修改UI,而是创建它...

以下是父窗口的一些示例代码,它通知其子窗口之一的更改。在做你正在谈论的事情时,同样的原则也适用。当孩子开放时,父母Windows并没有真正地传递信息(事实上,但我忘记了当时的想法)......自从我不得不做这样的事情已经10年了......但是下面的代码是为具有网格的父窗口和打开的子“添加/编辑”窗口设计的,当您添加或编辑项目时,它将更新“模态编辑”窗口后面的父GRID。这是在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;

}

然后,在子窗口中,我会在需要更新时将消息发送回父级。我这样做是通过创建一个简单发送消息的线程,以便对话的其余部分继续运行...(或者在您的情况下,您可以直接向Child 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);

嗯,希望这会帮助你一些,或者给你一些想法......