Как сделать окно дочерним

Добавил пользователь Дмитрий К.
Обновлено: 05.10.2024

← →
dva20 © ( 2006-03-20 17:19 ) [0]

Как сделать свое главное окно дочерним чужого, при нажатии на кнопку?

Делал примерно так:

var
wHWND: HWND;
begin
wHWND:= FindWindow("CorelDRW 12.0",nil); //Находим дескриптор
//Становится дочерним, но оно только в панели задач и неразворачивается
Form1.ParentWindow:= wHWND;
//Делаем показать, и оно появляется не активным
Form1.Show;
end;

Вопрос. Как энто дело правильно организовать?

← →
clickmaker © ( 2006-03-20 18:33 ) [1]


> dva20 © (20.03.06 17:19)

а зачем тебе это?

← →
dva20 © ( 2006-03-20 18:46 ) [2]

Надо. :)

Вот так это работает как надо, но только при создании моего приложения формы, а мне надо на нажатие кнопки уже запущенного(созданного) приложения:

. = class(TForm)
.
protected
procedure CreateParams(var params: TCreateParams); override;
.

procedure TForm2.Createparams(var params: TCreateParams);
var
wHWND: HWND;
begin
inherited;

wHWND:= FindWindow("CorelDRW 12.0",nil);
params.WndParent := ahWnd;

end;

← →
clickmaker © ( 2006-03-20 18:53 ) [3]


> надо на нажатие кнопки уже запущенного(созданного) приложения

а как ты собираешься это нажатие отловить?

← →
dva20 © ( 2006-03-20 18:57 ) [4]

В первом посте написал. Тот код работает на нажатие кнопки, но существуют проблемы, которые описал уже.

> но существуют проблемы, которые описал уже.

Существует слишком много проблем, чтобы их здесь описывать.
Поэтому, на практике к таким трюкам не прибегают.

procedure TForm1.Button1Click(Sender: TObject);
var
wHWND: HWND;
begin
wHWND:= FindWindow(nil, "Adobe Photoshop"); //Находим дескриптор
//Становится дочерним, но оно только в панели задач и неразворачивается
Form1.ParentWindow:= wHWND;

//Это по барабану.
ShowWindow(Application.Handle,WS_CHILD);

//Делаем показать, и оно появляется не активным
//и не становится им никогда :)
Form1.Show;

WS_CHILD - это стиль
передается в CreateWindow, можно подменить в CreateParams

← →
dva20 © ( 2006-03-21 10:47 ) [9]

Делаю вот так:

procedure TForm1.Button1Click(Sender: TObject);
var
wHWND: HWND;
begin

wHWND:= FindWindow(nil, "Adobe Photoshop"); //Находим дескриптор
//Становится дочерним, но оно только в панели задач и неразворачивается
Form1.ParentWindow:= wHWND;

Если спрашивать свое окно, то оно неактивное!

то окно включено.

то окно видимо, то есть, выдает положительный результат (true). Но присутствие окна только на панели задач. Не развернуть не свернуть его не удается. Хотя если послать

то разварачивается на все окно (нового родителя), показывается, но опять же неактивным!флаги типа SW_NORMAL, SW_RESTORE не помагают, окно не "появляется".

Если вызвать просто FormMain.Show; после Form1.ParentWindow:= wHWND; то появляется, опять же не активным.

Как его сделать активным?

← →
clickmaker © ( 2006-03-21 11:24 ) [10]


>
> Как его сделать активным?

AttachThreadInput / SetActiveWindow

← →
dva20 © ( 2006-03-21 12:19 ) [11]

Примерно так пытаюсь сделать но ничего не выходит. Не знаю как по другому. Может подскажите?

WindowHWND:= FindWindow("CorelDRAW 12.0", nil);
//Меняем родителя окна
FormMain.ParentWindow:= WindowHWND;

