Форум программистов, компьютерный форум, киберфорум
C++/CLI Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.87/187: Рейтинг темы: голосов - 187, средняя оценка - 4.87
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14

Ответы на 7 самых частых вопросов по Windows Forms, C++/CLI Edition

24.09.2016, 14:02. Показов 37328. Ответов 7
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Ответы на 7 самых частых вопросов по Windows Forms
C++/CLI Edition


Эта статья является адаптированной для C++/CLI статьёй от HIMenа.
Начинающие программисты часто испытывают трудности при переводе примеров кода с C# на C++/CLI.
Данная адаптация призвана облегчить этот перевод.
Также к некоторым из вопросов приложен проект приложения. Все проекты созданы в Visual Studio 2008.

Выражаю благодарность HIMen за качественную статью.
Если статья показалась вам полезной, не забудьте поблагодарить автора оригинальной статьи, нажав "+1 Спасибо" или оставив отзыв.
Если у вас есть вопросы, замечания или предложения по статье, просьба обращаться в тему-обсуждение.

Содержание: #
Особенности работы с двумя формами в C++/CLI

Многие примеры показывают, как работать с двумя формами в одном проекте.
Для определённости назовём их Form1 и Form2, располагаться они будут в пространстве имён CppCliWinForms.
Стоит обратить внимание на то, что пространство имён проекта явно не определено в каждом файле с исходным кодом, поэтому его либо нужно явно определить, написав в начале кода
C++
1
using namespace CppCliWinForms;
Либо указывать полное имя для формы из другого файла. Например, в коде Form1, форму Form2 можно вызывать так
C++
1
CppCliWinForms::Form2^ f = gcnew CppCliWinForms::Form2();
В статье для краткости выбран первый вариант.
Не забывайте, что одна форма по-умолчанию не видна другой, пока вы явно не укажете это в коде
C++
1
#include "Form2.h"
8
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
24.09.2016, 14:02
Ответы с готовыми решениями:

Ответы на 7 самых частых вопросов по Windows Forms, C++/CLI Edition - свой способ передачи данных между формами
Способ с использованием макросов. Средней сложности в реализации и понимании, не знаю, нарушает ли ООП, передача данных возможна в обе...

Ответы на 7 самых частых вопросов по WinForms
Ответы на 7 самых частых вопроса по WinForms 1. Как создать вторую форму 2. Как передать данные из одной формы в другую 2.1...

Непонятен пункт 2.5 из "Ответы на 7 самых частых вопросов по WinForms"
Вопрос по пункту 2.5 из "Ответы на 7 самых частых вопроса по WinForms". Вот код: // в форме 1 Form2 f = new Form2(); f.Owner =...

7
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:03  [ТС]
1. Как создать вторую форму? #

Любая форма представляет из себя класс, унаследованный от Form.
Экземпляр главной формы создается в файле <имя формы>.cpp по-умолчанию.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Form1.h" 
using namespace System;
using namespace System::Windows::Forms;
using namespace CppCliWinForms;  // имя вашего проекта
 
[STAThread]
int main(array<System::String^>^ args)
{
    Application::EnableVisualStyles();
    Application::SetCompatibleTextRenderingDefault(false);
    Application::Run(gcnew Form1());  // <- вот тут
    return 0;
}
Создать вторую форму в Visual Studio можно в "Обозревателе решений" (Solution Explorer), кликнув правой кнопкой по имени проекта и выбрав в меню пункт "Добавить" (Add). В появившемся диалоговом окне среди шаблонов выберите форму.
Чтобы отобразить вторую форму, нужно создать экземпляр этого класса (Form2), например, в обработчике события главной формы
C++
1
2
3
4
5
private: void button1_Click(Object^ sender, EventArgs^ e) {
    Form2^ f = gcnew Form2(); // создаем
    f->ShowDialog(); // показываем
    f->Show() // или так
}
При этом ShowDialog() блокирует главную форму, т.е. управление вернется в нее, только по закрытию второй формы, а Show() просто отображает вторую форму, т.е. будут доступны обе формы.
3
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:03  [ТС]
2. Как передать данные из одной формы в другую? #

Часто возникает необходимость передать данные из одной формы в другую; есть 7 способов, у каждого из которых свои недостатки и достоинства.

2.1. Изменение модификатора доступа #

В Form2 установить модификатор доступа для контрола/поля public
В любом месте Form1
C++
1
2
3
Form2^ f = gcnew Form2();
f->ShowDialog();
textBox1->Text = f->textBox1->Text;
+ Самый быстрый в реализации и удобный способ
- Противоречит всем основам ООП
- Возможна передача только из более поздней формы в более раннюю
- Форма f показывается только с использованием ShowDialog(), т.е. в первую форму управление вернется только по закрытию второй. Избежать этого можно, сохранив ссылку на вторую форму в поле первой формы

