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

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

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

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

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

Form ^ form2 = gcnew Form();
Button^ button2 = gcnew Button();
button2->Text = L"OK";
button2->Location = Point(10,10);
form2->Text = L"Моё окно";
form2->HelpButton = true;
form2->FormBorderStyle = System::Windows::Forms::FormBorderStyle::FixedDialog;
form2->StartPosition = FormStartPosition::CenterScreen;
form2->Controls->Add( button2 );
form2->ShowDialog();

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

button2->Click += gcnew System::EventHandler(this, &Form1::button2_Click);

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

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

private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
 MessageBox::Show("Here");
}

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

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

Добавим оператор

#include "Form2.h"

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

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

Form2 ^ F2;

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

F2=gcnew Form2();
F2->Show();

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

delete F2;

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

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

static const int MAX_FORMS = 100; //Максимальное количество форм
int FormCount; //Счётчик форм
array <Tabulator::Form2 ^> ^F2; //Указатель на массив форм

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

FormCount=0; 
F2 = gcnew array<Tabulator::Form2 ^>(MAX_FORMS);

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

if (FormCount<MAX_FORMS) {
  F2[FormCount++]=gcnew Form2();
  F2[FormCount-1]->Show();
 }
 else MessageBox::Show("Слишком много форм!");

и её удаления:

if (FormCount) { delete F2[FormCount-1]; FormCount--; }

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

F2[FormCount-1]->MdiParent = this;

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

Нам едва ли обойтись без привлечения файлов .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.

3) Объявить открытый метод Set в Form1.h для того, чтобы можно было изменить текст label1 (код можно написать в конце файла, после #pragma endregion):

public: void Set(String^ text) {
 label1->Text = text;
}

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

#include "Form1.h"

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

Form2(Form1^ parent)     {
 InitializeComponent();		
 parentForm = parent;
}
//ниже сразу ниже можно прописать ссылку: private: Form1^ parentForm;

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

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
 parentForm->Set("hello from form2");
 parentForm->Show();
 this->Hide();
}

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

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

#include "StdAfx.h"
#include "Form1.h"
#include "Form2.h"
namespace ChildToParent {
 System::Void Form1::button1_Click(System::Object^  sender, System::EventArgs^  e) {
  Form2^ f2 = gcnew Form2(this);
  f2->Show();
  this->Hide();
 }
}

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

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e);

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

 Пример ChildToParent, проект Visual Studio 2010 в архиве .zip (40 Кб)

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

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

Простой пример "многооконного редактора" есть в этой заметке блога.

 Пример TwoFormsSample, проект Visual Studio 2010 в архиве .zip (36 Кб)

См. также: редактор текста с отдельными окнами для файлов, простое MDI-приложение.

07.01.2014, 00:05 [55141 просмотр]


теги: программирование c++/cli

К этой статье пока нет комментариев, Ваш будет первым