ThreadID := GetWindowThreadProcessID(WindowHWND, nil);
ThisThreadID := GetWindowThreadPRocessId(FormMain.Handle, nil);
if AttachThreadInput(ThisThreadID, ThreadID, True) then
begin
//Окно появляется, но нестановится активным (аналог FormMain.Show)
BringWindowToTop(FormMain.Handle);
//Ничего не дает
SetActiveWindow(FormMain.Handle);
end;

Окно остается не активным. Окно можно передвигать, нажимать кнопки на нем, выбирать значения в ComboBox"e, в то же время значения в Edit не возможно ввести, окно все равно остается не активным.

← →
Сергей М. © ( 2006-03-21 12:59 ) [12]


> dva20 © (21.03.06 12:19) [11]

Ерундой ты занялся.

Созданием доч.окна должен заниматься код того целевого процесса, а не твой процесс.

Внедряй в АП целевого процесса код, создающий эту форму, - получишь требуемый результат.

← →
dva20 © ( 2006-03-21 13:03 ) [13]


>Ерундой ты занялся.
>
> Созданием доч.окна должен заниматься код того целевого
> процесса, а не твой процесс.

А как же с этим кодом? Ведь работает.

. = class(TForm)
.
protected
procedure CreateParams(var params: TCreateParams); override;
.

procedure TForm2.Createparams(var params: TCreateParams);
var
wHWND: HWND;
begin
inherited;

wHWND:= FindWindow("CorelDRW 12.0",nil);
params.WndParent := wHWND;

end;

← →
clickmaker © ( 2006-03-21 13:09 ) [14]


> dva20 © (21.03.06 13:03) [13]

а чего собственно нужно добиться от корела такими зверскими методами? Может есть решение проще?

Ну где же "работает", если сам говоришь, мол, того нет, этого нет, а, мол, надо щоб було ?

← →
dva20 © ( 2006-03-21 13:31 ) [16]

Повторюсь. Наверное чтоб было понятно чего мне нужно.

Вот с этим кодом моя прога встраивается как дочернее окно у Corel"a, все работает как мне надо, то есть окно активно ну и все такое. Но этот код работает только при создании моего приложения:

. = class(TForm)
.
protected
procedure CreateParams(var params: TCreateParams); override;
.

procedure TForm2.Createparams(var params: TCreateParams);
var
wHWND: HWND;
begin
inherited;

wHWND:= FindWindow("CorelDRW 12.0",nil);
params.WndParent := wHWND;

Что мне надо? Запустить свое приложение, ТОЛЬКО ЗАТЕМ на нажатие кнопки или чего другого, на клик короче, чтоб оно "встроилось", стало дочерним у Corel"a без всякой перезагрузки моего приложения. Вот. Думаю понятно написал чего я хочу.

Может как-то "на лету" можно пересоздать FormMain?

← →
clickmaker © ( 2006-03-21 13:47 ) [17]


> dva20 © (21.03.06 13:31) [16]

не, а все равно не понятно. Зачем его именно "встраивать" в корел?

← →
dva20 © ( 2006-03-21 14:23 ) [18]


> не, а все равно не понятно. Зачем его именно
> "встраивать" в корел?

А "зачем" я спрашивал потому что может есть еще какой-то способ получить результат. Ну не хочешь - не надо, приставать не буду больше

← →
Сергей М. © ( 2006-03-21 14:59 ) [20]


> dva20 © (21.03.06 14:23) [18]
> Извините, но вопрос не в том, зачем, а как?

Все верно. Но в вышенаписанном (посте номер 16) коде все работает чики-пуки без всяких на то глюков. Corel делает свое, а я свое. И нет никаких проблем!

Другой способ будет громозже, IMHO.

Вообщем мое приложение взаимодействует через OLE с Corel"ом (считает площадь объектов). Нужно выбрать объекты, затем нажать на кнопочку моего приложения "Расчет", Так вот, когда пользователь выбирает объекты, то мое окно улетает на задний план. Появляются лишние "телодвижения" чтобы его вернуть (лишние кликанья). Можно сделать поверх всех окон, но тогда оно будет мешатся другим запущенным приложениям. Опять же можно свернуть его, но опять лишние кликанья.
Было у меня решение: по таймеру 3 раза в секунду опрашивал Corel - Corel ты свернут? Если да, то тоже сворачивался, так же и наоборот. Но по таймеру - жрет проц. 3-5 процента у корела на машине P4-2.6
Поэтому этот метод не катит.

