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

  • Автор темы Shouldercannon
  • Дата начала
S

Shouldercannon

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

У каждой формы есть своя кнопка на панели задач благодаря
Код:
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 КБ · Просмотры: 263
S

sinkopa

Доброго времени суток!
Не могу понять в чём дело. Если форму свернуть с помощью иконки Свернуть в верхнем правом углу формы, то проверка на активность формы возвращает False. Если форму свернуть кликнув по кнопке формы на Панели задач, то проверка на активность возвращает True.
Помогите, пожалуйста разобраться.
Не совсем мне понятно, активность чего именно Вы пытаетесь отследить? Окна (THandle), Формы (TForm) или Приложения (TApplication)? <_<
Может вот это Вам поможет?
Код:
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.
 
S

Shouldercannon

Пытаюсь отследить активность Формы (TForm). Чем так сильно различаются два способа свернуть форму на панель задач (кнопкой в верхнем правом углу (system menu), кнопкой на панели задач), что в первом случае проверка Form.Active даёт True, а во втором False?
 
S

sinkopa

Пытаюсь отследить активность Формы (TForm). Чем так сильно различаются два способа свернуть форму на панель задач (кнопкой в верхнем правом углу (system menu), кнопкой на панели задач), что в первом случае проверка Form.Active даёт True, а во втором False?
Ответ в Вашем вопросе. <_<
Понятия "активое окно" и "активный заголовок окна" - разные вещи.
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 (пример я Вам дал)
 
S

Shouldercannon

Объяснили понятно <_< . Нашёл решение с помощью
Код:
 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 МБ · Просмотры: 247
S

Shouldercannon

Нашёл момент, когда WMActivate не срабатывает. Наставил BreakPoint тут
Код:
if (Msg.Active = WA_ACTIVE{1}) or (Msg.Active = WA_CLICKACTIVE{2}) then
и молчание
.
 
S

sinkopa

Нашёл момент, когда WMActivate не срабатывает. Наставил BreakPoint тут
Код:
if (Msg.Active = WA_ACTIVE{1}) or (Msg.Active = WA_CLICKACTIVE{2}) then
и молчание
.
Хм... на Вашем видео всё вроде работает. Заголовок формы меняется правильно, в соответствии с активностью заголовка формы. Что там не так по Вашему? <_<
PS
1. В первом варианте кода (который Вы "подрезали") вызов inherited должен быть ДО конструкции if() иначе нет гарантии что код (который Вы обозвали // Перестать мигать) не отменит фактическую активацию/деактивацию формы.
2. Если действия кода "// Перестать мигать" как-то связаны с перерисовкой формы либо изменением фокуса, эти действия правильнее выполнять ПОСЛЕ обработки формой сообщения WM_ACTIVATE. Для этого нужно "запостить" и обработать собственное сообщение.
Код:
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 меняет активность окон?... :)
 
S

Shouldercannon

Хм... на Вашем видео всё вроде работает. Заголовок формы меняется правильно, в соответствии с активностью заголовка формы. Что там не так по Вашему?
Когда пришло сообщение, заголовок формы был серым, что говорит о том, что форма не активна. Я кликнул по заголовку формы и он стал синим, событие OnActivate не сработало в противном случае мы бы получили сообщение и иконка перестала мигать,
1. В первом варианте кода (который Вы "подрезали") вызов inherited должен быть ДО конструкции if() иначе нет гарантии что код (который Вы обозвали // Перестать мигать) не отменит фактическую активацию/деактивацию формы.
Результат тот же
3. Вы не находите что останов по BreakPoint меняет активность окон?...
Запомнил при каких обстоятельствах не срабатывает OnActivate. Запустил Delphi, установил BreakPoint на if (Msg.Active = WA_ACTIVE) or (Msg.Active = WA_CLICKACTIVE) then. Довёл программу до момента на видео, где кликаю по заголовку, а иконка не перестаёт мигать. В этот момент обращений к OnActivate вообще не было.

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

Теперь такого не наблюдаю.
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!