OnExit элемента управления использует событие mouseup для нового элемента управления при отображении другого окна - PullRequest
1 голос
/ 16 августа 2011

Я нашел этот вопрос на Experts-Exchange .

OnExit элемента управления съедает событие mouseup для нового элемента управления при отображении другое окно

Проблема может быть легко воспроизведена.

Поместите 3 формы в форму. написать showmessage ('выход') в edit1's событие onexit запустить программу дать edit1 фокус использовать мышь, чтобы дать edit3 focus, нажмите ok, чтобы показать сообщение и посмотрите, как вы не можете написать что-нибудь в edit3 сейчас, пока вы не нажмете мышью где-нибудь на форма! дайте edit2 фокус, затем используйте мышь, чтобы придать edit3 фокус Посмотрите, как вы можете ввести то, что вы хотите в edit3 сейчас!

Пока я установил, что проблема заключается в том, что edit3 не получает сообщение mouseup, когда старые элементы управления события onExit отображает окно любого вида, я пробовал также показывать моя собственная форма в событии onExit, тот же результат. На самом деле, окна это под впечатлением, что мышка зажата над edit3 после Вы нажали Ok, чтобы показать сообщение

Полагаю, это ошибка в Delphi / Windows, но как ее обойти? я знаю, что я могу заставить WM_LBUTTONUP на событие onMouseDown edit3 (так как это последнее событие, вызванное в процессе), но это больше, чем утомительно и не всегда применимо

Я пытаюсь сделать что-то похожее:

В событии onexit я показываю предупреждение и затем хочу продолжить как обычно - перемещение фокуса туда, где фактически щелкнул пользователь. Это возможно?

Ответы [ 3 ]

6 голосов
/ 16 августа 2011

Еще раз PostMessage на помощь! Отложите диалог немного подольше, чтобы Windows смогла закончить изменение фокуса. Напишите себе сообщение вместо того, чтобы показывать диалог напрямую:

const
  WM_SHOWMYDIALOG = WM_APP + 321;

TForm1 = class(TForm)
  Edit1: TEdit;
  Edit2: TEdit;
  procedure Edit1Exit(Sender: TObject);
private
  procedure WMSHOWMYDIALOG(var Message: TMessage); message WM_SHOWMYDIALOG;
end;

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  PostMessage(Self.Handle, WM_SHOWMYDIALOG, 0, 0);
end;

procedure TForm1.WMSHOWMYDIALOG(var Message: TMessage);
begin
  ShowMessage('Nice one');
end;

И все нормально :) 1005 *

4 голосов
/ 16 августа 2011

Я не уверен, что причиной такого поведения является съеденное сообщение мыши.В любом случае, в любом случае, когда вы активируете окно в событии элемента управления OnExit, вы делаете то, что изменяете фокус, а фокус меняется.Это потому, что окно активируется до WM_SETFOCUS для вновь сфокусированного элемента управления.Это не рекомендуется, ниже приводится цитата из раздела «Лучшие практики» в « Активация Win32 и фокус », запись в блоге на MSDN:

Избегайте ручного изменения фокуса при получении и/ или потерять фокус.Это обычно оказывается подверженным ошибкам.

Тот факт, что элементы управления отключены во время переноса фокуса из-за модальной природы активированного окна, безусловно, не поможет.Если вы действительно должны это сделать, такой подход, как ответ Генриха , по крайней мере задержит запуск окна до завершения передачи фокуса.

2 голосов
/ 16 августа 2011

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

Да, (Screen.)ActiveControl всегда будет указывать на Edit3: до и после вызова ShowMessage:

procedure TForm1.Edit1Exit(Sender: TObject);
begin
  ShowMessage('Exit');
  PostMessage(ActiveControl.Handle, WM_LBUTTONUP, 0, 0);
end;

Но это только для полноты ради вашего вопроса! И это, конечно, ни совет, ни совет! См. Ответ Сертака по причине.

...