У меня есть приложение, которое использует вкладки как браузер Chrome. Теперь я хочу смочь открыть больше форм и не быть ограниченным только одной формой. Эти формы должны действовать то же, но если я закрываю основную форму, все формы закрываются. Как я могу заставить все формы быть равными, так неважно, которые формируются, я закрываюсь, это только закрывает ту форму и не приложение выхода, прежде чем все формы будут закрыты? Какие-либо идеи?
Наилучшие пожелания Roy M Klever
Сделать это не так уж сложно, хотя все начинает быстро усложняться в зависимости от того, насколько полной вы хотите. Заставить несколько модальных диалогов работать независимо - это огромные усилия.
Для начала вам нужно полностью избегать Application.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;
Есть несколько способов обработать запись на панели задач.
Отдельная запись на панели задач: Установите Application.MainFormOnTaskbar: = False;
, и будет использоваться скрытый дескриптор TApplication. При нажатии на запись на панели задач все окна выводятся на передний план. Вам нужно будет переопределить Application.OnMessage
или добавить компонент TApplicationEvents
и следить за WM_CLOSE
с помощью Msg.Handle = Application.Handle`. В этом случае пользователь щелкнул правой кнопкой мыши на панели задач и выбрал Закрыть , поэтому вам следует закрыть все окна.
Несколько записей на панели задач: установите Приложение.MainFormOntaskbar: = True
. Переопределите метод CreateParams
вашей формы и установите Params.WndParent: = 0;
. Каждая запись на панели задач будет управлять этой формой.
Вероятно, есть еще несколько ошибок, но это основы.
Как я уже сказал, заставить ShowModal
и TOpenDialog / TSaveDialog
работать независимо, так что это влияет только на его родительскую форму, и поэтому несколько диалогов могут быть открыты одновременно, - это огромная работа. , и я не могу его рекомендовать. Если вы мазохист, вот общие шаги:
Замените TCustomForm.ShowModal
собственной версией. Помимо прочего, эта процедура отключает все другие окна в приложении, поэтому вам нужно заменить вызовы DisableTaskWindows / EnableTaskWindows
на EnableWindow (Owner.Handle, False / True)
, чтобы просто отключить родительскую форму. На этом этапе вы можете открыть несколько диалогов, но их можно закрыть только в порядке «последний пришел - первый ушел», потому что в конечном итоге вызовы рекурсивны. Если все в порядке, остановись здесь.
Есть два способа обойти это:
Вместо того, чтобы блокировать ShowModal
, используйте подпрограммы StartModal
и EndModal
, которые имеют первый бит и последний бит кода ShowModal и вызвать событие OnShowModalDone
при закрытии диалогового окна. Это своего рода боль в использовании, но его относительно легко кодировать и легко сделать стабильным.
Используйте подпрограммы оптоволокна Windows для замены стека и запуска нового цикла сообщений.Этот подход прост в использовании, поскольку ShowModal
блокирует, поэтому вы вызываете его как обычно. Это подход, который мы использовали в Beyond Compare. Не делай этого. Сложно написать, там будут проблемы со стабильностью для нетривиальных приложений из-за несовместимости со сторонним кодом (глобальные перехватчики сообщений Windows, TWebBrowser, .NET в расширениях оболочки, загружаемых из диалогового окна просмотра, и т. д.), и если это кроссплатформенный проект, использование функций ucontext в Unix тоже небезопасно.
Общие диалоги (TOpenDialog, TColorDialog и т. Д.) Имеют аналогичные ограничения. Чтобы они отключили только родительскую форму, вам нужно переопределить TCommonDialog.TaskModalDialog
и заменить там вызовы DisableTaskWindows / EnableTaskWindows
. Однако их нельзя сделать асинхронными, как обычные диалоговые окна Delphi, описанные выше, поскольку они блокируют функции, предоставляемые Windows ( GetOpenFileName , ChooseColor и т. Д.). Единственный способ разрешить их закрытие в любом порядке - запустить каждый диалог в отдельном потоке. Windows может обрабатывать большую часть синхронизации для этого, если вы осторожны с доступом к объектам VCL, но в основном это включает в себя переписывание больших частей Dialogs.pas
.
Вот аналогичный вопрос StackOverflow: Активация нескольких окон приложений работает некорректно
В моем случае я не старайтесь избегать MainForm, как описывает Крейг. Вместо этого я скрываю главное окно, и все мои настоящие окна представляют собой другие немодальные формы. Я доволен тем, как работает мое приложение, но подход Крейга может быть проще.
См. Мой ответ на вышеупомянутый вопрос, чтобы увидеть примеры кода для моего подхода и несколько ссылок с хорошей справочной информацией.
Если вы действительно этого хотите,
1) используйте небольшую, возможно, скрытую MainForm и запускайте только первую дочернюю форму при запуске.
2) запускать отдельные приложения вместо Windows в одном процессе. Это то, что используется в более поздней версии Office.
Создана первая форма в приложении Delphi рассматривается как основная форма, и приложение завершается, когда эта форма закрывается. Очевидное решение - иметь первую форму, которая не будет закрыта пользователем, а будет невидимой для пользователя и закрывается только после закрытия всех остальных форм.
Я не пробовал, но должно работать.