Поэтому то что я спрашиваю IMHO мне больше всего подходит:

Дочернее окно всегда "видимое" в Corel"е.
Не вылазит за пределы окна Corel"а.
Нет лишних кликаний.

Ключевой момент

← →
dva20 © ( 2006-03-21 15:42 ) [23]

Так как "подкрутить" тот код (пост 16), чтоб тоже самое выполнялось на клик кнопки в уже работающем приложении (моем)?

← →
Сергей М. © ( 2006-03-21 15:50 ) [24]


> dva20 © (21.03.06 15:42) [23]


> как

Тебе же говорят - твоя задача в ее решении ведет к внедрению кода в чужое АП. А не к тем примитивным трем-четырем строчкам. что ты безрезультатно мучаешь вплоть до сего поста ..

Дочернее окно (child window) имеет стиль WS_CHILD и ограничено рабочей областью его родительского окна. Прикладная программа обычно использует дочерние окна, чтобы поделить рабочую область родительского окна на функциональные области. Вы создаете дочернее окно, определяя стиль WS_CHILD в функции CreateWindowEx.

Дочернее окно должно иметь родительское окно. Родительское окно может быть перекрывающим окном, выскакивающим окном или даже другим дочерним окном. Вы определяете родительское окно, когда Вы вызываете CreateWindowEx. Если Вы определяете стиль WS_CHILD в CreateWindowEx, но не определяете родительское окно, Windows не создает окно.

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

Позиционирование

Windows всегда устанавливает дочернее окно относительно верхнего левого угла рабочей области родительского окна. Никакая часть дочернего окна когда-либо не появляется снаружи рамок его родительского окна. Если прикладная программа создает дочернее окно, которое является большим чем родительское окно или устанавливает дочернее окно так, чтобы некоторые или все дочерние окна располагаются вне рамок родителя, Windows отсекает дочернее окно; то есть часть снаружи рабочей области родительского окна не отображается. Действия, которые воздействуют на родительское окно, могут также воздействовать на дочернее окно, следующим образом.

Закрепление

Windows автоматически не закрепляет дочернее окно с рабочей областью родительского окна. Это означает, что родительское окно делает прорисовку поверх дочернего окна, если оно выполняет какое-либо рисование, в том же самом месте, где дочернее окно. Однако, Windows скрепляет дочернее окно с рабочей областью родительского окна, если родительское окно имеет стиль WS_CLIPCHILDREN. Если дочернее окно закреплено, родительское окно не может рисовать поверх его.

Дочернее окно может накладываться на другие дочерние окна в той же самой рабочей области. Дочернее окно, которое разделяет то же самое родительское окно с одним или большим количеством других дочерних окон, называется сестринским окном (sibling window). Сестринские окна могут рисовать в рабочей области друг друга, если одно из дочерних окон не имеет стиля WS_CLIPSIBLINGS. Если дочернее окно имеет этот стиль, любая часть его сестринского окна, которое находится внутри дочернего окна, закрепляется.

Если окно имеет стиль WS_CLIPCHILDREN или WS_CLIPSIBLINGS, происходит небольшая потеря в эффективности. Каждое окно занимает системные ресурсы, так что прикладная программа не должна использовать дочерние окна беспорядочно. Для самой лучшей эффективности, прикладная программа, которой нужно логически поделить свое главное окно, должна сделать это в оконной процедуре главного окна скорее, чем используемые дочерние окна.

Взаимоотношение с родительским окном

