Связать две формы windows forms

Обновлено: 07.07.2024

БлогNot. Visual C++: из формы в форму

Visual C++: из формы в форму

Несмотря на то, что моё мнение о микрософтовском Visual Studio по-прежнему остаётся невысоким, иногда приходится что-то делать и на нём. Если смириться с тем, что пишем мы при этом, собственно, не на C++, а на так называемом C++/CLI, работа с привычными визуальными компонентами будет не так уж сильно отличаться от тех же Борландовских сред. А вот взаимодействие форм и модулей способно, по сравнению с Builder'ом, создать проблемы. Рассмотрим 3 типовых ситуации работы с приложением, содержащим больше одной формы. Среда примера - бесплатная Visual C++ 2010 Express, предполагается, что главная форма имеет имя по умолчанию Form1 .

Пример конструирования и программного вызова формы

Этот код можно выполнить, например, по нажатию кнопки в главной форме Form1.

Для добавления обработчика нажатия программно сгенерированной кнопки button2 достаточно перед последней строкой кода написать:

- до того, как будет вызван метод form2->ShowDialog() или form2->Show();

При этом код обработчика размещён в текущем модуле Form1.h :

Вызвать другую форму из главной формы

В меню выберем Проект - Добавить новый элемент - Форма - имя Form2

перед первым namespace в Form1.h (то есть, в самое начало файла).

Включим указатель на экземпляр класса в секцию public класса Form1 :

Добавим код там, где нужно создать и вызвать вторую форму:

Для программного удаления второй формы подойдёт код

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

Опишем нужные данные в классе формы Form1 (здесь имя и namespace проекта Tabulator , если нужно, замените на своё):

Потом инициализируем данные по событию Load главной формы:

Затем реализуем код для создания очередной формы

Если мы хотим создавать дочерние формы не отдельно, а внутри родительской формы, то в свойствах Form1 нужно указать, что она "предок" (установить свойство IsMdiParent = true ), а перед показом дочерней формы оператором F2[FormCount-1]->Show() пометить её как потомка Form1:

Вызвать из дочерней формы метод родительской формы

Нам едва ли обойтись без привлечения файлов .cpp, что неплохо - писать код в файлах .h правильного Си'шника вообще ломает :)

Распишем процесс по шагам.

1) Имеются 2 формы - Form1 и Form2 , на Form1 располагаются Button ( button1 , будет открывать вторую форму) и Label ( label1 , здесь будем менять текст). На Form2 - button1 , по нажатию на которую будет происходить смена текста в label1 .

2) Так как нам из первой формы нужно иметь доступ ко второй, а из второй к первой, то будет возникать проблема перекрестных ссылок (когда Form1.h ссылается на Form2.h , который, в свою очередь, опять ссылается на Form1.h ). Для того, чтобы этого избежать, код первой формы ( Form1 ), который будет иметь доступ ко второй форме ( Form2 ), мы вынесем из .h-файла в .cpp файл. Таким образом нужно создать файл Form1.cpp .

4) В файле Form2.h подключаем Form1.h (в начале):

и создаем конструктор, который будет принимать и сохранять ссылку на первую форму для дальнейшего использования: //ниже сразу ниже можно прописать ссылку: private: Form1^ parentForm;

5) По клику кнопки в Form2 будем вызывать метод Set родительской формы:

6) Осталось в первой форме сделать открытие второй формы. Для этого из Form1.h обработчик нажатия кнопки переносим в Form1.cpp , а в .h-файле оставляем только его объявление.

Код в файле Form1.cpp :

В Form1.h вставляем только строку:

На этом все. Можно скомпилировать и проверить проект, архив во вложении:

Наладить взаимодействие двух форм

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

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

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

В данном пошаговом руководстве представлены следующие задачи.

создание нового проекта Windows Forms приложения .

Создание и настройка набора данных с помощью мастера настройки источника данных.

Выбор элемента управления, создаваемого на форме при перетаскивании элементов из окна Источники данных. Дополнительные сведения см. в разделе Установка элемента управления, создаваемого при перетаскивании из окна Источники данных.

Создание элемента управления с привязкой к данным с помощью перетаскивания элементов из окна Источники данных на форму.

Создание второй формы с сеткой для отображения данных.

