Модераторы: Snowy, MetalFan, bems, Poseidon

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Запуздырить иконку в трей (c), Delphi XE, TTrayIcon, кривые руки 
:(
    Опции темы
MetalFan
Дата 1.5.2011, 17:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Простите за заголовок темы, вроде как все должно быть просто...
Но возникла небольшая сложность, что-то не соображу, как правильно победить.
Цель: Сворачивать приложение в трей (+убирать из панели задач) , по щелчку по иконке - разворачивать (возвращать в панель задач)
Компоненты (Delphi XE): TTrayIcon, TApplicationEvents. Первому назначен OnClick, второму OnMinimize/OnRestore
Код :
Код

procedure TForm1.appevtMinimize(Sender: TObject);
begin
  tricon.Visible := True;
  Hide;
end;

procedure TForm1.appevtRestore(Sender: TObject);
begin
  tricon.Visible := False;
  Show;
  SetForegroundWindow(Handle);
end;

procedure TForm1.triconClick(Sender: TObject);
begin
  if WindowState = wsMinimized then
    Application.Restore
  else
    Application.Minimize;
end;

в аттаче тестовое приложение с указанным кодом.
Проблема: на первый взгляд все хорошо: сворачиваем - получаем иконку в трее, разворачиваем - получаем приложение в панели задач...
Но! При сворачивании по клику по кнопке в панели задач приложение обратно из трея не разворачивается(
Городил собственную обработку сворачивания/разворачивания (вместо Application.Minimize/Restore), но там другие косяки повылазили...
Может кто сталкивался и знает изящное решение?
Всем спасибо за внимание,
wbw, MetalFan.


Это сообщение отредактировал(а) MetalFan - 1.5.2011, 17:59

Присоединённый файл ( Кол-во скачиваний: 23 )
Присоединённый файл  TrayIcon.zip 1,14 Kb


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Rrader
  Дата 1.5.2011, 18:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Inspired =)
***


Профиль
Группа: Экс. модератор
Сообщений: 1535
Регистрация: 7.5.2005

Репутация: 18
Всего: 191



Как увиделось, проблема в том, что IsIconic работает по-разному в разных случаях сворачивания. А что, если зафорсить единое поведение?
Код

procedure TForm1.appevtMinimize(Sender: TObject);
begin
  tricon.Visible := True;
  SendMessage(Application.Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
  Hide;
end;



--------------------
Let's do this quickly!
Rest in peace, Vit!
PM MAIL Skype   Вверх
MetalFan
Дата 1.5.2011, 18:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Rrader, Да, на IsIconic тоже обратил внимание... почему-то IsIconic "слетает" после того, как Hide  форме делается...
А SC_MINIMIZE приходит до вызова Application.OnMinimize (точнее как раз OnMinimize вызывается вследствие прихода SC_MINIMIZE) судя по коду 
TApplication.WndProc...
Но твой вариант работает верно... спасибо за идею)
Может вообще есть более корректный подход, чем который я изначально привел?
кстати, IsIconic возвращает неверно выставленный внутренний флаг TApplication.FAppIsIconic в моем случае... который выставляется по приходу WM_ACTIVATEAPP, после того, как приложение свернуто... хм. косяк что-ли где-то в VCL.

Это сообщение отредактировал(а) MetalFan - 1.5.2011, 18:52


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
MetalFan
Дата 11.1.2012, 21:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Подниму сию тему...
В общем решил исходную задачу следующим рабочим кодом, который прекрасно отрабатывает по клику на иконку в трее (используется стандартный компонент - TTrayIcon):
Код

procedure TForm1.DoRestoreOrMinimize;
begin
  if WindowState = wsMinimized then
  begin
    WindowState := wsNormal;
    Application.Restore;
    Show;
    SetForegroundWindow(Handle);
  end
  else
  begin
    Application.Minimize;
    Hide;
  end;
end;

Данный код сворачивает приложение "в трей", если оно "развернуто", либо разворачивает его из оного, если оно было свернуто.
Иконка в трее теперь видна всегда.

Задача: модифицировать код так, чтобы при вызове этого кода в момент клика мышью на иконке в трее добавился третий вариант реакции - если приложение развернуто, но не на переднем плане, перенести его на передний план...
Казалось бы, что сложного, во вторую ветку добавить проверку вида 
Код

if GetForegroundWindow <> Handle then 
  SetForegroundWindow(Handle)
else
...старый код

Но в момент клика на иконку в трее, при вызове данного кода, GetForegroundWindow всегда <> Self.Handle
Другие, пришедшие в голову проверки (GetTopWindow, Application.Active, Applicaiton.MainForm.Active, etc...) так же не срабатывают, т.к. в момент клика активным окном на переднем плане становится окно тулбара винды...

Собственно уважаемые коллеги, какие будут соображения на эту тему?

p.s.По скольку вопрос напрямую связан с сабжевым вопросом, то создавать новую тему не вижу смысла

Это сообщение отредактировал(а) MetalFan - 12.1.2012, 08:07


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 11.1.2012, 23:35 (ссылка)    | (голосов:3) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Цитата(MetalFan @  1.5.2011,  17:36 Найти цитируемый пост)
TTrayIcon

А Shell_NotifyIcon недостаточно?




--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
CodeMonkey
Дата 12.1.2012, 07:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Это баг в Delphi.

Application.Restore первым делом проверяет "свёрнутость" окна. Проблема в том, что делает она это на Handle себя, а не формы (это при MainFormOnTaskbar = True). Application.Handle и Application.MainForm.Handle - это два разных окна и их состояния могут быть несогласованными, что мы и получаем в этом примере.

Решение: сворачивать Application.

Код
procedure TForm1.appevtMinimize(Sender: TObject);
begin
  tricon.Visible := True;
  // Application:
  if (Application.Handle <> 0) and (Application.Handle <> Application.MainFormHandle) then
    ShowWindow(Application.Handle, SW_MINIMIZE);
  // Form:
  Application.MainForm.Hide;
end;

procedure TForm1.appevtRestore(Sender: TObject);
begin
  tricon.Visible := False;
  // Application:
  if (Application.Handle <> 0) and (Application.Handle <> Application.MainFormHandle) then
    ShowWindow(Application.Handle, SW_NORMAL);
  // Form:
  Application.MainForm.Show;
  if Application.MainForm.WindowState = wsMinimized then
    Application.MainForm.WindowState := wsNormal;
  // Activation:
  SetForegroundWindow(Application.MainFormHandle);
end;

procedure TForm1.triconClick(Sender: TObject);
begin
  if Application.MainForm.Visible then
    Application.Minimize
  else
    Application.Restore;
end;


Добавлено через 2 минуты и 34 секунды
P.S. Эх, проморгал исходную тему, а то сохранил бы тебе полгода мучений smile


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
CodeMonkey
Дата 12.1.2012, 07:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата
Задача: модифицировать


Чего-то слона-то я и не заметил...

Не очень понял как может быть "если приложение развернуто, но не на переднем плане" одновременно с "при клике мышью на иконке в трее". Ты же скрываешь икноку при показе окна.

В любом случае проверка должна опираться на видимость окна. Видимо окно - на первый план его, нет - восстановить. 


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 12.1.2012, 07:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(Чучмек @  11.1.2012,  23:35 Найти цитируемый пост)
А Shell_NotifyIcon недостаточно?

по делу есть что сказать?


Цитата(CodeMonkey @  12.1.2012,  07:28 Найти цитируемый пост)
Не очень понял как может быть "если приложение развернуто, но не на переднем плане" одновременно с "при клике мышью на иконке в трее". Ты же скрываешь икноку при показе окна.

В том то и дело, что рассматриваем вариант, когда иконка в трее видна всегда.
Предложенный второй отрезок кода при его вызове работает так: Если приложение свернуто - разворачивает, если развернуто, то сворачивает... 
Необходимо модифицировать: Если приложение НЕ свернуто в трей, но, к примеру, сейчас активно окно другого приложения, то в этом случае наше приложение должно "переехать" на передний план, а не свернуться в трей, при клике по его иконке в этом трее.
Такое поведение наблюдается, к примеру, у The Ваt при соответствующих настройках.
Исходный же алгоритм ВСЕГДА сворачивает приложение, если оно не свернуто.

В итоге задача сводится к тому, что как в момент клика на иконке в трее определить, что ДО клика было активно окно нашего приложения.

Это сообщение отредактировал(а) MetalFan - 12.1.2012, 08:04


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 12.1.2012, 11:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



А, всё, понял.

Это просто: возьми Foreground или Active окно (надо проверить, как там с SOT-окнами), найди следующее по Z-порядку (GetNextWindow). Если твоё - то ты сверху, минимизируй. Если не твоё, то ты перекрыт - сворачивайся.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 12.1.2012, 11:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



CodeMonkey, не сработало) пробовал так уже. В момент клика, даже если перед этим было активно наше окно, то GetNextWindow от GetForegroundWindow возвращает вообще другое окно, никак не относящееся к нашему приложению.
з.ы. а что такое SOT-окна?

Это сообщение отредактировал(а) MetalFan - 12.1.2012, 11:20


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 12.1.2012, 11:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



SOT = Stay On Top

Через Spy++ проверь, что там GetNextWindow возвращает. По нему же можно цепочку Z order проверить (вроде).


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 12.1.2012, 11:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



CodeMonkey, вот моя пока нерабочая модификация кода:
Код

  if WindowState = wsMinimized then
  begin
    WindowState := wsNormal;
    Application.Restore;
    Show;
    SetForegroundWindow(Handle);
  end
  else
  begin
    if (GetForegroundWindow = Handle) or (GetNextWindow(GetForegroundWindow, GW_HWNDNEXT) = Handle) then
    begin
      Application.Minimize;
      Hide;
    end
    else
      SetForegroundWindow(Handle);
  end;

Смотрел в S++, в момент нажатия по трею GetNextWindow(GetForegroundWindow, GW_HWNDNEXT) и GetNextWindow(GetForegroundWindow, GW_HWNDPREV) возвращает вообще левые окна... что и видно в S++.

тестовое приложение в аттаче.

Это сообщение отредактировал(а) MetalFan - 12.1.2012, 12:18

Присоединённый файл ( Кол-во скачиваний: 8 )
Присоединённый файл  TrayTest.zip 1,19 Kb


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 12.1.2012, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата
вообще левые окна...


А что это за окна? Чьи они? И какие у них атрибуты?

Добавлено через 1 минуту и 2 секунды
Кстати, а ты пробовал GetLastActivePopup?


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 12.1.2012, 13:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(CodeMonkey @  12.1.2012,  12:30 Найти цитируемый пост)
А что это за окна? Чьи они? И какие у них атрибуты?

просто окна других приложений. среди них нет моего.

Цитата(CodeMonkey @  12.1.2012,  12:30 Найти цитируемый пост)
Кстати, а ты пробовал GetLastActivePopup? 

пробовал. Если в него отдаешь 0, то возвращается 0, если отдаешь хэндл формы, то получаешь тот же хэндл формы.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 12.1.2012, 21:23 (ссылка)    | (голосов:5) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



OnPaint


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 12.1.2012, 21:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, выскажись по-подробнее....

Это сообщение отредактировал(а) MetalFan - 12.1.2012, 22:58


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 12.1.2012, 21:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Если окно приложения перекрыто другими окнами и становится активным, то для окна вызывается OnPaint
А если окно не перекрыто - то  OnPaint не вызывается.
Отсюда решение: По клику на иконку в трее сделать окно активным и запустить ожидание события  OnPaint (0,5 сек)
Если событие не произошло - скрыть окно.

Это сообщение отредактировал(а) Чучмек - 12.1.2012, 21:55


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 12.1.2012, 22:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, хм, как самый крайний вариант может и сойдет, но, имхо, не очень красивое решение...


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 13.1.2012, 01:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Выяснил, что все функции работают только в контексте цепочки окна. Я не нашёл ни одной функции, которая давала бы доступ к глобальному Z-порядку.

Для теста использовал такой код:
Код
procedure TForm1.appevtMinimize(Sender: TObject);
begin
//  tricon.Visible := True;
  // Application:
  if (Application.Handle <> 0) and (Application.Handle <> Application.MainFormHandle) then
    ShowWindow(Application.Handle, SW_MINIMIZE);
  // Form:
  Application.MainForm.Hide;
end;

procedure TForm1.appevtRestore(Sender: TObject);
begin
//  tricon.Visible := False;
  // Application:
  if (Application.Handle <> 0) and (Application.Handle <> Application.MainFormHandle) then
    ShowWindow(Application.Handle, SW_NORMAL);
  // Form:
  Application.MainForm.Show;
  if Application.MainForm.WindowState = wsMinimized then
    Application.MainForm.WindowState := wsNormal;
  // Activation:
  SetForegroundWindow(Application.MainFormHandle);
end;

function GetProcessImageFileName(hProcess: THandle; lpImageFileName: PWideChar; nSize: DWORD): DWORD; stdcall; external 'PsAPI.dll' name 'GetProcessImageFileNameW';

procedure TForm1.triconClick(Sender: TObject);

  function GetPrevWnd(const AWnd: HWND): HWND;
  // тут - всякий бред, я экспериментировал
  type
    TParams = record
      PID: DWord;
      Src: HWND;
      Dst: HWND;
    end;
    PParams = ^TParams;

    function Enumer(AWnd: HWND; Params: PParams): BOOL; stdcall;
    var
      PID: DWORD;
    begin
      Result := True;
      if GetWindowThreadProcessId(AWnd, PID) <> 0 then
      begin
        if PID <> Params.PID then
        begin
          Params.Dst := AWnd;
          Result := False;
        end;
      end;
    end;

  var
    PID: DWORD;
    Params: TParams;
  begin
    if GetWindowThreadProcessId(AWnd, PID) = 0 then
    begin
      Result := 0;
      Exit;
    end;

    Params.PID := PID;
    Params.Src := AWnd;
    Params.Dst := 0;
    EnumWindows(@Enumer, Integer(@Params));
    Result := Params.Dst;
  end;

  function GetWindowText(const AWnd: HWND): String;
  var
    Buf1, Buf2: String;
    PID: DWORD;
    Handle: THandle;
  begin
    SetLength(Buf1, 10240);
    SetLength(Buf1, GetClassName(AWnd, PChar(Buf1), Length(Buf1)));

    SetLength(Buf2, 10240);
    SetLength(Buf2, Windows.GetWindowText(AWnd, PChar(Buf2), Length(Buf2)));

    if GetWindowThreadProcessId(AWnd, PID) <> 0 then
    begin
      Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
      try
        SetLength(Result, 10240);
        SetLength(Result, GetProcessImageFileName(Handle, PChar(Result), Length(Result)));
        if Result = '' then
          Result := SysErrorMessage(GetLastError);
      finally
        CloseHandle(Handle);
      end;
      Result := ExtractFileName(Result);
    end
    else
      Result := '?';

    Result := Format('[%s] "%s" (%s)', [Buf1, Buf2, Result]);
  end;