Прикладная программа может изменять родительское окно существующего дочернего окна, вызывая функцию SetParent. В этом случае, Windows удаляет дочернее окно из рабочей области старого родительского окна и перемещает его в рабочую область нового родительского окна. Если SetParent определяет значение дескриптора ПУСТО (NULL), окно рабочего стола становится новым родительским окном. В этом случае, дочернее окно рисуется в самом главном окне, вне рамок любого другого окна. Функция GetParent восстанавливает дескриптор родительского окна для дочернего окна.

Родительское окно уступает часть своей рабочей области дочернему окну, и дочернее окно принимает всю вводимую информацию для этой области. Класс окна не должен быть тот же самый для каждого из дочерних окон родительского окна. Это означает, что прикладная программа может заполнять родительское окно дочерними окнами, которые выглядят поразному и выполняют различные задачи. Например, диалоговое окно может содержать много типов элементов управления, каждое из них дочернее окно, которое принимает различные типы данных от пользователя.

Дочернее окно имеет только одно родительское окно, но родитель может иметь любое число дочерних окон. Каждое дочернее окно, в свою очередь, может иметь дочерние окна. В этой цепочке окон, каждое дочернее окно называется порожденным окном первоначального родительского окна. Прикладная программа использует функцию IsChild, чтобы обнаружить, является ли данное окно дочерним окном или порожденным окном данного родительского окна.

Функция EnumChildWindows перечисляет дочерние окна родительского окна. Затем, EnumChildWindows передает дескриптор каждого дочернего окна в определенную прикладной программой функцию повторного вызова. Порожденные окна данного родительского окна также перечисляются.

Создание приложения с дочерними окнами в Visual Studio предельно просто. При создании Windows приложения достаточно установить свойство IsMdiContainer в значение true и проект решения становится проектом решения с дочерними окнами, приобретая соответствующий вид и свойства (Рис.1.).

Следующим этапом разработки приложения с дочерними окнами становится создание непосредственно формы для дочерних окон. Для этого к проекту добавляем новую форму Рис.1. (например, с именем MDIChildForm).

Рис.1. Решение приложения с дочерними окнами

И, последним этапом, осталось добавить пункт меню (createChild) для создания новой формы и его обработчик (двойной клик мышкой на пункте меню) и пункт меню Close All Childern. И не забудем закрыть все, что открыто, в обработчике события пункта меню Close All Childern.

Можно создать дополнительно ("страховочное") закрытие всех открытых дочерних окон, например, в обработчике события закрытия основной формы:

Результат выполнения решения показан на Рис.2.

Рис.2. Приложение с дочерними окнами

Параграф 2. Взаимодействие между родительской и дочерними формами

Дочерние окна обычно используются как самостоятельные окна со своими функциональными возможностями. Уже хорошо то, что основное окно может управлять их открытием и закрытием. Хотя, это не мешает организовать и "более тесное взаимодействие" между ними. Организовать взаимодействие между окнами можно множествами способов. Один из них показан ниже.

Добавим в форму основного окна пункт меню "Set Phrase to Childern", как показано на Рис.3.

Рис.3. Решение приложения с дочерними окнами

Теперь, на дочернюю форму, поместим контролы Button и Label, с соответствующим текстом, как показано на Рис.4.

Рис.4. Форма для дочернего окна

В коде для дочерней формы или полностью заменим конструктор, или добавим еще один, который позволяет принимать ссылку на основную форму:

Соответственно в основной форме в функции создания дочернего окна необходимо заменить

В принципе, этого достаточно для показа взаимодействия форм. Но можно еще добавить определение параметров основной формы в дочерних окнах, как это сделано в обработчике события нажатия кнопки:

Результат выполнения решения показан на Рис.5.

Рис.5. Выполнение приложения

Молчанов Владислав 12.09.2007г., переработано 8.5.2009г.

Еcли Вы пришли с поискового сервера - посетите мою главную страничку

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

На этом шаге мы рассмотрим различные виды дочерних окон .

При самостоятельном создании приложений с использованием библиотеки OWL тут же начнут возникать вопросы типа: как создавать дочерние окна и как управлять ими? Как разобраться с линейками прокрутки? Каким образом добавлять эти полезные управляющие элементы при разработке собственных прикладных программ?

Ответы на эти, а также на многие другие вопросы вы найдете в следующих шагах, в которых глубже рассматриваются возможности OWL -класса TWindow . Здесь мы рассмотрим некоторые еще не знакомые вам функциями, так же как с полезными приемами программирования, которые позволяют использовать возможности Windows в полной мере.

В процессе обсуждения вопросов программирования в среде Windows и использования OWL возникли неоднозначные толкования термина "дочерние окна". К сожалению, из-за недостаточно исчерпывающих толкований этот термин часто имеет разный смысл, зависящий от контекста, в котором он употреблен.

К примеру, большинство объектов, возникающих в ваших приложениях: окна, диалоговые окна, управляющие элементы - являются объектами, связанными с классом TWindow , иными словами, эти объекты являются окнами. Поэтому, хотя дочернее окно MDI очевидно является таковым по определению, кнопку диалога иногда также называют дочерним окном.

Такое определние дочернего окна указывает на взаимосвязь объекта с другим окном. В этом смысле дочернее окно (будь то обычное окно или кнопка) имеет родительское окно. Однако, исходя из классической терминологии Windows , этот тип дочернего окна в действительности имеет не родительское окно, а так называемое окно-владельц. Это различие позволяет установить более-менее однозначное определение дочернего окна.

В Windows дочернее окно - это окно, имеющее стиль WS_CHILD . Окно данного типа не может быть передвинуто за пределы рабочей области родительского окна, подобно дочернему окну MDI . Такое определение дочернего окна указывает как на стиль окна, так и на тот факт, что это окно имеет родительское окно.

  1. Перекрывающиеся окно . У окна данного типа нет родительского окна (хотя может быть окно-владелец). Вы используете перекрывающееся окно, которое обычно имеет меню, строку заголовка и жирную рамку, в качестве главного окна вашего приложения. Перекрывающиеся окна имеют стиль WS_OVERLAPPED или WS_OVERLAPPEDWINDOW .
  2. Всплывающие окна . Эти окна не привязаны к рабочей области окна-владельца. Хотя всплывающее окно и принадлежит другому окну, оно может появляться в любом месте экрана. При минимизации всплывающего окна его пиктограмма появляется на рабочем столе Windows , а не в рабочей области окна-владельца. Всплывающие окна имеют стиль WS_POPUP или WS_POPUPWINDOW .
  3. Дочернее окно . Дочернее окно не может быть вынесено за пределы рабочей области своего родительского окна. Кроме того, при минимизации окна его пиктограмма появляется внутри родительского окна, а не на рабочем столе Windows . Стиль дочернего окна - WS_CHILD .

Замечание . При создании нового окна у программиста может возникнуть необходимость использования нескольких констант стиля окна, чтобы определить, как окно будет выглядеть и действовать. Например, полностью функциональное перекрывающееся окно может требовать задания следующих типов:

Чтобы избежать необходимости включения отдельной константы для каждого элемента типа окна, Windows определяет константы двух стилей, которые уже включают обычные стили окон. Константа WS_OVERLAPPEDWINDOW определяет перекрывающееся окно. Тип WS_POPUPWINDOW создает всплывающее окно с типами WS_POPUP, WS_BORDER, WS_SYSTEM (системное меню появляется, только если добавить WS_CAPTION ).

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

На 45 шаге вы познакомились с дочерним MDI -окном. Окна данного вида являются дочерними в буквальном смысле слова. Это означает, что они не могут быть перемещены за пределы рабочей области своего родительского окна, при минимизации их пиктограммы появляются внутри родительского окна. Но что делать, если вы захотите создать окно About или другой тип вспомогательного окна? Другими словами, как поступать, если необходимо сконструировать всплывающее окно не в MDI -приложениях. Следующий пример показывает, как это делается.

Следующий пример показывает, как создавать дочернее окно и использовать функцию-итератор ForEach для управления дочерним окном.

При запуске этой программы появляется главное окно приложения.


Рис.1. Результат работы приложения

Выберите команду Open из меню File , и появится новое дочернее окно. Помните, что это так называемое дочернее окно в действительности является подчиненным окном, так как оно имеет стиль, отличный от WS_CHILD . Вы можете создать столько дочерних окон, сколько вам захочется, выбирая повторно команду Open , как показано на рисунке 1. Вы можете закрыть каждое дочернее окно в отдельности двойным нажатием кнопки мыши, когда курсор будет находиться в верхнем левом углу дочернего окна, или можно закрыть одновременно все окна, выбрав команду Close All в меню File .

Посмотрите на класс главного окна:

Как обычно, конструктор TWndw определяет расположение и размеры главного окна прикладной программы и назначает ему меню. Кроме того, эта версия конструктора также инициализирует положение первого дочернего окна:

Конечно, в тот момент, когда программа инициализирует свои childX и childY , дочернее окно еще не существует. Значения этих полей используются в CmOpen() , функции, которую OWL вызывает при выборе команды Open из меню File :

Эта функция сначала вызывает конструктор TWindow , чтобы создать новое дочернее окно. Так как дочернее окно представляет собой "приправу" к TWindow , то программе не требуется для него специального класса. Однако атрибуты окна должны быть обязательно инициализированы. Функция CmOpen() получает доступ к атрибутам нового дочернего окна через указатель окна. Стиль окна устанавливается как WS_VISBLE | WS_POPUPWINDOW | WS_CAPTION , т.е. видимое всплывающее окно со строкой заголовка, системным меню и рамкой. Положение окна определяется величинами, хранящимися в childX и childY . Устанавливаются также ширина и высота окна. Затем программа отображает новое дочернее окно, вызывая функцию Create() , которая создает соответствующий элемент-окно. Наконец, CmOpen() вычисляет координаты следующего дочернего окна.

Когда пользователь выбирает в меню File команду Close All , OWL вызывает CmClose() :

  • итераторы ForEach() и FirstThat() , а также
  • функцию ChildWidth() , возвращающую указатель на дочернее окно с заданным идентификатором,
  • GetFirstChild() , возвращающую указатель на первое окно в списке;
  • HumChildren() , возвращающую число дочерних окон, и
  • Previous() , возвращающую указатель на последнее окно в списке.

В этой программе той функцией, которую ForEach() вызывает для каждого окна из списка дочерних окон, является CloseTheWindow() :

Когда ForEach() вызывает CloseTheWindow() , она передает в качестве параметров указатель обрабатываемого в данный момент окна и указатель списка параметров. CloseTheWindow() использует указатель окна для вызова функции окна ShutDownWindow() , которая, в свою очередь, вызывает функцию Destroy() из TWindow , чтобы убрать элемент окна с экрана и удалить объект окна.

Хотя создание и отображение дочерних окон осуществляется довольно легко, вы можете захотеть поэкспериментировать с различного типа WS_ константами, чтобы узнать, как выглядят и работают окна различных типов. Windows располагает разнообразными типами окон, давая вам возможность конструировать наиболее подходящее окно для вашего приложения.

В приложении есть дочернее окно, которое создается так:

Оно должно быть всегда на виду, но постоянно исчезает если кликнуть на любое другое окно приложения, как сделать его всегда сверху?

1 ответ 1

Для этого нужно установить флаг WS_EX_TOPMOST в расширенных стилях окна. Укажите этот флаг в первом аргументе функции CreateWindowEx. Либо вызывайте функцию SetWindowPos с аргументом HWND_TOPMOST в hWndInsertAfter .


Всё ещё ищете ответ? Посмотрите другие вопросы с метками c++ winapi или задайте свой вопрос.

Похожие

Для подписки на ленту скопируйте и вставьте эту ссылку в вашу программу для чтения RSS.

дизайн сайта / логотип © 2022 Stack Exchange Inc; материалы пользователей предоставляются на условиях лицензии cc by-sa. rev 2022.1.21.41235

Читайте также: