2010-10-04 3 views
4

В-приложение Win32 есть сообщение для Windows или некоторые другие уведомления, которые будут передаваться в окно ребенка, когда он помещается в другой родительКак окно ребенок реагирует на изменение своего родителя

+0

Чтобы уточнить, вы спрашиваете, '' SetParent (hwndChild, hwndNewParent) 'отправляет нет tification to hwndChild? –

+1

Да, или есть ли другой способ для ребенка определить, что было перенесено на другого родителя? – solsberg

ответ

2

Это легко протестировать в приложении Windows Forms. Это то, что я видел:

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.

+0

Я бы начал с проверки 'WM_WINDOWPOSCHANGED'. –

0

Для этого не существует единого уведомления. Однако некоторые фреймворки, такие как VCL Borland, обертывают окна в классах и, таким образом, выдает свои собственные уведомления, когда объекты класса перемещаются из одного родителя в другой (например, VCL имеет CM_CONTROLLISTCHANGING, CM_CONTROLLISTCHANGE и CM_CONTROLCHANGE уведомлений).

Можете ли вы предоставить более подробную информацию о том, что именно вы хотите добиться, обнаружив изменение родительского окна?

+0

Мое окно находится внутри плагина, который динамически вставлен в иерархию окна главной программы, и мне нужно определить, когда он перемещается между разными местами в этой иерархии хоста. – solsberg

+0

Затем я предлагаю вам регистрировать сообщения, которые действительно получает ваше плагин, а затем выбрать наиболее подходящий для ваших нужд. –

+0

Да, это то, что я делаю сейчас, вызывая GetParent(), когда я получаю сообщение WM_WINDOWPOSCHANGED и сравниваю его с предыдущим родительским дескриптором. – solsberg

0

Сортировка ... Я сделал это, прежде чем использовать обмен сообщениями между Windows и поток для прослушивания на них. Помните, что вы НЕ хотите изменять пользовательский интерфейс из любого потока, а затем тот, который СОЗДАЛ его ...

Вот пример кода родительского окна, которое получает уведомление об изменении одним из его дочерних окон Windows. Тот же принцип применяется, когда вы делаете то, о чем говорите. Родительская Windows на самом деле не накачивает сообщения, пока ребенок открыт, (он есть, но я забываю, что происходит в это время) ... Прошло уже 10 лет с тех пор, как я должен был сделать что-то подобное ... Но приведенный ниже код предназначен для родительского окна с сеткой и дочернего окна «Добавить/редактировать», которое открывается, а когда вы добавляете или редактируете элемент, он обновляет родительский GRID за окном Modal Edit. Это было разработано в 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; 

}

Затем в детском окне, я бы отправить сообщение обратно к родителю, когда пришло время Обновить. Я сделал это, создав поток, который просто отправил сообщение, чтобы остальная часть диалога продолжала функционировать ... (Или в вашем случае вы можете отправить сообщение непосредственно в HWND для дочерних Windows, чтобы обновить его. .)

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

Затем все это в движение, когда пользователь выбрал «СЛЕДУЮЩИЙ» в диалоговом окне, вместо OK или CANCEL ...

_beginthread(GridUpdateThread, NULL, this); 

Ну, надеюсь, это поможет вы некоторые, или дать вам некоторые идеи ...

+0

Полезная информация, но я думаю, что вы отвечаете на другой вопрос. –

+0

В моем точном примере да. Но то, что я делал, было способом, которым он мог бы использовать для наблюдения за вещами, возможно, используя переопределение для SetParent() или что-то в этом роде. Примером этого примера было показать, как разговаривать между двумя окнами с помощью потоков и настраиваемых сообщений. Я думаю, он мог бы сделать то, что хотел, использовать метод, как я упоминаю ... В нем нет ничего, что сделало бы для него ... – LarryF