Создание запроса адаптера таблицы для получения заказов определенного клиента.

Передача данных между формами.

Предварительные требования

в этом пошаговом руководстве используется SQL Server Express LocalDB и образец базы данных Northwind.

если у вас нет SQL Server Express LocalDB, установите его на странице загрузки SQL Server Expressили с помощью Visual Studio Installer. в Visual Studio Installer SQL Server Express LocalDB можно установить как часть рабочей нагрузки хранения и обработки данных или как отдельный компонент.

Установите учебную базу данных Northwind, выполнив следующие действия.

в Visual Studio откройте окно обозреватель объектов SQL Server . (SQL Server обозреватель объектов устанавливается как часть рабочей нагрузки хранения и обработки данных в Visual Studio Installer.) разверните узел SQL Server . щелкните правой кнопкой мыши экземпляр LocalDB и выберите создать запрос.

Откроется окно редактора запросов.

скопируйте скрипт Transact-SQL Northwind в буфер обмена. этот сценарий T-SQL создает базу данных Northwind с нуля и заполняет ее данными.

вставьте скрипт T-SQL в редактор запросов, а затем нажмите кнопку выполнить .

По истечении короткого времени выполнение запроса завершается и создается база данных Northwind.

создание проекта Windows Forms приложения

В Visual Studio в меню Файл выберите пункты Создать > Проект.

в средней области выберите тип проекта приложения Windows Forms .

Назовите проект пассингдатабетвинформс и нажмите кнопку ОК.

Создается проект PassingDataBetweenForms, который добавляется в Обозреватель решений.

Создание источника данных

Чтобы открыть окно Источники данных , в меню данные выберите команду отобразить источники данных.

В окне Источники данных выберите Добавить новый источник данных, чтобы запустить Мастер настройки источника данных.

На странице Выбор типа источника данных выберите элемент База данных и нажмите Далее.

На странице Выбор модели базы данных выберите Набор данных и нажмите кнопку Далее.

На странице Выбор подключения к данным выполните одно из следующих действий.

Если подключение к учебной базе данных Northwind доступно в раскрывающемся списке, то выберите его.

Выберите Новое подключение для открытия диалогового окна Добавить/изменить подключение.

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

На странице Сохранение подключения в файле конфигурации приложения нажмите кнопку Далее.

Разверните узел Таблицы на странице Выбор объектов базы данных.

Выберите таблицы Customers и Orders и нажмите кнопку Готово.

NorthwindDataSet добавляется в проект, и таблицы Customers и Orders отображаются в окне Источники данных.

Создание первой формы (Form1)

Вы можете создать сетку с привязкой к данным (элемент управления DataGridView) с помощью перетаскивания узла Customers из окна Источники данных на форму.

Создание сетки с привязкой к данным на форме

Перетащите главный узел Customers из окна Источники данных на форму Form1.

На форме Form1 появляется DataGridView и панель инструментов (BindingNavigator) для перемещения по записям. В области компонентов появляется NorthwindDataSet, CustomersTableAdapter, BindingSource и BindingNavigator.

Создание второй формы

Создайте вторую форму для передачи данных.

В меню Проект выберите пункт Добавить форму Windows.

Оставьте имя по умолчанию Form2 и нажмите кнопку Добавить.

Перетащите главный узел Orders из окна Источники данных на форму Form2.

На форме Form2 появляется DataGridView и панель инструментов (BindingNavigator) для перемещения по записям. В области компонентов появляется NorthwindDataSet, CustomersTableAdapter, BindingSource и BindingNavigator.

Удалите OrdersBindingNavigator из области компонентов.

OrdersBindingNavigator исчезает из Form2.

Добавление запроса TableAdapter

Добавление запроса TableAdapter в форму Form2 для загрузки заказов выбранного клиента на Form1.

Дважды щелкните файл NorthwindDataSet.xsd в обозревателе решений.

Щелкните правой кнопкой мыши элемент OrdersTableAdapter и выберите пункт Добавить запрос.

Оставьте параметр по умолчанию Использовать инструкции SQL и нажмите кнопку Далее.

Оставьте параметр по умолчанию Инструкция SELECT, возвращающая строки и нажмите кнопку Далее.

Добавьте в запрос предложение WHERE, чтобы возвратить Orders на основании CustomerID . Запрос должен выглядеть примерно следующим образом:

Проверьте правильность синтаксиса параметров для своей базы данных. Например, в Microsoft Access предложение WHERE должно выглядеть следующим образом: WHERE CustomerID = ? .

Щелкните Далее.

Для поля заполнить Дататаблемесод имя введите FillByCustomerID .

Снимите флажок Вернуть таблицу данных (DataTable) и нажмите кнопку Далее.

Создание метода на Form2 для передачи данных

Щелкните правой кнопкой мыши Form2 и выберите пункт Просмотреть код, чтобы открыть Form2 в редакторе кода.

Добавьте следующий код в Form2 после метода Form2_Load :

Создание метода на Form1 для передачи данных и показа Form2

В Form1 щелкните правой кнопкой мыши сетку данных клиентов и выберите пункт Свойства.

В окне Свойства выберите События.

Дважды щелкните событие CellDoubleClick.

Откроется окно редактора кода.

Обновите определение метода в соответствии со следующим примером:

Запустите приложение

Нажмите клавишу F5 для запуска приложения.

Дважды щелкните запись клиента в форме Form1, чтобы открыть Form2 с заказами этого клиента.

Дальнейшие действия

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

Изменение набора данных для добавления или удаления объектов базы данных. Дополнительные сведения см. в разделе, посвященном созданию и настройке наборов данных.

Добавление функциональности для сохранения данных в базу данных. Дополнительные сведения см. в разделе Сохранение данных обратно в базу данных.

У меня есть две формы, одна главная форма и форма вариантов. Так скажем, например, что пользователь нажимает на мое меню в главной форме: Tools -> Options , это приведет к отображению моей формы параметров.

Итак, каков наилучший способ?

Form1 запускает Form2 для открытия. Form2 имеет перегруженный конструктор, который принимает вызывающую форму в качестве аргумента и предоставляет ссылку на члены Form2. Это решает проблему коммуникации. Например, я предоставил свойство Label как public в Form1, которое изменяется в Form2.

при таком подходе вы можете делать общение по-разному.

//ваш Форма form1

//Ваши Формы Form2

в комментарии принято отвечать, Нирадж Гулиа пишет:

это приводит к плотной связи форм Form1 и Form2, я думаю, вместо этого следует использовать пользовательские события для такого рода сценариев.

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

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

вот пример использования кода принятого ответа в качестве базовой линии:

форма form1.cs:

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

обратите внимание, что выражение (sender, e) => Lbl.Text = ((Form2)sender).Message автоматически преобразуется компилятором в метод, который выглядит примерно так (но определенно не совсем так):

на самом деле существует множество способов/синтаксисов для реализации и подписаться на обработчик события. Например, используя анонимный метод, как указано выше, вам действительно не нужно бросать ; вместо этого вы можете просто использовать frm локальная переменная напрямую: (sender, e) => Lbl.Text = frm.Message .

идя в другую сторону, вам не нужно использовать анонимный метод. На самом деле вы можете просто объявить обычный метод, как и созданный компилятором, который я показываю выше, а затем Подписаться на этот метод на событие: frm.Button1Click += frm_Message; (если вы, конечно, использовали имя frm_Message для метода, как и в моем примере выше).

независимо от того, как вы это сделаете, конечно, вам понадобится для Form2 фактически реализовать это Button1Click событие. Это очень просто.

формы Form2.cs:

в дополнение к событию, я также объявил свойство Message что подвергает Text свойство (и только the Text свойство, и только как read-only на самом деле) из txtMessage управление. Это позволяет подписчику события получить значение и сделать с ним все, что ему нужно.

обратите внимание, что все, что делает событие, это предупредить подписчика, что кнопка имеет на самом деле была нажата. Подписчик должен решить, как интерпретировать или реагировать на это событие (например, путем извлечения значения Message свойство и присвоение его чему-либо).

кроме того, вы можете фактически доставить текст вместе с самим событием, объявив новый EventArgs подкласс и использование этого для события вместо:

главное внимание во всех перечисленных выше вариаций, что не класс Form2 нужно знать что-нибудь о Form1 . Имея Form1 знаю, о Form2 неизбежно; в конце концов, это объект, который создаст новый Form2 экземпляр и использовать его. Но отношения могут быть асимметричными, с Form2 использовать любой объект, который нуждается в его функции. От разоблачения функциональность как событие (и, возможно, со свойством), она делает себя полезной, не ограничивая ее полезность только Form1 класса.

лучшим в этом случае было бы иметь некоторые OptionsService класс / интерфейс, доступный через IServiceProvider .

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

Properties-один вариант, shared static class-другой вариант, events-другой вариант.

вы можете попробовать AutoMapper. Сохраните параметры в отдельном классе, а затем используйте AutoMapper для переноса данных между классом и формой.

создайте класс и поместите все свои свойства внутри класса .. Создайте свойство в родительском классе и задайте его из дочерней формы (параметры)

вы можете иметь функцию в форме B, например:

и вы можете назвать это так:

MVC, MVP, MVVM -- небольшой перебор для кого-то, по общему признанию, говоря, что они хотят учебники. Это теории, которым посвящены целые курсы.

Как уже написал, передав объект по проще. Если рассматривать класс как объект (взаимозаменяемый в этом смысле) является новым, то вы можете потратить еще 2-4 недели на выяснение свойств и конструкторов и тому подобное.

в конце концов, это нажать.

существует множество способов выполнения связи между двумя формами. Некоторые из них вам уже объяснили. Я показываю вам другой путь.

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

  1. Использование Системы.Действие (здесь вы просто передаете функцию main forms в качестве параметра дочерней форме, как функцию обратного вызова)
  2. Метод OpenForms ( Вы напрямую вызываете одну из своих открытых форм)

Использование Системы.Действие

вы можете думать об этом как о функции обратного вызова, переданной дочерней форме.

Метод OpenForms

этот метод прост (2 строки). Но работает только с открытыми формами. Все, что вам нужно сделать, это добавить эти две строки, где вы хотите передать некоторые данные.

Я не могу найти хороший пример, похожий на то, как я это делаю (который на самом деле имеет фактический объект class+), но это охватывает другой способ сделать это:

форма-это класс, как и любой другой класс. Добавьте некоторые открытые переменные в класс формы и установите их, когда они нажимают кнопку, чтобы закрыть форму (технически они просто скрывают ее).

в вашем классе OptionsForm:

etc. Установите их, когда они нажмут кнопку "ОК".

Итак, в вашей основной форме, когда они нажимают кнопку" Параметры " - вы создаете свои параметры форма:

когда он выходит, вы собираете настройки параметров из открытых переменных в форме:

Ответы (5 шт):

На самом деле довольно просто. Экземпляр формы - это экземпляр класса, поэтому если нужен доступ снаружи к чему-то внутри формы, просто сделайте соответствующее public свойство (или поле, или метод - как вам больше нравится).

ну и самое главное, что бы экземпляры форм были в области видимости друг у друга.

ну а как обращаться, я думаю, понятно и без объяснений, правда?

из Form1:
Form2 frm = new Form2(); frm.label1.Text = "hello"; frm.Show();

Так как после закрытия формы Form2 она уничтожается, то я переопределяю метод для закрытия - OnClosing. Нужно зайти в конструктор формы Form2. В свойствах формы найти значок с молнией. В списке найти FormClosing и кликнуть дважды на пустое поле справаот него. В редакторе кода появится новый метод, в котором я пишу следующее:

Далее другой пример, который касается взаимодействия дочерней формы и родительской. Form1.cs:

Спасибо за статью! В Делфи и правда всё было достаточно просто, а тут пришлось немного повозиться и покопаться. И вот, наконец - заработало! Вообще, есть, конечно, и другие способы, но этот мне кажется наиболее простым и удобным. Про передачу параметров через события и делегаты я вообще молчу - это не для новичков. Так что данный вариант отлично подходит для тех, кому нужно просто, быстро и понятно.

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

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

*Операции выполняются внутри тела класса родительской формы к котрой присоединяется дочерняя. Производный класс userForm унаследованный от класса Form, должен быть предварительно объявлен(здесь это опущено).

Теперь, в зависимости от потребностей вы можете

    Доверить процесс удаления дочернего окна сборщику мусора. В данном случае оно будет удалено после закрытия главного окна (если программистом не предусмотрено другого)

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

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

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