Іноді буває потрібно звернутися до елементів якоїсь форми з іншого в процесі виконання програми. Наприклад, є форма Form1, з неї ми відкриваємо іншу Form2 і тепер, працюючи у формі Form2, потрібно звернутися, отримати доступ до елементів батьківської форми Form1. Я знайшов кілька способів, як це зробити.
1-й спосіб. Передача посилання на public змінну.
Namespace WindowsApplication1 ( public partial class Form1: Form ( public Form1() ( InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) ( Form2 frm = new Form2(); frm.but1 = this.button1; // передаємо посилання на кнопку у форму Form2 frm.ShowDialog(); ) ) )
У формі Form2 змінна, в яку передавали посилання, тепер відповідатиме кнопці button1 з форми Form1
Namespace WindowsApplication1 ( public partial class Form2: Form ( public Button but1; // ця змінна буде містити посилання на кнопку button1 з форми Form1 public Form2() ( InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) ( but) Text = "test"; // змінюємо текст на кнопці button1 форми Form1)))
2-й спосіб. Передача посилання на дочірню форму.
Суть приблизна та сама, те й у 1-му способі. При відкритті форми Form2 передаємо у ній посилання на елемент, який плануємо потім міняти.
Namespace WindowsApplication1 ( public partial class Form1: Form ( public Form1() ( InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) ( Form2 frm = new Form2(this.button1); //) передаємо посилання на кнопку у форму Form2 frm.ShowDialog(); ) ) )
Тепер у формі Form2 потрібно створити змінну, яка міститиме посилання на цю кнопку і через неї будемо звертатися до кнопки на Form1 (рядки 5,7,9 і 15).
Namespace WindowsApplication1 ( public partial class Form2: Form ( private Button but1; // ця змінна міститиме посилання на кнопку button1 з форми Form1 public Form2(Button but) // отримуємо посилання на кнопку в змінну but ( but1 = but; // тепер) but1 буде посиланням на кнопку button1 InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) (
3-й спосіб. Доступ до всієї батьківської форми.
Щоб здійснити це, потрібно внести зміни в декількох файлах, зате при цьому отримаємо доступ до всіх елементів батьківської форми і не потрібно передавати посилання на кожен елемент, як в 1-му способі.
Крок 1.У файлі Program.csстворюємо публічну змінну f1 (рядок 5).
Namespace WindowsApplication1 ( static class Program ( public static Form1 f1; // змінна, яка буде містити посилання на форму Form1 static void Main() ( Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1() ); ) ) )
Крок 2Відкриваємо Form1.Designer.csі в ньому елементи, до яких потрібно буде звернутися з іншої форми, міняємо privateна public. Наприклад, зробимо доступною для змін кнопку button1 на формі Form1.
Public System.Windows.Forms.Button button1; // замінили private на public
Крок 3. При створенні форми Form1 присвоюємо змінної f1 посилання на цю форму (рядок 7)
Namespace WindowsApplication1 ( public partial class Form1: Form ( public Form1() ( Program.f1 = this; // тепер f1 буде посиланням на форму Form1 InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) ( Form2 frm = new Form2(); frm.ShowDialog(); ) ) )
Крок 4Тепер з будь-якої форми або з будь-якого класу можна звернутися до елемента button1 що знаходиться на Form1 так: Program.f1.button1. Наприклад, нехай кнопка у Form2 поміняє текст кнопки на Form1:
Namespace WindowsApplication1 ( public partial class Form2: Form ( public Form2() ( InitializeComponent(); ) private void button1_Click(object sender, EventArgs e) ( Program.f1.button1.Text = "test"; // Змінюємо текст на кнопці форми Form1 ) ) )
Сьогодні я хочу розповісти про те, як створити проект Windows Forms на C++ в Visual Studio 2013 IDE. Справа в тому, що, починаючи з VS 2012, у списку проектів, які можна створити, прибрали пункт Додаток Windows Forms. Я зараз говорю про те, що на C++, створити такий проект на C# можна, вибравши відповідний пункт у розділі проектів, що створюються. Однак той факт, що такий проект не можна вибрати зі списку, не говорить про те, що його не можна створити. Саме про це я хочу розповісти в цій статті.
Перше, що потрібно зробити - запустити Visual Studio. Як тільки VS запустили, послідовно натискаємо Файл > Створити > Проект
Після цього у вікні буде запропоновано вибрати тип проекту. Нам необхідно вибрати у розділі Visual C++ підрозділ CLR та вибрати пункт Пустий проект CLR.
Коли проект буде створено, в браузері рішень клацаємо правою кнопкою миші за створеним проектом. У контекстному меню, що відкрилося, послідовно вибираємо Додати > Створити елемент і в меню, що відкрилося, в розділі UI вибираємо Форма Windows Forms
Коли форму буде додано, в браузері рішень вибираємо файл MyForm.cpp. Перед вами відкриється нова вкладка з єдиним рядком коду:
#include "MyForm.h"
У цей файл нам необхідно додати наступний код:
Using namespace System; using namespace System::Windows::Forms; void Main(array
Після цього у властивостях проекту. Вибираємо підрозділ Системарозділу Компонувальник і в рядку Підсистема з меню вибираємо Windows (/SUBSYSTEM:WINDOWS) і натискаємо Застосувати.
Не закриваючи вікно властивостей проекту, переходимо до підрозділу Додатково та у рядку Точка входупишемо Mainі після цього натискаємо клавішу ОК.
На цьому налаштування проекту закінчуються. Для редагування зовнішнього виглядуформи, необхідно перейти у вкладку MyForm.h [Конструктор], клацнувши двічі по файлу MyForm.h в браузері рішень.
Незважаючи на те, що моя думка про мікрософтівське Visual Studio як і раніше, іноді доводиться щось робити і на ньому. Якщо змиритися з тим, що пишемо ми при цьому, власне, не на C++, а на так званому C++/CLI, робота зі звичними візуальними компонентами буде не дуже відрізнятися від тих же Борландівських середовищ. А ось здатне, в порівнянні з Builder"ом, створити проблеми. Розглянемо 3 типові ситуації роботи з додатком, що містить більше однієї форми.
Приклад конструювання та програмного виклику форми
Цей код можна виконати, наприклад, натисканням кнопки в головній формі 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
Потім ініціалізуємо дані щодо події Load головної форми:
FormCount = 0; F2 = gcnew array
Потім реалізуємо код для створення чергової форми
If (FormCount
та її видалення:
If (FormCount) ( delete F2; FormCount--; )
Якщо хочемо створювати дочірні форми не окремо, а всередині батьківської форми, то властивостях Form1 треба зазначити, що вона " предок " (встановити властивість IsMdiParent = true), а перед показом дочірньої форми оператором F2->Show() помітити її як нащадка Form1:
F2->MdiParent = this;
Викликати з дочірньої форми метод батьківської форми
Нам навряд чи обійтися без залучення файлів. cpp, що непогано - писати код у файлах.
Розпишемо процес за кроками.
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-файлі залишаємо лише його оголошення.
Останнє оновлення: 31.10.2015
Щоб додати ще одну форму до проекту, натисніть на ім'я проекту у вікні Solution Explorer (Обозреватель рішень) правою кнопкою миші і оберемо Add(Додати)->Windows Form...
Дамо новій формі якесь ім'я, наприклад, Form2.cs:
Отже, у нас у проект було додано другу форму. Тепер спробуємо здійснити взаємодію між двома формами. Припустимо, перша форма натискання на кнопку викликатиме другу форму. По-перше, додамо на першу форму Form1 кнопку та подвійним клацанням по кнопці перейдемо у файл коду. Отже, ми потрапимо в обробник події натискання кнопки, який створюється за замовчуванням після подвійного клацання за кнопкою:
Private void button1_Click(object sender, EventArgs e) ( )
Тепер додамо до нього код виклику другої форми. У нас друга форма називається Form2, тому спочатку ми створюємо об'єкт даного класу, а потім для відображення на екрані викликаємо метод Show:
Private void button1_Click(object sender, EventArgs e) ( Form2 newForm = new Form2(); newForm.Show(); )
Тепер зробимо навпаки – щоб друга форма вплинула на першу. Поки що друга форма не знає про існування першої. Щоб це виправити, треба другій формі передати відомості про першу форму. Для цього скористаємося передачею посилання на форму у конструкторі.
Отже, перейдемо до другої форми і перейдемо до її коду - натиснемо правою кнопкою миші на форму і виберемо View Code (Перегляд коду). Поки що він порожній і містить лише конструктор. Оскільки C# підтримує перевантаження методів, ми можемо створити кілька методів і конструкторів з різними параметрами й у залежність від ситуації викликати одне із них. Отже, змінимо файл коду другої форми на наступний:
Using System; використовуючи System.Collections.Generic; using System.ComponentModel; using System.Data; використовуючи System.Drawing; using System.Linq; using System.Text; використовуючи System.Threading.Tasks; using System.Windows.Forms; namespace HelloApp ( public partial class Form2: Form ( public Form2() ( InitializeComponent(); ) public Form2(Form1 f) ( InitializeComponent(); f.BackColor = Color.Yellow; ) ) )
Фактично ми додали тут новий конструктор public Form2(Form1 f) , в якому ми отримуємо першу форму і встановлюємо її фон у жовтий колір. Тепер перейдемо до коду першої форми, де ми викликали другу форму та змінимо його на наступний:
Private void button1_Click(object sender, EventArgs e) ( Form2 newForm = new Form2(this); newForm.Show(); )
Оскільки в даному випадкуКлючове слово this представляє посилання на поточний об'єкт - об'єкт Form1, то при створенні другої форми вона отримуватиме її (посилання) і через неї керуватиме першою формою.
Тепер після натискання на кнопку у нас буде створено другу форму, яка відразу змінить колір першої форми.
Ми можемо також створювати об'єкти та поточної форми:
Private void button1_Click(object sender, EventArgs e) ( Form1 newForm1 = new Form1(); newForm1.Show(); Form2 newForm2 = new Form2(newForm1); newForm2.Show(); )
При роботі з декількома формами треба враховувати, що одна з них є головною – яка запускається першою у файлі Program.cs. Якщо в нас одночасно відкрита купа форм, то при закритті головною закривається вся програма і разом з ним всі інші форми.
Питання, що розглядається в цій статті, швидше відноситься до теми побудови архітектури програми, а не конкретно проблеми, що розглядається. Передавати дані від однієї форми в іншу зовсім не важко. Для цього достатньо контрол, дані якого ми хочемо отримати, зробити відкритим, тобто помітити модифікатором public. Також, можливий інший варіант. Наприклад, у першій формі ми створюємо об'єкт другої форми, передавши в конструктор посилання на себе, тобто, передавши з першої форми до другого посилання на першу
SecondForm secondForm = New SecondForm (this );
Звичайно, перед цим слід подбати про створення навантаження конструктора другої форми.
І такий спосіб є досить поширеним. Проте, зі своєю простотою, він несе багато потенційних проблем, головна з яких – порушення принципу інкапсуляції Одним словом, друга форма нічого не повинна знати про існування першої і, тим більше, не повинна мати можливість впливати на неї.
Вирішення цієї проблеми досить просте. Звернемося безпосередньо до коду. У дизайнері створюємо головну форму (вона запускатиметься при запуску програми). Помістимо один TextBox, Lableі Button.
Після натискання на кнопці відкриватиметься друга форма і текст із текстового поля головної форми передається в текстове поле другої форми. Спочатку друга форма виглядає так:
Аналогічно першою вона має ті ж контролі. Більше нам і не треба. Точка входу в програму запускає головну форму:
Using System; використовуючи System.Collections.Generic; using System.Linq; using System.Windows.Forms; namespace From1FormTo2 ( static class Program ( / / The main entry point for application. static void Main() ( Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); ) ) )
Код головної форми виглядає так:
Using System; використовуючи System.Collections.Generic; using System.ComponentModel; using System.Data; використовуючи System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace From1FormTo2 ( public partial class MainForm: Form ( //друга форма SecondForm secondForm; //конструктор public MainForm() ( InitializeComponent(); ) //обробник події передачі даних //від головної форми до другої private void btn_mainForm_Click(object sender, EventArgs e) ( secondForm = new SecondForm(tb_mainForm.Text.Trim()); secondForm.ShowDialog(); if (secondForm.DialogResult == DialogResult.OK) tb_mainForm.Text = secondForm.ReturnData(); )
Відповідно, не забудьте підключити кнопку на подію Click. Тут, у класі головної форми, є поле SecondForm secondForm, Що представляє об'єкт-другу форму. При натисканні на кнопці «Передати» створюється друга форма (викликається перевантажений конструктор, його ми ще створимо) і запускається методом ShowDialog(). У разі нам підходить саме цей метод. До того ж, після цього ми обов'язково перевіряємо, чи не закрили другу форму, а виконали клік по її кнопці. Якщо, на другій формі був виконаний клік по кнопці, то перша форма повинна прийняти дані від другої. Це відбувається шляхом виклику методу ReturnData()у другої форми.
Тепер найцікавіше – код другої форми:
Using System; використовуючи System.Collections.Generic; using System.ComponentModel; using System.Data; використовуючи System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace From1FormTo2 ( public partial class SecondForm: Form ( // перевантажений конструктор public SecondForm(string data) ( InitializeComponent(); tb_secondForm.Text = data; ) //обробник події передачі //від другої форми до головної private void btn_secondForm_Click (object e) ( this.DialogResult = DialogResult.OK; ) //відкритий метод для доступу до //текстового поля даної форми public string ReturnData() ( return (tb_secondForm.Text.Trim()); ) )
Як бачимо, є єдине навантаження конструктора, який приймає тип string. Пам'ятаємо, що ми намагаємось передавати текст із TextBox. У конструкторі відбувається планова ініціалізація компонент та встановлення тексту текстового поля в передане значення від першої форми. Далі, передплативши подію Clickдля кнопки другої форми, ми створили обробник btn_secondForm_Click, що імітує роботу кнопки «Ok» будь-якого діалогового вікна. Таким чином, натискаючи на кнопці «Відправити» (другої форми), ми виконуємо умову
(secondForm .DialogResult == DialogResult .OK)
Першої форми, через що, викликаючи метод secondForm .ReturnData(), ми встановлюємо тектове поле першої форми значення тектового поля другої форми.
Робота даного методу, на мою думку, вже не вимагає пояснень. Він просто повертає текст із єдиного текстового поля, при цьому залишаючи його приватним.
У результаті ми передали дані у другу форму з першої і з другої в першу не порушуючи принципи інкапсуляції.
Спробуйте внести текст "ааа" у текстове поле першої форми та виконати натискання на кнопці. Ви побачите в другій формі, що відкрилася, цей текст у її текстовому полі. Спробуйте змінити текст на "ааа ппп" і натиснути кнопку. Ви побачите, як після закриття другої форми цей текст з'явиться у текстовому полі головної форми.
Тепер, я думаю, ви будете правильно здійснювати передачі даних між формами. У наступній статті ми поговоримо, як у програмах ASP.NET.