begin
  Label1.Caption := 'Application.Handle: ' + IntToHex(Application.Handle, 8);
  Label2.Caption := 'Application.MainForm.Handle: ' + IntToHex(Application.MainForm.Handle, 8);
  Label3.Caption := 'GetForegroundWindow: ' + IntToHex(GetForegroundWindow, 8) + ' ' + GetWindowText(GetForegroundWindow);
  Label4.Caption := 'GetActiveWindow: ' + IntToHex(GetActiveWindow, 8) + ' ' + GetWindowText(GetActiveWindow);
  Label5.Caption := 'Next(GetForegroundWindow): ' + IntToHex(GetNextWindow(GetForegroundWindow, GW_HWNDNEXT), 8) + ' ' + GetWindowText(GetNextWindow(GetForegroundWindow, GW_HWNDNEXT));
  Label6.Caption := 'Next(GetActiveWindow): ' + IntToHex(GetNextWindow(GetActiveWindow, GW_HWNDNEXT), 8) + ' ' + GetWindowText(GetNextWindow(GetActiveWindow, GW_HWNDNEXT));
  Label7.Caption := 'Prev(GetForegroundWindow): ' + IntToHex(GetNextWindow(GetForegroundWindow, GW_HWNDPREV), 8) + ' ' + GetWindowText(GetNextWindow(GetForegroundWindow, GW_HWNDPREV));
  Label8.Caption := 'Prev(GetActiveWindow): ' + IntToHex(GetNextWindow(GetActiveWindow, GW_HWNDPREV), 8) + ' ' + GetWindowText(GetNextWindow(GetActiveWindow, GW_HWNDPREV));
  Label9.Caption := 'LastActive(GetForegroundWindow): ' + IntToHex(GetLastActivePopup(GetForegroundWindow), 8) + ' ' + GetWindowText(GetLastActivePopup(GetForegroundWindow));
  Label10.Caption := 'LastActive(GetActiveWindow): ' + IntToHex(GetLastActivePopup(GetActiveWindow), 8) + ' ' + GetWindowText(GetLastActivePopup(GetActiveWindow));
  Label11.Caption := 'MyPrev(GetForegroundWindow): ' + IntToHex(GetPrevWnd(GetForegroundWindow), 8) + ' ' + GetWindowText(GetPrevWnd(GetForegroundWindow));
  Label12.Caption := 'MyPrev(GetActiveWindow): ' + IntToHex(GetPrevWnd(GetActiveWindow), 8) + ' ' + GetWindowText(GetPrevWnd(GetActiveWindow));

  {
  if Application.MainForm.Visible then
    Application.Minimize
  else
    Application.Restore;
  }
end;


Предлагаю попробовать так: перечислить все окна. Отобрать из них те, которые видимые, не SOT и пересекают твой клиентский прямоугольник. Если такие есть - ты перекрыт, давай наверх. Если таких нет - ты наверху, убирайся в трей.

Добавлено через 3 минуты и 59 секунд
Возможно, вместо перечисления окон можно глянуть в сторону GetClipBox.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Чучмек
Дата 13.1.2012, 02:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



PtVisible


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
Qu1nt
Дата 13.1.2012, 03:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



http://delphimaster.net/view/2-1169797326
Или вот, что получилось у меня.
Код

function EnumProc(Handle: THandle; var Foreground: THandle): Boolean; stdcall;
var
  ClassName: array [Byte] of Char;
begin
  GetClassName(Handle, ClassName, SizeOf(ClassName));
  Foreground := Handle;
  Result := not IsWindowEnabled(Handle) or not IsWindowVisible(Handle) or
    (GetWindow(Handle, GW_OWNER) <> 0) or
    (GetWindowLongPtr(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) or
    (ClassName = 'NotifyIconOverflowWindow') or
    (ClassName = 'Shell_TrayWnd') or
    (ClassName = 'Internet Explorer_Hidden');
end;

function GetForeground: THandle;
begin
  EnumWindows(@EnumProc, NativeInt(@Result));
end;


Это сообщение отредактировал(а) Qu1nt - 13.1.2012, 17:12
PM MAIL   Вверх
MetalFan
Дата 13.1.2012, 09:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Цитата(CodeMonkey @  13.1.2012,  01:23 Найти цитируемый пост)
и пересекают твой клиентский прямоугольник.

не понял, как это определить... если просто сравнить пересечение прямоугольников окон. так если чужое окно будет под или над моим, получается, что прямоугольники пересекуться...


Цитата(CodeMonkey @  13.1.2012,  01:23 Найти цитируемый пост)
глянуть в сторону GetClipBox

а вот это посмотрим

Цитата(Чучмек @  13.1.2012,  02:53 Найти цитируемый пост)
PtVisible 

хм, и что, проверять каждый пиксель формы? ну как еще один крайний вариант - сойдет. хотя оно же не учитывает так называемые SOT окна наверняка.


Qu1nt, да, тема стара, как мир)))
предложенный код исходит из предположения, что EnumWindows перечисляет окна в порядке видимости сверху вниз? А список исключения по ClassName если вдруг поменяется? программа какая-либо сторонняя вдруг так же вылезет "наверх"... спасибо, как вариант, возможно прокатит. Но как-то на мой взгляд не надежно....

Добавлено @ 09:12
з.ы. как же ритлабовцы в своем thebat добились нужного поведения...  и uTorrent тоже как надо работает....

Это сообщение отредактировал(а) MetalFan - 13.1.2012, 09:15


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
CodeMonkey
Дата 13.1.2012, 09:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Не видел TheBat, но может они читерят smile

Например, первый клик - если окно видимо, то наверх его. Если второй клик (но не дабл-клик) происходит менее чем через 2 сек после первого - то свернуть окно, если позднее - то начать с начала.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
MetalFan
Дата 13.1.2012, 09:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



CodeMonkey, неа... даж если надо окном бата/utorrenta поместить, к примеру, калькулятор, то при клике на иконку в трее окно не свернется в трей, а "переедет" на передний план.

Сегодня попробую все предложенные варианты, отпишусь.

Добавлено через 2 минуты и 29 секунд
вот еще рещение, как раз, как ты писал с проверкой на пересечение окон, что выше по Z-порядку находятся. В общем надо пробовать.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
MetalFan
Дата 13.1.2012, 15:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Небольшой подитог: все способы, определяющие частично перекрытие окна не катят на мой взгляд. т.к. неправильно сработают в след.ситуации: наше окно открыто не на весь экран и видно полностью, рядом АКТИВНО окно другого приложения так же не на весь экран и не перекрывающее наше окно. В этом случае по логике с перекрытиями наше окно считается поверх всех, т.к. видно полностью, что на мой взгляд неправильно.

Вариант Qu1nt вроде как работает правильно, только вот не нравятся мне проверка на классы окон, ибо может появиться вдруг еще какой-нибудь класс, который сломает сию добрую логику...

и одна вот эта часть проверки, кмк, так же написана неверно (скобок не хватает):
Код

...
(GetWindowLongPtr(Handle, GWL_EXSTYLE and WS_EX_TOPMOST) <> 0) or
...

Разве должно быть не так:
Код

((GetWindowLongPtr(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST) <> 0) or




--------------------
There are always someone smarter than you...
PM MAIL   Вверх
MetalFan
Дата 13.1.2012, 17:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



В общем модифицировал функцию от Qu1nt и все заработало ПОЧТИ как надо:
Код

function EnumProc(Handle: HWND; LResult: LPARAM): Boolean; stdcall;
begin
  PInteger(LResult)^:= Handle;
  Result := not IsWindowEnabled(Handle) or
            not IsWindowVisible(Handle) or
            ( GetWindow(Handle, GW_OWNER) <> 0 ) or
            ( GetWindowLongPtr(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0 );
end;

function GetForeground: THandle;
begin
  EnumWindows(@EnumProc, NativeInt(@Result));
end;

Код

  if WindowState = wsMinimized then
  begin
    WindowState := wsNormal;
    Application.Restore;
    Show;
    SetForegroundWindow(Handle);
  end
  else
  begin
    if GetForeground = Self.Handle then
    begin
      Application.Minimize;
      Hide;
    end
    else
      SetForegroundWindow(Handle);
  end;


Это Почти заключается в небольшом отличии от поведения ранееупомянутой мыши.
Наше окно всегда считается foreground, даже если сейчас активно другое окно с ExStyle = WS_EX_TOPMOST...
С одной стороны это наверное правильно... Замена проверки ExStyle на WS_EX_TOOLWINDOW привело к тому, что если на экране есть одно SOT-окно, то наше окно вообще перестает сворачиваться (такое же поведение и у uTorrent, кстати).
Как же в бате сделали разработчики, чтобы все работало как надо красиво... загадка.



--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Qu1nt
Дата 13.1.2012, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Ой, не там скобку убрал:
Код

(GetWindowLongPtr(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0) 

Подход основывался на:
http://stackoverflow.com/questions/210504/...ke-alt-tab-does
http://code.google.com/p/k-kovalev-persona...DataProvider.cs
PM MAIL   Вверх
Qu1nt
Дата 13.1.2012, 17:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



MetalFan, уточни какого поведения ты хочешь добиться.
PM MAIL   Вверх
MetalFan
Дата 13.1.2012, 18:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Qu1nt, поведение я ж вроде описывал.
Необходимо момент нажатия на иконку в трее:
1. Если окно свернуто, то развернуть его.
2. Если окно приложения активно в данный момент, то свернуть его "в трей".
3. Если окно развернуто из трея, но не активно в данный момент, то сделать его активным.

в п.3 как раз и загвоздка. Как корректно определить, активно ли окно в момент нажатия на иконку в трее.
Самый приближенный к "правде" вариант - последний приведенный мною на основании твоего кода.



--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Qu1nt
Дата 13.1.2012, 20:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



Вот еще вариант:
Код

function EnumProc(Handle: HWND; LParam: LPARAM): BOOL; stdcall;
begin
  PHandle(LParam)^ := Handle;
  Result := (GetParent(Handle) <> 0) or
    (GetWindowLongPtr(Handle, GWL_EXSTYLE) and WS_EX_TOPMOST <> 0);
end;

function GetForeground: THandle;
begin
  EnumWindows(@EnumProc, LPARAM(@Result));
end;

Разницы между поведением этого кода и The Bat! 5 не увидел. 
PM MAIL   Вверх
CodeMonkey
Дата 14.1.2012, 05:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



В описании EnumWindows не сказано, в каком порядке она обходит окна.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
Чучмек
Дата 14.1.2012, 09:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Код

keybd_event(VK_MENU,0,0,0);
keybd_event(VK_ESCAPE,0,0,0);
keybd_event(VK_ESCAPE,0,KEYEVENTF_KEYUP,0);
keybd_event(VK_MENU,0,KEYEVENTF_KEYUP,0);
application.ProcessMessages;
if form1.Active then ...



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
b8195108
Дата 14.1.2012, 14:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 17.7.2011

Репутация: нет
Всего: 2



Код

function isWindowFullVisible(AWnd: THandle): Boolean;
var
  R1, R2, R3: TRect;
begin
  GetWindowRect(AWnd, R1);
  GetWindowRect(GetDesktopWindow, R2);
  Result :=
    (IsWindowVisible(AWnd)) and (not IsIconic(AWnd)) and
    (R1.Left >= R2.Left) and (R1.Top >= R2.Top) and
    (R1.Right <= R2.Right) and (R1.Bottom <= R2.Bottom);
  while (AWnd <> 0) and (Result) do
    begin
      AWnd := GetNextWindow(AWnd, GW_HWNDPREV);
      if (IsWindowVisible(AWnd)) and (not IsIconic(AWnd)) then
        begin
          GetWindowRect(AWnd, R2);
          if IntersectRect(R3, R2, R1) then
            Result := False;
        end;
  end;
end;

PM MAIL   Вверх
MetalFan
Дата 14.1.2012, 14:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



CodeMonkey, действительно, не сказано... но вроде бы работает. Может лучше конечно на GetNextWindow переделать...

Чучмек, тоже какой-то колхоз.

b8195108, не катит, т.к.
Цитата(MetalFan @  13.1.2012,  15:46 Найти цитируемый пост)
все способы, определяющие частично перекрытие окна не катят на мой взгляд. т.к. неправильно сработают в след.ситуации: наше окно открыто не на весь экран и видно полностью, рядом АКТИВНО окно другого приложения так же не на весь экран и не перекрывающее наше окно. В этом случае по логике с перекрытиями наше окно считается поверх всех, т.к. видно полностью, что на мой взгляд неправильно.







--------------------
There are always someone smarter than you...
PM MAIL   Вверх
b8195108
Дата 14.1.2012, 15:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 27
Регистрация: 17.7.2011

Репутация: нет
Всего: 2



MetalFan, сорри, пропустил.
зы имхо не совсем правильная логика)
PM MAIL   Вверх
MetalFan
Дата 16.1.2012, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Qu1nt, отличия есть. если перейти с нашего окна к SOT-окну, то при клике по иконке в трее наша программа сворачивается, хотя хотелось бы, чтобы она активировалась.

Это сообщение отредактировал(а) MetalFan - 16.1.2012, 12:35


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 17.1.2012, 00:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Вот как выглядит функция обратного вызова для  EnumWindows у uTorrent
Код

004b5583 sub_4b5583:                      ; function entry point
004b5583   push    $fffffff0
004b5585   push    dword ptr [esp+8]
004b5589   call    dword ptr [$4f178c]    ; GetWindowLongW (USER32.dll)
004b5589
004b558f   test    eax, $10000000
004b5594   jnz     loc_4b559b
004b5594
004b5596   xor     eax, eax
004b5598   inc     eax
004b5599   jmp     loc_4b55c0
004b5599
004b5599 ; ---------------------------------------------------------
004b5599
004b559b loc_4b559b:
004b559b   mov     eax, [esp+8]
004b559f   inc     dword ptr [eax]
004b55a1   push    esi
004b55a2   push    0
004b55a4   push    dword ptr [esp+$c]
004b55a8   call    dword ptr [$4f1828]    ; GetWindowThreadProcessId (USER32.dll)
004b55a8
004b55ae   mov     esi, eax
004b55b0   call    dword ptr [$4f1198]    ; GetCurrentThreadId (kernel32.dll)
004b55b0
004b55b6   xor     ecx, ecx
004b55b8   cmp     esi, eax
004b55ba   setnz   cl
004b55bd   pop     esi
004b55be   mov     eax, ecx
004b55bd
004b55c0 loc_4b55c0:
004b55c0   ret     8

Код

function cb(hwnd:cardinal;var lparam:cardinal):bool;stdcall;
begin
result:=true;
if WS_VISIBLE=WS_VISIBLE and GetWindowLong(hwnd,GWL_STYLE)then
 begin
 inc(lparam);
 if GetCurrentThreadId=GetWindowThreadProcessId(hwnd,nil) then result:=false;
 end;
end;

А вот сам вызов EnumWindows
 
Код

004b55c3 sub_4b55c3:                      ; function entry point
004b55c3   push    ebp
004b55c4   mov     ebp, esp
004b55c6   push    ecx
004b55c7   and     dword ptr [ebp-4], 0
004b55cb   lea     eax, [ebp-4]
004b55ce   push    eax
004b55cf   push    $4b5583
004b55d4   call    dword ptr [$4f16d8]    ; EnumWindows (USER32.dll)
004b55d4
004b55da   xor     eax, eax
004b55dc   cmp     dword ptr [ebp-4], 2
004b55e0   setle   al
004b55e3   leave
004b55e4   ret


Код

....
var1:=0;
result:=false;
EnumWindows(@cb,integer(@var1));
if var1<=2 then result:=true;


Это сообщение отредактировал(а) Чучмек - 17.1.2012, 00:41


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 17.1.2012, 09:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, ну во первых, uTorrent работает не совсем корректно в случае, когда на экране есть SOT-окно - он перестает сворачиваться в трей вообще. ну и во вторых, спасибо конечно за реверс-инжиниринг, но ты хоть проверил, что у тебя получилось то?)


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 17.1.2012, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Цитата(MetalFan @  17.1.2012,  09:26 Найти цитируемый пост)
но ты хоть проверил, что у тебя получилось то

Вот теперь проверил. Работает.
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs,shellapi;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure ni(var msg:tmessage);message wm_user+1;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
function cb(hwnd:cardinal;var lparam:cardinal):bool;stdcall;
begin
result:=true;
if WS_VISIBLE=WS_VISIBLE and GetWindowLong(hwnd,GWL_STYLE)then
 begin
 inc(lparam);
 if GetCurrentThreadId=GetWindowThreadProcessId(hwnd,nil) then result:=false;
 end;
end;

procedure TForm1.ni(var msg:tmessage);
var var1 :cardinal;
begin
if msg.LParam=messages.WM_LBUTTONDBLCLK then
 begin
 var1:=0;
 EnumWindows(@cb,integer(@var1));
 if var1<=2 then form1.Visible:=false else
   begin
   form1.Visible:=true;
   setForegroundWindow(form1.Handle);
   end;
 end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var nd:TNotifyIconDataA ;
begin
nd.cbSize:=sizeof(nd);
nd.Wnd:=form1.Handle;
nd.uCallbackMessage:=wm_user+1;
nd.hIcon:=application.Icon.Handle;
nd.szTip:='Project1';
nd.uFlags:=NIF_TIP or NIF_ICON or NIF_MESSAGE;
Shell_NotifyIcon(NIM_ADD,@nd);
end;

end.




--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 17.1.2012, 13:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, опять же работает без учета текущего активного topmost окна... т.е. так же, как и мой последний вариант.
Но как вариант сойдет.
Я, кстати, остановился на варианте с GetNextWindow... т.к. действительно не стоит полагаться, что enumwindows обходит и будет обходить окна именно в порядке от верхнего к нижнему...

Это сообщение отредактировал(а) MetalFan - 17.1.2012, 13:48


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 17.1.2012, 13:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Это уже не ко мне. Это к создателям uTorrent.
Там, где ты про колхоз писал... Суть в том, чтобы после клика в трее "попросить" систему восстановить порядок окон.


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 17.1.2012, 13:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, да это понятно) просто uTorrent, как оказалось, не очень удачным примером оказался.
А про колхоз - ну посылать сочетания клавиш для того, чтобы "попросить" систему о чем-то, имхо, не совсем правильно...

Но все равно спасибо за активную помощь в поиске решения)  smile 

Это сообщение отредактировал(а) MetalFan - 17.1.2012, 13:51


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Чучмек
Дата 17.1.2012, 13:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Цитата(MetalFan @  17.1.2012,  13:51 Найти цитируемый пост)
не очень удачным

А какой удачный?



--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 17.1.2012, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, идеальным, на мой взгляд, считаю поведение TheBat.


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Qu1nt
Дата 17.1.2012, 15:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



MetalFan, очередная итерация.
Код

procedure TForm1.ApplicationEvents1Deactivate(Sender: TObject);
begin
  FToTray := not GetWindowLongPtr(GetForegroundWindow, GWL_EXSTYLE) and
    (WS_EX_TOPMOST or WS_EX_TOOLWINDOW) = 0;
end;

procedure TForm1.TrayIcon1Click(Sender: TObject);
begin
  if WindowState = wsMinimized then
  begin
    WindowState := wsNormal;
    Application.Restore;
    Show;
    Application.BringToFront;
  end
  else
    if FToTray then
    begin
      Application.Minimize;
      Hide;
    end
    else
      Application.BringToFront;
end;

Всё короче и короче smile
PM MAIL   Вверх
Чучмек
Дата 18.1.2012, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


НЭТ БИЛЭТ
**


Профиль
Группа: Участник
Сообщений: 841
Регистрация: 11.5.2008
Где: СССР

Репутация: 7
Всего: 41



Цитата(MetalFan @  17.1.2012,  14:10 Найти цитируемый пост)
TheBat

The Bat! написан на delphi или на чем-то подобном, а delphi компилит ###код smile 
Но из того что удалось понять следует следующее:
Сообщение трея $0401
Сообщения трея принимает не основная форма. 
В случае когда  основное окно The Bat есть foregroun:
   По сообщению основного окна WM_ACTIVATE/WA_INACTIVE запоминается текущее время.
   Если клик в трее происходит через "менее чем ...", окно сворачивается в трей. 


Добавлю:
TheBat время получает через GetTickCount
менее чем - это 500 тиков.

Это сообщение отредактировал(а) Чучмек - 18.1.2012, 15:06


--------------------
умную мысль держи при себе, а дурной - поделись с другими 
PM MAIL   Вверх
MetalFan
Дата 18.1.2012, 14:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 22
Всего: 128



Чучмек, я так и предполагал... одна из мыслей была как раз по определению некой временной дельты между потерей активности приложения и кликом по трею...
Теперь за дело говорю - спасибо!


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Qu1nt
Дата 18.1.2012, 15:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 22
Всего: 50



MetalFan, чем мой последний вариант не устроил?
PM MAIL   Вверх
CodeMonkey
Дата 18.1.2012, 20:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1839
Регистрация: 24.6.2008
Где: Россия, Тверь

Репутация: 29
Всего: 89



Цитата
В случае когда  основное окно The Bat есть foregroun:
   По сообщению основного окна WM_ACTIVATE/WA_INACTIVE запоминается текущее время.
   Если клик в трее происходит через "менее чем ...", окно сворачивается в трей. 


Эге, я же говорил.


--------------------
Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
PM MAIL WWW ICQ Skype GTalk Jabber   Вверх
kuzduk
  Дата 13.9.2012, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 21.9.2011

Репутация: нет
Всего: 2



Эгегей! Я знаю как просто и красиво решить данную проблему, когда при нажатии на трей-иконку надо определить активна ли была наша программа или нет!


Моё решение такое:
Код


type
  TForm1 = class(TForm)
   
   public
   procedure TrayClick(var msg: TMessage); message WM_MYICONNOTIFY; //перехватываем события трей-иконки

  end;


var
  _WindowActiv: Boolean = False;








implementation



procedure TForm1.TrayClick(var msg: TMessage);
begin

case msg.LParam
of    

  
  WM_MOUSEMOVE://событие когда навели курсор на трей-иконку нашей программы 
  begin
    //Запоминаем во внешнюю переменную активно ли окно нашей программы
    if (Application.Handle = GetForegroundWindow) or (Self.Handle = GetForegroundWindow)
    then _WindowActiv := True
    else _WindowActiv := False;
  end;


  WM_LBUTTONDOWN://событие когда кликнули ПКМ по трей-иконке нашей программы
  begin
          if IsIconic(Application.Handle) //свёрнута ли форма
//
          then//свёрнуто:
          begin
              Application.Restore;
              SetForegroundWindow(Application.Handle); //Вывести окно на передний план
              ShowNeedIcon(IconOnRestore.ItemIndex);
          end

          else//НЕ свёрнуто:
          begin
//              ВНИМАНИЕ!!! Self.Handle <> Application.Handle
//              if GetWindow(Self.Handle, GW_HWNDFIRST) = Self.Handle ...
//              if GetForegroundWindow = Self.Handle ...
//              if GetActiveWindow = Self.Handle ...
//              if GetLastActivePopup(GetDesktopWindow) = Self.Handle ...



              //Гемморой в том, что после клика по трей-иконке активной становится панель задач,
              //следовательно надо найти предыдущее активное окно,
              //если было активно окно нашей программы => свернуть программу
              //если было активно окно НЕ нашей программы => вывести окно нашей программы на передний план
              
              if _WindowActiv = true

              then//окно активно => сворачиваем
              begin
//                ShowMessage('активно');

                Application.Minimize;
                ShowNeedIcon(2);
                _WindowActiv := False;
              end

              else//окно пассивно => на передний план
              begin
//                ShowMessage('пассивно');

                SetForegroundWindow(Application.Handle);
                _WindowActiv := True;
              end;
          end;
  end;

end;

end;





--------------------


через Z-последовательности определить ничего не получилось - куча посторонних окон...

также можно попробовать поиграть с GetLastActivePopup(GetDesktopWindow)


--------------------


всем рекомендую качать мой модуль KuTray для работы с иконкой в трее и панели задач: http://kuzduk.narod.ru/_tray.html  smile 


также смотрите другие мои полезные модули и программы: http://kuzduk.narod.ru/_tvor.html  smile 

Это сообщение отредактировал(а) kuzduk - 14.9.2012, 12:28
PM MAIL WWW   Вверх
Akella
  Дата 3.2.2013, 00:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 8
Всего: 329



Кто-нибудь сталкивался с тем, что в Windows 7 x64 значок TTrayIcon не исчезает из области уведомления, хотя программа закрывается корректно?
Используется D2007 и стандартная компонента TTrayIcon, но немного переделанная:

Код

//уже не помню для чего это нужно было
Type
  TCrackTrayIcon = class(TTrayIcon)
  protected
    procedure WindowProc(var Message: TMessage); override;
  end;

  TfmMain = class(TForm)
...
...


implementation
....
...

procedure TfmMain.FormCreate(Sender: TObject);
begin
//так создаем
  TrayIcon2 := TCrackTrayIcon.Create(Application);
  TrayIcon2.Hint := constAppName + '(' + constSiteName + ')';
  TrayIcon2.Visible := True;
  TrayIcon2.PopupMenu := pmTray;
  TrayIcon2.Icon := Self.Icon;
  TrayIcon2.OnClick := TrayIconClick;


PM MAIL   Вверх
gesper
Дата 3.2.2013, 03:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


"Shарфик"
*


Профиль
Группа: Участник
Сообщений: 183
Регистрация: 23.2.2005

Репутация: 1
Всего: 2



А не переделаный так же все делает?
--------------------
...И приколется обломившийся и oбломится приколовшийся...
PM MAIL   Вверх
Akella
Дата 3.2.2013, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 8
Всего: 329



Всё равно остаётся
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Для новичков"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Для новичков | Следующая тема »


 




[ Время генерации скрипта: 0.2248 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.