Проект: WindowsForms_2_1.zip

2.2. Использование открытого свойства/метода #

В классе Form2 определяем свойство (или метод)
C++
1
2
3
4
5
public: property String^ Data {
    String^ get() {
        return textBox1->Text;
    }
}
В любом месте Form1
C++
1
2
3
Form2^ f = gcnew Form2();
f->ShowDialog();
textBox1->Text = f->Data;
+ Противоречит не всем основам ООП
- Минусы те же

Проект: WindowsForms_2_2.zip

2.3. Передача данных в конструктор #

Изменяем конструктор Form2
C++
1
2
3
4
5
6
public: Form2(String^ data) {
    InitializeComponent();
    // обрабатываем данные
    // или записываем их в поле
    textBox1->Text = data;
}
А создаем форму в любом месте Form1 так:
C++
1
2
3
Form2^ f = gcnew Form2(textBox1->Text);
f->ShowDialog();
// или f->Show();
+ Простой в реализации способ
+ Не нарушает ООП
- Возможна передача только из более ранней формы в более позднюю

Проект: WindowsForms_2_3.zip

2.4. Передача ссылки в конструктор #

Изменяем конструктор Form2
C++
1
2
3
4
5
6
public: Form2(Form1^ f1) {
    InitializeComponent();    
    // обрабатываем данные
    // или записываем их в поле
    textBox1->Text = f1->textBox1->Text;
}
А создаем форму в любом месте Form1 так, т.е. передаем ей ссылку на первую форму
C++
1
2
3
Form2^ f = gcnew Form2(this);
f->ShowDialog();
// или f->Show();
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
- Нарушает ООП

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


Проект: WindowsForms_2_4.zip

2.5. Используем свойство 'владелец' #

При создании второй формы устанавливаем владельца
C++
1
2
3
Form2^ f = gcnew Form2();
f->Owner = this;
f->ShowDialog();
Во второй форме определяем владельца
C++
1
2
3
4
5
Form1^ main = dynamic_cast<Form1^>(Owner);
if(main != nullptr) {
    String^ s = main->textBox1->Text;
    main->textBox1->Text = L"OK";
}
+ Доступ ко всем открытым полям/функциям первой формы
+ Передача данных возможна в обе стороны
+ Не нарушает ООП

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


Проект: WindowsForms_2_5.zip

2.6. Используем отдельный класс #

Создаем отдельный класс со статическим свойством и в основном пространстве имёню Удобнее всего будет разметить его в отдельном заголовочном файле, ссылку на который поместить в stdafx.h
C++
1
2
3
4
ref class Data
{
    public: static property String^ Value;
};
Его открытые свойства/методы доступны из любой формы.
C++
1
Data::Value = L"111";
+ Самый удобный способ, когда данные активно используются несколькими формами.

Проект: WindowsForms_2_6.zip

2.7. Использование функций обратного вызова #

2.7.1 Передача метода в конструктор

Создаем в основном пространстве имён делегат
C++
1
public delegate void MyDelegate(String^ data);
В Form1 создаем метод, который будет обрабатывать принятые данные
C++
1
2
3
void GetData(String^ param) {
    // обработка
}
Создаем вторую форму так:
C++
1
2
Form2^ f = gcnew Form2(gcnew MyDelegate(this, &Form1::GetData));
f->ShowDialog();
При этом изменяем конструктор второй формы, чтобы он принимал делегат
C++
1
2
3
4
5
6
public: Form2(MyDelegate^ sender) {
    InitializeComponent();
    _d = sender;
}
 
private: MyDelegate^ _d;
И в любой момент отправляем данные
C++
1
_d(textBox1->Text);
Проект: WindowsForms_2_7_1.zip

2.7.2. Создание отдельного класса с делегатом

Создаем в основном пространстве имён отдельный класс
C++
1
2
3
4
5
6
public ref class Data
{
public:
    delegate void MyDelegate(String^ data);
    static MyDelegate^ PseudoHandler;
};
В первой форме добавляем обработчик
C++
1
2
3
void Function(String^ param) {
    MessageBox::Show(param);
}
и инициализируем PseudoHandler
C++
1
Data::PseudoHandler = gcnew Data::MyDelegate(this, &Form1::Function);
Вторую форму создаем обычным способом и вызываем из нее
C++
1
Data::PseudoHandler(textBox1->Text);
+ Наиболее гибкий способ передачи данных
- Сложен в реализации и понимании

Проект: WindowsForms_2_7_2.zip
6
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:04  [ТС]
3. Как получить доступ к контролу из другого потока? #

.NET не позволяет обращаться к контролам напрямую из других потоков.

3.1. Простой и неправильный способ

