Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > Позиция диалогового окна


Автор: navodri 9.7.2010, 13:57
Хочу поместить диалоговое окно в нижнем правом углу, над трейем, как это делает QIP (всплывающие сообщения). Но мое окно перекрывает трей. Прошу помощи.

Код

var
 trayHandle: HWND;
 trayRect, dlgRect: TRect;
 x, y: integer;

...

  WM_INITDIALOG:
    begin
     trayHandle := FindWindow('Shell_TrayWnd', nil);
     if trayHandle <> 0 then GetWindowRect(trayHandle, trayRect);

     y:= GetSystemMetrics(SM_CYSCREEN);
     x := GetSystemMetrics(SM_CXSCREEN);
     GetWindowRect(Hwin, dlgRect);
     dec(y, dlgRect.Bottom - dlgRect.TopLeft.y); //Вот здесь у меня что-то неправильно?..

     SetWindowPos(Hwin, HWND_TOPMOST,
      x - (dlgRect.Right - dlgRect.left),
      y,
      dlgRect.Right - dlgRect.Left,
      dlgRect.Bottom - dlgRect.Top,
      SWP_SHOWWINDOW or SWP_NOACTIVATE or SWP_NOSIZE);
    end;



Автор: Maks1509 9.7.2010, 14:21
Код

  trayHandle := FindWindow('Shell_TrayWnd', nil);
  if (trayHandle <> 0) then
  begin

    GetWindowRect(trayHandle, trayRect);

    y := GetSystemMetrics(SM_CYSCREEN);
    x := GetSystemMetrics(SM_CXSCREEN);

    GetWindowRect(hWnd, dlgRect);
    SetWindowPos(
      hWnd,
      HWND_TOPMOST,
      x - (dlgRect.Right - dlgRect.Left),
      trayRect.Top - (dlgRect.Bottom - dlgRect.Top)
      {y - (trayRect.Bottom - trayRect.Top) - (dlgRect.Bottom - dlgRect.Top)},
      0,
      0,
      SWP_NOACTIVATE or SWP_NOSIZE
    );

  end;


?

Автор: navodri 9.7.2010, 15:33
Спасибо! А как раположить второе окно, выше предыдущего?

Автор: Maks1509 9.7.2010, 17:18
Зависит от твоего способа реализации. Как вариант, завести массив дескрипторов всплывающих окон. Если надо отобразить окно, проходимся по всему массиву, считываем координаты каждого окна оттуда и к примеру увеличиваем нашу переменную с высотой всех наших всплывающих окон. Не знаю, можно посмотреть исходные коды ICQ мессенджеров как там реализовано все это. Сложно сказать на этот счет.

Автор: navodri 9.7.2010, 20:03
Я понял, хорошо. С этим буду думать. 
По ходу вопрос: а как сделать "всплывающее" с низу окно? Понимаю, что в таймере придется реализовывать SetWindowPos. Есть у кого-то пример?

Автор: Maks1509 9.7.2010, 23:17
Высоту всплывающего окна и системой панели вычисляешь, получится какое-то значение. Ну в цикле можно через while какую-нибудь переменную уменьшать на 1, которая первоначально была равна высоте экрана, до значения = высота экрана - высота всплывающего окна - высота системной панели. По этому результирующему значению выводишь свое всплывающее окно. 
smile 

Автор: Keeper89 9.7.2010, 23:51
Ребяты, запоминать координаты левого верхнего угла нового окошка не проще?

А анимацию можно сделать с помощью AnimateWindow (http://msdn.microsoft.com/en-us/library/ms632669%28VS.85%29.aspx, http://www.delphisources.ru/pages/faq/base/animatewindow.html).

Автор: navodri 11.7.2010, 21:12
Итак, с позицией окна разобрались. Теперь бы как-нибудь прояснить ситуацию в таймере с функцией SetWindowPos. Вообще не понимаю, как это сделать?

Код

const
 ID_TIMER_POPUPWINDOW = 300;

function DlgProc(hWin: HWND; uMsg: UINT; wp: WPARAM; lp: LPARAM): bool; stdcall;
var
 trayHandle: HWND;
 trayRect, dlgRect: TRect;
 x, y: integer;
 leaveTop: Integer;
begin
 Result := False;
  case uMsg of
   WM_INITDIALOG:
    begin

     trayHandle := FindWindow('Shell_TrayWnd', nil);
      if (trayHandle <> 0) then begin
       GetWindowRect(trayHandle, trayRect);
       y := GetSystemMetrics(SM_CYSCREEN);
       x := GetSystemMetrics(SM_CXSCREEN);
       GetWindowRect(hWin, dlgRect);
       SetWindowPos(hWin, HWND_TOPMOST, x - (dlgRect.Right - dlgRect.Left),
        trayRect.Top - (dlgRect.Bottom - dlgRect.Top), 0, 0, SWP_NOACTIVATE or SWP_NOSIZE);
      end;
     SetTimer(hWin, ID_TIMER_POPUPWINDOW, 1, nil);
    end;

   WM_TIMER: //Таймер
    case LOWORD(wp) of
     ID_TIMER_POPUPWINDOW:
      begin
      //Выезжаем вверх
      leaveTop := trayRect.Top - 200;
       while dlgRect.Top > leaveTop do begin
        dlgRect.Top := dlgRect.Top-2;

        SetWindowPos(); //Вот здесь помогите!

       end;
        KillTimer(hWin, ID_TIMER_POPUPWINDOW);
      end;
    end;

   WM_DESTROY, WM_CLOSE:
    begin
     PostQuitMessage(0);
    end;
 end;
end;


Автор: Snowy 12.7.2010, 12:05
Цитата(navodri @  9.7.2010,  13:57 Найти цитируемый пост)
Хочу поместить диалоговое окно в нижнем правом углу, над трейем
Как человек, у которого трей уже лет 10 находится в левом нижнем углу, могу сказать "ну-ну..."
Также не учтён вариант с несколькими мониторами, когда имеет место быть точка отсчёта <> 0. В данном случае ширина или высота экрана не есть координата края.
Также не учитывается автохайд. Если панель спряталась, то какой смысл вычитать её высоту?
Нужно не экран мерять, а десктоп. Координаты правого нижнего угла которого найти несложно:
Код
  x := GetSystemMetrics(SM_CXVIRTUALSCREEN) - GetSystemMetrics(SM_XVIRTUALSCREEN);
  y := GetSystemMetrics(SM_CYVIRTUALSCREEN) - GetSystemMetrics(SM_YVIRTUALSCREEN);

Автор: navodri 12.7.2010, 12:45
2Snowy: Спасибо. Об этом и не подумал. Учту.

Ребята, пожалуйста, помогите решить тему с выезжанием окна вверх. Сам не справлюсь:

Код

 WM_TIMER:
    case LOWORD(wp) of
     ID_TIMER_POPUPWINDOW:
      begin
      //Выезжаем вверх
      leaveTop := trayRect.Top - dlgRect.Top;
       while dlgRect.Top > leaveTop do begin
        dlgRect.Top := dlgRect.Top-2;

        SetWindowPos();

       end;
        KillTimer(hWin, ID_TIMER_POPUPWINDOW);
      end;
    end;

Автор: Snowy 12.7.2010, 14:46
А в чём проблема-то?
Навскидку вижу, что окно у тебя не выезжает потому, что нет вызова цикла обработки сообщений.
Но проще воспользоваться AnimateWindow, чем городить велосипед.
А, учитывая, что таких окошек у тебя может быть несколько, то выезжать вручную будет к тому же и нелепо.
Юзай AnimateWindow. Так и проще и корректней.

Автор: navodri 12.7.2010, 15:36
Вроде, всё сделал правильно, но не работает. Помогите!

Код

const
 ID_TIMER_POPUPWINDOW = 300;

function DlgProc(hWin: HWND; uMsg: UINT; wp: WPARAM; lp: LPARAM): bool; stdcall;
var
 trayHandle: HWND;
 trayRect, dlgRect: TRect;
 x, y: integer;
 leaveTop: Integer;
begin
 Result := False;
  case uMsg of

   WM_INITDIALOG:
    begin
     trayHandle := FindWindow('Shell_TrayWnd', nil);
      if (trayHandle <> 0) then begin
       GetWindowRect(trayHandle, trayRect);
       x := GetSystemMetrics(SM_CXVIRTUALSCREEN) - GetSystemMetrics(SM_XVIRTUALSCREEN);
       y := GetSystemMetrics(SM_CYVIRTUALSCREEN) - GetSystemMetrics(SM_YVIRTUALSCREEN);
       GetWindowRect(hWin, dlgRect);
      end;
     SetTimer(hWin, ID_TIMER_POPUPWINDOW, 1, nil);
    end;

   WM_TIMER:
    case LOWORD(wp) of
     ID_TIMER_POPUPWINDOW:
      begin
       leaveTop := trayRect.Top - (dlgRect.Bottom - dlgRect.Top);
        while dlgRect.Top > leaveTop do begin
         dlgRect.Top := dlgRect.Top-2;
         SetWindowPos(hWin, HWND_TOPMOST, x - (dlgRect.Right - dlgRect.Left), dlgRect.Top, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE);
       end;
        KillTimer(hWin, ID_TIMER_POPUPWINDOW);
      end;
    end;

   WM_DESTROY, WM_CLOSE:
    begin
     PostQuitMessage(0);
    end;
 end;
end;

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)