Проверка На Активность Формы Возвращает True После Сворачивания

Тема в разделе "Delphi - Компоненты", создана пользователем Shouldercannon, 28 дек 2014.

  1. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Доброго времени суток!
    Не могу понять в чём дело. Если форму свернуть с помощью иконки Свернуть в верхнем правом углу формы, то проверка на активность формы возвращает False. Если форму свернуть кликнув по кнопке формы на Панели задач, то проверка на активность возвращает True.
    Помогите, пожалуйста разобраться.

    У каждой формы есть своя кнопка на панели задач благодаря
    Код (Delphi):
    procedure TForm.CreateParams(var Params: TCreateParams);
    begin
    inherited CreateParams(Params);
    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
    end;
    Что делаем:
    1. Запускаем приложение, нажимаем кнопку Test (у нас есть 3 секунды) и сразу же сворачиваем форму на Панель задачь через кнопку Свернуть в верхнем правом углу формы. В данном случае всё нормально и звук не проигрывается.
    2. Запускаем приложение, нажимаем кнопку Test (у нас есть 3 секунды) и сразу же сворачиваем форму на Панель задачь через кнопку формы на Панели задач. В данном случае звук проигрывается говоря о том, что форма активна, но она свёрнута и не показывается.
     

    Вложения:

    • Test.zip
      Размер файла:
      327,4 КБ
      Просмотров:
      4
  2. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Не совсем мне понятно, активность чего именно Вы пытаетесь отследить? Окна (THandle), Формы (TForm) или Приложения (TApplication)? <_<
    Может вот это Вам поможет?
    Код (Delphi):
    unit Unit1;

    interface

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

    type
    TForm1 = class(TForm)
    private
    procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE;
    protected
    procedure CreateParams(var Params: TCreateParams);
    public

    end;

    var
    Form1: TForm1;

    implementation

    {$R *.dfm}

    { TForm1 }

    procedure TForm1.CreateParams(var Params: TCreateParams);
    begin
    inherited CreateParams(Params);
    Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
    end;

    procedure TForm1.WMActivate(var Msg: TWMActivate);
    begin
    inherited;
    case Msg.Active of
    0: MessageBeep(MB_ICONASTERISK);    // Окно деактивировалось
    1: MessageBeep(MB_ICONEXCLAMATION); // Окно активизировалось
    2: MessageBeep(MB_OK);           // Окно активизировалось щелчком мыши
    end;
    end;

    end.
     
  3. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Пытаюсь отследить активность Формы (TForm). Чем так сильно различаются два способа свернуть форму на панель задач (кнопкой в верхнем правом углу (system menu), кнопкой на панели задач), что в первом случае проверка Form.Active даёт True, а во втором False?
     
  4. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Ответ в Вашем вопросе. <_<
    Понятия "активое окно" и "активный заголовок окна" - разные вещи.
    1. Свойство Form.Active сообщает активен ли заголовок окна.
    2. Заголовок окна меняет состояние активности через сообщение WM_ACTIVATE (см пример в моём предыдущем посту).
    3. Через system menu окну посылается сообщение WM_MINIMIZE, которое никакого отношения к WM_ACTIVATE не имеет.
    WM_ACTIVATE при этом лишь "побочный эффект" из за того что Вы кликаете по кнопке СВЕРНУТЬ ("мимо" заголовка окна). Т.е. сообщения WM_MOUSEDOWN, WM_MOUSEUP ушли контролу системного меню (не заголовку окна).
    4. Кликая в панели задач Вы кликаете по ЗАГОЛОВКУ окна отображенного в панели задач (Params.ExStyle or WS_EX_APPWINDOW).
    Понятно объяснил? :)

    PS.
    А еще бывает "невидимое окно", "окно свёрнутое в значок" и "активное окно с неактивным заголовком"...
    Если Вам необходимо отслеживать именно активность надо ловить изменения этого состояния через WM_ACTIVATE (пример я Вам дал)
     
  5. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Объяснили понятно <_< . Нашёл решение с помощью
    Код (Delphi):
     function WindowCaption: string;
    var
    Nm: array[0..255] of Char;
    Wind: HWND;
    begin
    Wind := GetForegroundWindow();

    while GetParent(Wind) <> 0 do
    begin
    Wind := GetParent(Wind);
    end;

    GetWindowText(Wind, Nm, SizeOf(Nm)); // Считываем текст заголовка окна
    Result := string(Nm);
    end;
     

    Вложения:

    • Test.zip
      Размер файла:
      1,1 МБ
      Просмотров:
      1
  6. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Нашёл момент, когда WMActivate не срабатывает. Наставил BreakPoint тут
    Код (Delphi):
    if (Msg.Active = WA_ACTIVE{1}) or (Msg.Active = WA_CLICKACTIVE{2}) then
    и молчание
    Видео с действиями.
     
  7. sinkopa

    sinkopa Well-Known Member

    Регистрация:
    17 июн 2009
    Сообщения:
    344
    Симпатии:
    9
    Хм... на Вашем видео всё вроде работает. Заголовок формы меняется правильно, в соответствии с активностью заголовка формы. Что там не так по Вашему? <_<
    PS
    1. В первом варианте кода (который Вы "подрезали") вызов inherited должен быть ДО конструкции if() иначе нет гарантии что код (который Вы обозвали // Перестать мигать) не отменит фактическую активацию/деактивацию формы.
    2. Если действия кода "// Перестать мигать" как-то связаны с перерисовкой формы либо изменением фокуса, эти действия правильнее выполнять ПОСЛЕ обработки формой сообщения WM_ACTIVATE. Для этого нужно "запостить" и обработать собственное сообщение.
    Код (Delphi):
    unit Unit1;
    interface
    uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;
    const
    WM_MY_STOP_BLINK = WM_USER + 10; // кастомное сообщение
    type
    TForm1 = class(TForm)
    private
    procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE;
    procedure WMMyStopBlink(var Msg: TMessage); message WM_MY_STOP_BLINK;
    public
    end;
    var
    Form1: TForm1;

    implementation

    procedure TForm1.WMActivate(var Msg: TWMActivate);
    begin
    inherited;
    { отправляем сообщение ( Перестать мигать) самому себе
    отправленное через PostMessage сообщение обработается
    когда до него дойдет очередь
    }

    if Msg.Active in [1,2] then
    PostMessage(Self.Handle,WM_MY_STOP_BLINK,1,0)  // Окно активизировалось
    else
    PostMessage(Self.Handle,WM_MY_STOP_BLINK,0,0); // Окно деактивировалось
    end;

    procedure TForm1.WMMyStopBlink(var Msg: TMessage);
    begin
    if (Msg.Msg = WM_MY_STOP_BLINK) then begin
    if (Msg.WParam = 1) then begin
    MessageBeep(MB_OK);          // Окно активизировалось
    //... Перестать мигать
    end
    else
    MessageBeep(MB_ICONASTERISK);   // Окно деактивировалось
    Self.Caption := IntToStr(Msg.WParam);
    // подозреваю еще нужно вызвать перерисовку? (раз там что то такое мигало)
    Self.Invalidate;
    end;
    end;
    end.
    3. Вы не находите что останов по BreakPoint меняет активность окон?... :)
     
  8. Shouldercannon

    Shouldercannon Well-Known Member

    Регистрация:
    25 май 2010
    Сообщения:
    125
    Симпатии:
    0
    Когда пришло сообщение, заголовок формы был серым, что говорит о том, что форма не активна. Я кликнул по заголовку формы и он стал синим, событие OnActivate не сработало в противном случае мы бы получили сообщение и иконка перестала мигать,
    Результат тот же
    Запомнил при каких обстоятельствах не срабатывает OnActivate. Запустил Delphi, установил BreakPoint на if (Msg.Active = WA_ACTIVE) or (Msg.Active = WA_CLICKACTIVE) then. Довёл программу до момента на видео, где кликаю по заголовку, а иконка не перестаёт мигать. В этот момент обращений к OnActivate вообще не было.

    Заметил, что при клике по иконке в трее главная форма приложения всегда с активным заголовком. У дочерней формы такого не наблюдал, если конечно дочерняя форма не была показана раньше главной. Теперь когда показываю дочернюю форму, то вызываю
    Код (Delphi):
    SetForegroundWindow(Self.Handle); // Для FormPrivate
    До этого наблюдал такую картину:
    Как докопаться до бага (ShowPopup=0 (не показываем никакие формы с оповещениями), только одна вкладка):
    1. Отправим нам приватное сообщение
    2. Кликаем по мигающей иконке в трее. Отображается форма, заголовок формы активен
    3. Закроем вкладку (форма закроется, так как вкладок больше нет)
    4. Отправим нам приватное сообщение
    5. Кликаем по мигающей иконке в трее. Отображается форма, заголовок формы не активен
    6. Отправим нам приватное сообщение
    7. Кликнем по заголовку формы привата, он переходит из неактивного состояния в активное. Сообщение не получено, иконка в Tab мигает
    8. Кликаем по мигающей иконке в трее. Получаем сообщения, иконка в Tab перестаёт мигать, заголовок формы не активен
    Далее петля (форму привата не закрываем)
    6-8

    Теперь такого не наблюдаю.
     
Загрузка...
Похожие Темы - Проверка На Активность
  1. ghost
    Ответов:
    0
    Просмотров:
    149
  2. JohnLemon
    Ответов:
    7
    Просмотров:
    1.759
  3. San40S
    Ответов:
    4
    Просмотров:
    1.387
  4. EmptyR
    Ответов:
    7
    Просмотров:
    4.456
  5. Dragon108
    Ответов:
    8
    Просмотров:
    4.230

Поделиться этой страницей