Отменяем проверку, из какого потока используется контрол
C++
1
System::Windows::Forms::Control::CheckForIllegalCrossThreadCalls = false;
Для одного раза может и сработать, но делать так крайне не рекомендуется.

3.2. Использование методов Invoke/BeginInvoke

Эти методы выполняют указанные делегаты в том потоке, в котором контрол был создан.
Invoke вызывает делегат синхронно, BeginInvoke - асинхронно.
Чтобы определить, требуется ли Invoke используйте свойство InvokeRequired.
Например, объявляем делегат
C++
1
delegate void Del(String^ text);
внутри Form1 создаём метод, выполняющий предполагаемое действие
C++
1
2
3
void DelFunc(String^ s) {
    textBox1->Text = s;
}
и вызываем Invoke
C++
1
textBox1->Invoke(gcnew Del(this, &Form1::DelFunc), L"newText");
Вместо объявления новых делегатов можно использовать готовые, Action или Func
Пример готового, потокобезопасного метода
C++
1
2
3
4
5
6
void SetTextSafe(String^ newText) {
    if (textBox1->InvokeRequired)
        textBox1->Invoke(gcnew Action<String^>(this, &Form1::DelFunc), newText);
    else
        textBox1->Text = newText;
}
5
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:05  [ТС]
4. Как динамически добавить/удалить контрол? #

4.1. Добавление

Пример динамического создания кнопки:
C++
1
2
3
4
5
6
7
8
9
10
11
Button^ button1 = gcnew Button(); // создаем контрол
// устанавливаем необходимые свойства
button1->Location = System::Drawing::Point(101, 50);
button1->Name = L"button1";
button1->Size = System::Drawing::Size(75, 23);
button1->TabIndex = 0;
button1->Text = L"button1";
button1->UseVisualStyleBackColor = true;
// button1_Click - функция обработчик события нажатия на кнопку
button1->Click += gcnew EventHandler(this, &Form1::button1_Click);
Controls->Add(button1); // добавляем на форму
Если непонятно как создать другие контролы - откройте функцию InitializeComponent, которая находится в конструкторе вашей формы. Это функция - код генерируемый дизайнером, посмотрите, как дизайнер создает тот или иной компонент и скопируйте код.

4.2. Удаление
C++
1
2
Controls->Remove(button1);
delete button1;
4
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:05  [ТС]
5. Как создать массив контролов? #

Точно также, как обычный массив
C++
1
2
3
4
5
6
7
8
9
10
array<TextBox^>^ tb = gcnew array<TextBox^>(10);
for (int i = 0; i < tb->Length; i++) {
    tb[i] = gcnew TextBox();
    tb[i]->Location = System::Drawing::Point(101, 50 + i * 30);
    tb[i]->Name = L"textBox" + i.ToString();
    tb[i]->Size = System::Drawing::Size(75, 23);
    tb[i]->TabIndex = i;
    tb[i]->Text = L"textBox" + i.ToString();                
    Controls->Add(tb[i]);
}
Теперь получить доступ к конкретному текстбоксу можно по индексу:
C++
1
tb[2]->Text = L"newText";
4
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:05  [ТС]
6. Как получить доступ к контролу по имени? #

C++
1
2
3
TextBox^ tb = dynamic_cast<TextBox^>(Controls[L"textBox1"]);
if (tb != nullptr)
    tb->Text = L"newText";
3
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9670 / 4823 / 762
Регистрация: 17.04.2012
Сообщений: 9,661
Записей в блоге: 14
24.09.2016, 14:05  [ТС]
7. Как пройтись по всем однотипным контролам? #

C++
1
2
3
4
5
6
// пример обхода всех TextBox'ов
for each (Control^ control in Controls) {
    TextBox^ tb = dynamic_cast<TextBox^>(control);
    if (tb != nullptr)
        tb->Text = L"Text";
}
2
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
24.09.2016, 14:05
Помогаю со студенческими работами здесь

C++/CLI Windows Forms
Помогите пожалуйста, 1 и 2 кнопку сделала, а вот с 3 и 4 проблемы возникли(( Создать проект, содержащий 4 кнопки со следующими...

Литература по C++/CLI Windows Forms
Народ, подскажите путевый учебник или самоучитель по Windows Forms на C++.

Литература по C++/CLI Windows Forms
Хочу начать учить Windows Forms, но в интернете никакой литературы найти не могу! Подскажите хорошие книги.

Теория по C++/CLI Windows Forms
Доброе утро:) На носу сдача курсовой, назрели некоторые вопросы по теории (определениям) winforms. 1)public ref class Form1 :...

Создание приложения Windows Forms на C++/CLI в Windows 8
Добрый день! Нужно создать windows приложение на Си++, стоит 8, на 2013 много заморочек с созданием windows forms. Не подскажите, можно ли...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
8
Закрытая тема Создать тему
Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru