在 Win32 应用程序中,是否有一条 Windows 消息或一些其他通知,当它被放置到不同的父窗口时,它会被发送到子窗口
3 回答
这很容易在 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。
没有专门针对此的单一通知。然而,一些框架,如 Borland 的 VCL,将窗口包装在类中,因此当类对象从一个父对象移动到另一个父对象时(例如,VCL 具有 、 和 通知),它们会发出自己CM_CONTROLLISTCHANGING
的CM_CONTROLLISTCHANGE
通知CM_CONTROLCHANGE
。
您能否通过检测父窗口中的更改来提供有关您想要完成的更多信息?
有点...我在使用 Windows 之间的消息传递之前已经完成了这项工作,并使用了一个线程来监听它们。请记住,您不想从任何线程修改 UI,然后是创建它的线程...
这是父窗口的一些示例代码,它会通过其子窗口之一获得更改通知。在做你所说的事情时,同样的原则也适用。当孩子打开时,父窗口并没有真正发送消息,(它是,但我忘记了当时在想什么)......自从我不得不做这样的事情已经有 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;
}
然后,在子窗口中,当需要更新时,我会向父窗口发送一条消息。我通过创建一个简单地发送消息的线程来做到这一点,以便对话框的其余部分继续运行......(或者在你的情况下,你可以直接向子 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);
好吧,希望这会对你有所帮助,或者给你一些想法......