Запретить деактивацию формы в Delphi 6
У нас есть приложение Delphi 6, которое использует немодальную форму с редактированием в сетке. В событии FormClose мы проверяем, что записи являются квадратными и предотвращаем закрытие, если это не так.
Однако, если пользователь нажимает на главную форму позади, то исходная форма исчезает позади (как вы и ожидали), но это позволяет пользователю перейти к новой записи на главном экране, без их изменений в сетке были проверены.
Я попробовал событие FormDeactivate, которое делает огонь, но, похоже, не имеет никакого механизма для предотвращения деактивации (в отличие от параметра действия FormClose events).
Я попробовал Онексит из сети, но он не срабатывает при деактивации.
Я попытался перехватить сообщение WM_ACTIVATE и установить Msg.Результат = 1, но это не имеет никакого эффекта (возможно, потому, что другое сообщение WM_ACTIVATE отправляется в основную форму?).
Итак, я ищу идеи о том, как (условно) предотвратить деактивацию формы, когда пользователь нажимает на другую форму.
(ПС Я не хочу менять стиль формы на fsStayOnTop)
Спасибо
6 ответов:
Когда вы звоните
ShowModal, все формы, кроме той, которую показывают, отключаются. Они снова включаются непосредственно перед возвращениемShowModal.Покажите вашу форму редактированиянемодально , и когда данные начнут редактироваться, заставьте форму сделать себя модальной, отключив другую форму. Включите другую форму после завершения редактирования. По-видимому, отключение windows не всегда так просто, как установка
Enabledсобственность. Я бы предложил использоватьDisableTaskWindows, но так и будет отключите все окна, включая форму редактирования. Тем не менее, взгляните на то, как это реализовано в формах .pas . Он хранит список всех окон, которые он отключает, так что только они будут повторно включены позже.
Классическое правило в Windows заключается в том, что вы не можете изменить фокус во время события изменения фокуса. Событие
OnDeactivateпроисходит во время события изменения фокуса. Вашей форме сообщают, что она деактивируется - ОС не запрашивает разрешения - и в то же время другой форме сообщают, что она активируется. Ни одно из окон не имеет никакого права голоса в этом вопросе, и попытка изменить фокус, пока эти события происходят, только запутает все окна. Симптомы включают наличие двух окна рисуют себя так, как будто у них есть фокус, и сообщения с клавиатуры никуда не идут, несмотря на мигание курсора ввода. MSDN еще более ужасен, хотя я никогда не видел ничего настолько плохого:Поскольку вы не можете отрицать изменение фокуса после того, как оно уже началось, нужно отложить обработку события до тех пор, пока все не успокоится. Когда ваша форма редактирования будет деактивирована и данные на ней еще не действительны, отправьте форме сообщение. Сообщение помещается в конец очереди сообщений, поэтому оно не будет обработано до тех пор, пока все предыдущие сообщения - в частности, уведомления об изменении фокуса-не будут обработаны. Когда приходит сообщение, указывает, что данные недопустимы, и возвращает фокус в форму редактирования:При обработке этого сообщения [WM_KILLFOCUS ] Не выполняйте никаких вызовов функций, которые отображают или активируют окно. Это приводит к тому, что поток теряет управление и приложение перестает отвечать на сообщения. Дополнительную информацию смотрите в разделе сообщение Тупики .
Я должен отметить, что этот ответ технически не отвечает на ваш вопрос, поскольку он ничего не делает для предотвращения деактивации формы, но вы отвергли мой другой ответ, который действительно предотвращает деактивацию.const efm_InvalidData = wm_User + 1; type TEditForm = class(TForm) ... private procedure EFMInvalidData(var Msg: TMessage); message efm_InvalidData; end; procedure TEditForm.FormDeactivate(Sender: TObject); begin if DataNotValid then PostMessage(Handle, efm_InvalidData, 0, 0); end; procedure TEditForm.EFMInvalidData(var Msg: TMessage); begin Self.SetFocus; ShowMessage('Invalid data'); end;
Delphi 2006 представила onmouseactivate события. OnMouseActivate основной формы позволит вам предотвратить активацию основной формы, если другая форма видна.
Это, конечно, не работает с D6.
Это не очень полезный ответ, Дэвид, но я думаю, что должен согласиться с другими респондентами, что это не правильный подход. Есть так много способов, что все это может пойти не так, что остановиться и посмотреть на другой способ решения вашей проблемы может быть лучше.
Даже если вам удалось найти событие / метод / сообщение, которое делает то, что вы хотите, вам все равно нужно будет иметь дело со сценарием, в котором отключается электричество.
О чуть более полезном обратите внимание, вы пробовали отключить свою основную форму до готовности? Вы можете поместить все элементы управления на панель, а затем просто сделать
panel1.enabled := false;
Вы также можете ввести в модель состояние, которое отслеживает, требуется ли окну фокус, как описано здесь, и использовать обработчики onFocus для других форм, которые программно возвращают фокус в окно сетки.
[Edit] копия моего комментария:
Вы можете зарегистрироваться для события onShow форм с помощью сетки. (Если вы реализуете его, обязательно сделайте его каким-то образом настраиваемым, чтобы минимизировать зависимость сетки от текущего макета приложения. Возможно, предоставив метод, вызываемый формами, который в свою очередь запускает регистрацию события сетки в вызывающей форме для события onShow)
Подробнее о регистрации событий:
Вы можете присоединить обработчики событий программно. В сети полно всяких Говорунов по этому поводу. У меня здесь нет Delphi, поэтому я не могу скопировать рабочий код сейчас.
Псевдокод для программной привязки события!
myform.onShow=myGrid.formOnShowHandler;FormOnShowHandler имеет ту же сигнатуру, что и функции которые генерируются IDE для событий onShow. Он имеет параметр, который можно использовать, чтобы выяснить, какая форма вызвала обработчик, чтобы вы могли повторно использовать функцию и просто поместить форму в фоновом режиме и снова показать свою форму сетки (которая будет, например, родительской для сетки).
Спасибо всем за помощь и предложения.
Вот решение, с которым я пошел: В "сеточной форме" (например, Form2)...
public PricesNotSquare: boolean;В событии FormDeactivate задайте PricesNotSquare значение true, если они не совпадают.
В событии OnActivate основной формы,...
if Assigned(Form2) and (Form2.PricesNotSquare) then begin ShowMessage( 'Please ensure the total Prices match before leaving the form' ); Form2.Show; exit; end; // other form activate stuff hereОказалось простым решением, просто потребовалось время, чтобы его получить.
Вроде бы работает нормально, но если у него есть проблемы, то я включу идею отправки сообщения.
Comments