Delphi, как сделать независимые окна
У меня есть приложение, которое использует вкладки, как в браузере Chrome. Теперь я хочу иметь возможность открывать больше форм и не ограничиваться только одной формой. Эти формы должны действовать одинаково, но если я закрываю основную форму, все формы закрыты. Как я могу сделать все формы равными, чтобы, какую бы форму я ни закрыл, она закрывала только эту форму и не выходила из приложения до закрытия всех форм? Есть идеи?
С Наилучшими Пожеланиями Рой М. Клевер
5 ответов
это не слишком сложно сделать, хотя это начинает усложняться быстро в зависимости от того, насколько полным вы хотите, чтобы это было. Получение нескольких модальных диалогов для работы независимо-это тонна усилий.
чтобы начать, вам нужно избежать применения.Полностью форму mainform. Всегда используйте Form := TMyForm.Create(Application)
вместо Application.CreateForm(TMyForm, Form)
. Более поздние наборы MainForm, и вы никогда не хотите, чтобы это произошло.
чтобы сделать вещи закрытыми должным образом, вам нужно будет сделать что-то вроде этого в вашей форме OnClose
обработчик событий:
if Screen.FormCount = 1 then
Application.Terminate;
CloseAction := caFree;
Application.Run
полагается на присвоение MainForm, поэтому в вашем DPR замените эту строку этим циклом:
repeat
try
Application.HandleMessage;
except
Application.HandleException(Application);
end;
until Application.Terminated;
существует несколько способов обработки записи на панели задач.
запись на одной панели задач: Set
Application.MainFormOnTaskbar := False;
и будет использоваться скрытая ручка TApplication. При нажатии на запись панели задач все окна будут выведены на передний план. Вам нужно будет переопределитьApplication.OnMessage
или добавитьTApplicationEvents
компонент, и следите заWM_CLOSE
С Msg.Ручка = Приложение.Ручка.` В этом случае пользователь щелкнул правой кнопкой мыши на панели задач и выбрал закрыть, так что вы должны закрыть все окна.несколько записей панели задач: Set
Application.MainFormOntaskbar := True
. Переопределите формуCreateParams
методParams.WndParent := 0;
. Каждая запись панели задач будет управлять этой формой.
есть, вероятно, несколько других gotchas, но это основы.
как я уже сказал, что делает ShowModal
и TOpenDialog/TSaveDialog
работает независимо, поэтому он влияет только на его родительскую форму, и поэтому несколько диалогов могут быть открыты сразу, это тонна работы, и я не могу ее рекомендовать. Если вы мазохист, вот общие шаги:
-
заменить
TCustomForm.ShowModal
С пользовательской версии. Среди прочего, эта процедура отключает все остальные окна в приложении, поэтому вам нужно заменитьDisableTaskWindows/EnableTaskWindows
звонки сEnableWindow(Owner.Handle, False/True)
чтобы просто отключить родительскую форму. На этом этапе можно открыть несколько диалоговых окон, но они могут быть закрыты только в порядке "последний вход" и "первый выход", поскольку вызовы становятся рекурсивными. Если все в порядке, остановись здесь.есть два способа обойти это:
вместо
ShowModal
блокированиеStartModal
иEndModal
подпрограммы, которые имеют Первый БИТ и последний бит кода ShowModal и вызываютOnShowModalDone
событие, когда диалоговое окно закрытый. Это своего рода боль в использовании, но относительно легко кодировать и легко сделать стабильным.используйте Windows подпрограммы волокна для замены стека и запуска нового цикла сообщений. Этот подход прост в использовании, потому что
ShowModal
блокирует, поэтому вы называете это как обычно. Это подход, который мы использовали в Beyond Compare. не делай этого. это сложно написать, там будет вопросы стабильности для нетривиальных приложения из-за несовместимости со сторонним кодом (Windows global message hooks, TWebBrowser, .NET в расширениях оболочки, загружаемых диалоговым окном обзора и т. д.), И если это кросс-платформенный проект, функции ucontext Unix также небезопасны для использования.
общие диалоги (TOpenDialog, TColorDialog и т. д.) имеют аналогичные ограничения. Чтобы сделать их только отключить родительскую форму, вам нужно переопределить
TCommonDialog.TaskModalDialog
и заменитьDisableTaskWindows/EnableTaskWindows
звонит и туда. Они не могут быть сделаны асинхронными, как обычные диалоговые окна Delphi выше, хотя, поскольку они блокируют функции, предоставляемые Windows (GetOpenFileName, ChooseColor и т. д.). Единственный способ закрыть их в любом порядке-запустить каждый диалог в выделенном потоке. Windows может обрабатывать большую часть синхронизации для этого, если вы будете осторожны с доступом к объектам VCL, но это в основном включает перезапись больших частейDialogs.pas
.
Если вы действительно хотите этого,
1) используйте небольшую, возможно скрытую, MainForm и запустите только первую дочернюю форму при запуске.
2) запуск отдельных приложений вместо Windows в том же процессе. Это то, что использует более поздняя версия Office.
вот аналогичный вопрос StackOverflow: активация нескольких приложений windows работает неправильно
в моем случае я не пытаюсь избежать MainForm, как описывает Крейг. Вместо этого я скрываю главное окно, и все мои настоящие окна-это другие немодальные формы. Я был доволен тем, как работает мое приложение, но подход Крейга может быть проще.
см. мой ответ на вышеуказанный вопрос, чтобы увидеть примеры кода для моего подхода и несколько ссылок с хорошим исходная информация.
первая форма, созданная в приложении Delphi, рассматривается как основная форма, и приложение завершается, когда эта форма закрывается. Очевидное решение состоит в том, чтобы иметь первую форму, которая не закрывается пользователем, а скорее не видна пользователю и закрывается только тогда, когда все другие формы были закрыты.
Я не пробовал это, но он должен работать.
Это слишком поздно, чтобы ответить, но я столкнулся с той же проблемой. Решение, которое я выбрал, - это извлечь Application.ExeName
и передать его функции, как createProcess
или даже shellExecute
. Итак, теперь у меня есть независимые приложения на уровне ОС. Мне также нужны были разные кнопки панели задач для разных экземпляров.