uses
Windows, Messages;
var
WC: TWndClass;
H1, H2: hWND;
Message: TMsg;
function WP(Handle: HWND; Message: UINT; WP: WParam; LP: LParam): longint; stdcall;
begin
case Message of
wm_Destroy: if Handle = H1 then begin
PostQuitMessage(0);
Result := 0;
Exit;
end;
end;
Result := DefWindowProc(Handle, Message, WP, LP);
end;
begin
with WC do begin
Style := cs_HRedraw or cs_VRedraw or cs_OwnDC;
lpfnWndProc := @WP;
cbClsExtra := 0;
cbWndExtra := 0;
hInstance := MainInstance;
hIcon := 0;
hCursor := LoadCursor(0, idc_Arrow);
hbrBackground := Color_BtnFace + 1;
lpszMenuName := nil;
lpszClassName := 'Test';
end;
RegisterClass(WC);
H1 := CreateWindow('Test', 'Test1', ws_OverlappedWindow,
100, 100, 320, 200,
0, 0, MainInstance, nil);
H2 := CreateWindow('Test', 'Test2', ws_OverlappedWindow,
110, 110, 320, 200,
H1, 0, MainInstance, nil);
ShowWindow(H1, cmdShow);
UpdateWindow(H1);
ShowWindow(H2, sw_ShowNormal);
while GetMessage(Message, 0, 0, 0) do begin
TranslateMessage(Message);
DispatchMessage(Message);
end;
end.
Абсолютно правильное поведение:
http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#owned_windows
А мне что делать, чтобы сверху было активное окно? Первое окно наверх даже BringWindowToTop не вытаскивает, кстати.
> Какая между ними связь?
Да никакой, на самом деле. Они равноправны, разница лишь в том, что когда закрывается H1, должно завершаться приложение, ну так это и так в оконной функции указано.
Короче, надо выкручиваться.
Я поступил по-VCLовски: в качестве главного создал видимое окно нулевого размера, а у тех двух указал родителем его.
А, вот оно как.
Тогда сделаю во-твоему.
Вот они, преимущества безVCLного кода... Захотел - юникодом все компоненты задал, захотел - окна как надо сделал.
Ещё оффтоп, но тоже об окнах - у меня в одной программе главное окно без рамки (ws_Popup), она страшно глючит при запуске под линуксом через WINE, это известный глюк WINE или в программе что-то не так?
Теперь у меня новая проблема.
Если переключиться на другое приложение, закрывающее окно2, а потом снова на это, то окно2 пропадает.
Надо ловить wm_Activate и руками что-то писать?
И ещё, надо, чтобы при соваривании окна1 сворачивалось и окно2 (да, я забыл это сказать, думал, что такой эффект сам собой получится).
uses
Windows, Messages;
var
WC: TWndClass;
H1, BK, H2: hWND;
Message: TMsg;
function WP(Handle: HWND; Message: UINT; WP: WParam; LP: LParam): longint; stdcall;
begin
case Message of
wm_Activate: if (Handle = H1) and (LoWord(WP) <> wa_Inactive) then begin
// ???
end;
wm_Destroy: if Handle = H1 then begin
PostQuitMessage(0);
Result := 0;
Exit;
end;
end;
Result := DefWindowProc(Handle, Message, WP, LP);
end;
begin
with WC do begin
Style := cs_HRedraw or cs_VRedraw or cs_OwnDC;
lpfnWndProc := @WP;
cbClsExtra := 0;
cbWndExtra := 0;
hInstance := MainInstance;
hIcon := 0;
hCursor := LoadCursor(0, idc_Arrow);
hbrBackground := Color_BtnFace + 1;
lpszMenuName := nil;
lpszClassName := 'Test';
end;
RegisterClass(WC);
H1 := CreateWindow('Test', 'Test1', ws_OverlappedWindow,
100, 100, 320, 200,
0, 0, MainInstance, nil);
BK := CreateWindow('Test', 'Test1', 0,
100, 100, 320, 200,
0, 0, MainInstance, nil);
H2 := CreateWindow('Test', 'Test2', ws_OverlappedWindow,
110, 110, 320, 200,
BK, 0, MainInstance, nil);
ShowWindow(H1, cmdShow);
UpdateWindow(H1);
ShowWindow(H2, sw_ShowNormal);
while GetMessage(Message, 0, 0, 0) do begin
TranslateMessage(Message);
DispatchMessage(Message);
end;
end.
> это уже случай WA_ACTIVE, если не произошло WA_CLICKACTIVE перед этим
Не, так не прокатило - при старте как раз происходит wa_Active без wa_ClickActive и если в обработчике "wa_Active, перед которым не было wa_ClickActive" написать подъём окон, то при старте они дёргаются.
> Ну, как тебе безVCL-ный код?
Документацию рыть много надо, а так разницы мало - у меня всё равно болшая часть кода не относится к интерфейсу.
Добавлено через 1 мин.
Или я не так понял? Оконна функция:
function WP(Handle: HWND; Message: UINT; WP: WParam; LP: LParam): longint; stdcall;
const
WasCA: byte = 0;
begin
if WasCA > 0 then Dec(WasCA);
case Message of
wm_SysCommand: if Handle = H1 then begin
if WP = sc_Minimize then ShowWindow(H2, sw_Hide)
else if WP = sc_Restore then ShowWindow(H2, sw_Show);
end;
wm_Activate: if LoWord(WP) = wa_ClickActive then begin
if Handle = H1 then begin
BringWindowToTop(H2);
BringWindowToTop(H1);
end else begin
BringWindowToTop(H1);
BringWindowToTop(H2);
end;
WasCA := 2;
end else if (Handle = H1) and (LoWord(WP) = wa_Active) and (WasCA = 0) then begin
BringWindowToTop(H2);
BringWindowToTop(H1);
end;
wm_Destroy: if Handle = H1 then begin
PostQuitMessage(0);
Result := 0;
Exit;
end;
end;
Result := DefWindowProc(Handle, Message, WP, LP);
end;
Это я что-то ступил... Есть же еще WM_ACTIVATEAPP. Вот его и надо ловить, когда переключаемся с другого приложения.
varКак-то так.
WasCA: byte = 0; // Перенес сюда, лень лезть в настройки компилятора
function WP(Handle: HWND; Message: UINT; WP: WParam; LP: LParam): longint; stdcall;
begin
if WasCA > 0 then Dec(WasCA);
case Message of
wm_SysCommand:
if Handle = H1 then begin
if WP = sc_Minimize then ShowWindow(H2, sw_Hide)
else if WP = sc_Restore then ShowWindow(H2, sw_Show);
end;
wm_Activate:
if LoWord(WP) = wa_ClickActive then begin
if Handle = H1 then begin
BringWindowToTop(H2);
BringWindowToTop(H1);
end else begin
BringWindowToTop(H1);
BringWindowToTop(H2);
end;
WasCA := 2;
end
// Внимательнее. Здесь обработка должна быть только когда WasCA > 0, а не = ...
else if (Handle = H1) and (LoWord(WP) = wa_Active) and (WasCA > 0) then begin
BringWindowToTop(H2);
BringWindowToTop(H1);
end;
// Собственно, переключение с другого приложения
WM_ACTIVATEAPP:
if WP <> 0 then // Активируется? Да, при деактивации WP = 0
begin
BringWindowToTop(H2);
BringWindowToTop(H1);
end;
wm_Destroy: if Handle = H1 then begin
PostQuitMessage(0);
Result := 0;
Exit;
end;
end;
Result := DefWindowProc(Handle, Message, WP, LP);
end;
Обнаружил, что если WM_ACTIVATEAPP написать наоборот, то есть
WM_ACTIVATEAPP:
if WP <> 0 then // Активируется? Да, при деактивации WP = 0
begin
BringWindowToTop(H1);
BringWindowToTop(H2); // сверху ставим второе окно!
end;
Так. Ну, допустим, в WM_ACTIVATEAPP проверять, если это не самая первая активация (то есть, не та, которая при создании приложения, а та, которая уже при клике на таскбаре, там разрулишь флагами) - то просто посылать
PostMessage(H1, WM_ACTIVATE, WA_CLICKACTIVE, H1); // если надо активным сделать окно №1
// или
PostMessage(H2, WM_ACTIVATE, WA_CLICKACTIVE, H2); // если надо сделать активным второе окно
Заработал такой вариант оконной функции:
function WP(Handle: HWND; Message: UINT; WP: WParam; LP: LParam): longint; stdcall;
const
WasH1: boolean = false;
begin
Result := 0;
case Message of
wm_SysCommand: if Handle = H1 then begin
if WP = sc_Minimize then ShowWindow(H2, sw_Hide)
else if WP = sc_Restore then ShowWindow(H2, sw_Show);
end;
wm_Activate: if LoWord(WP) = wa_ClickActive then WasH1 := Handle = H1;
wm_ActivateApp: if WP <> 0 then begin
if WasH1 then begin
BringWindowToTop(H2); // тут небольшая проблема
BringWindowToTop(H1);
end else PostMessage(H2, wm_Activate, wa_ClickActive, H2);
end;
wm_Destroy: if Handle = H1 then begin
PostQuitMessage(0);
Exit;
end;
end;
Result := DefWindowProc(Handle, Message, WP, LP);
end;
Вот этого никогда не делал, хотя теоретически знаю, что в этом может помочь функция http://msdn.microsoft.com/en-us/library/ms633545%28VS.85%29.aspx (в данном конкретном случае особенно интересен второй параметр hWndInsertAfter, который указывает, после какого окна в Z-последовательности будет установлено hWnd).
К сожалению, я сейчас не под Windows, так что проверить возможности не имею.
BringWindowToTop(H2);
BringWindowToTop(H1);
BringWindowToTop(H1);
SetWindowPos(H2, H1, 0, 0, 0, 0, swp_NoMove or swp_NoSize);