Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Разработка Windows Forms > Как управлять компонентами формы из другого модуля


Автор: valeriyzf 11.2.2010, 03:14
Microsoft Visual C++ 2008 (2005)

В проекте 1 форма и несколько модулей. Но управлять компонентами формы из других модулей не получается.

Например: 
Создаем новый проект "Test1" с пустой формой "Form1". 
На форму помещаем кнопку "Button1". 
В заголовочном файле "Form1.h" объявляем процедуру:

Код

void Change_Button_Text();

Вызываем эту процедуру нажатием кнопки "Button1".

А теперь, внимание - задача!
Описание самой процедуры

Код

void Test1::Change_Button_Text() 
{
   // здесь ожидается ваше решение
   Form1::lable1->Text = "Hello Forum!" // - не работает!
   Form1 ^fr1 = gcnew Form1(); fr1->label1->Text = "Hello Forum!" // - не работает!
}

делаем не в этом же файле "Form1.h", а в главном модуле "Test1.cpp".
Задача процедуры - изменить текст кнопки на другой, например "Hello forum!".

Что должно получиться: Запускаем проект, нажимаем кнопку, и ее текст меняется на указанный в коде.

Здесь можно скачать исходничек примера:
http://www.cyberforum.ru/visual-cpp/thread93157.html

Спасибо!

Автор: 586 11.2.2010, 05:56
В Form1.h найди строку:
Код
private: System::Windows::Forms::Label^  label1;

и поменяй её на эту:
Код
public: System::Windows::Forms::Label^  label1;

и тогда можно будет писать так:
Код
Form1 ^fr1 = gcnew Form1();
fr1->label1->Text = "Hello Forum!";

Если нужно изменить текст у существующей формы, то можно написать так:
Код
    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
                 for (int i = 0; i < Application::OpenForms->Count; ++i){
                     if (Application::OpenForms[i]->Name == "Form1"){
                         Application::OpenForms[i]->Controls["label1"]->Text = "Hello Forum!";
                    }
                 }
             }

Автор: valeriyzf 11.2.2010, 20:23
586, Вы просто Гений!

Спасибо огромное!. Я запостил эту тему на 5-ти или 6-ти различных форумах, включая 3 англоязычных.

На одном из форумов решение было найдено, но намного более сложное:

http://www.daniweb.com/forums/thread259425.html

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

Код

                 Graphics^ im = Application::OpenForms[0]->CreateGraphics();

                 im->DrawLine(pen,10,10,200,200);


Процедуры обработки графики довольно громоздкие (хотя и простые). Соответственно хотелось их разбить на разные модули.
Беру этот форум и Вас лично на заметку. Еще раз Спасибо!  smile 

Автор: valeriyzf 14.2.2010, 21:44
Вынужден опять поднять тему.

Данный метод не получается применить к компонентам формы типа ListBox
Код

Application::OpenForms["Form1"]->Controls["ListBox1"]->

далее в выпадающем списке нету свойств и методов ListBox, например ListBox1->Items

Метод
Код

  Form1 ^fr1 = gcnew Form1();
  fr1->ListBox1->Items->Clear();

НЕ выдает ошибки, но и ничего не делает с компонентом ListBox1 (private на public в шапке Form1.h заменить не забыл).

Заранее спасибо!

Автор: KelTron 15.2.2010, 14:30
Цитата(valeriyzf @  14.2.2010,  21:44 Найти цитируемый пост)
далее в выпадающем списке нету

((ListBox)Application::OpenForms["Form1"]->Controls["ListBox1"])->Items

Цитата(valeriyzf @  14.2.2010,  21:44 Найти цитируемый пост)
ничего не делает с 

Если Change_Button_Text() находится внутри класса формы, то
Код

void Test1::Change_Button_Text() 
{
    this.ListBox1->Items->Clear();
}

Иначе передаём как параметр:
Код

void Test1::Change_Button_Text(Form form) 
{
    form.ListBox1->Items->Clear();
}

Автор: valeriyzf 15.2.2010, 21:05
KelTron, большое спасибо за ответ.
Все выглядит очень заманчиво.
Но:
Пример №1:
Код

((ListBox)Application::OpenForms["Form1"]->Controls["ListBox1"]).Items->Clear();

После последней точки действительно появляются методы ListBox. 
Но компилятор выдает ошибку:
error C2440: приведение типов: невозможно преобразовать 'System::Windows::Forms::Control ^' в 'System::Windows::Forms::ListBox'
Для преобразования требуется конструктор или оператор пользовательского преобразования, который не может использоваться const_cast или reinterpret_cast


Далее, пример №2:
Код

void Test1::Change_Button_Text() 
{
    this.ListBox1->Items->Clear();
}

Здесь работает безупречно, но с этим проблем и не было. Внутри класса формы все работает.
Далее, пример №3:
Код

void Test1::Change_Button_Text(Form form) 
{
    form.ListBox1->Items->Clear();
}

Если в качестве параметра функции поставить просто тип (Form form), то у параметра form не будет компонента ListBox1. Т.е. нужен параметр (Form1 form)
Я сделал вот так (в отдельном модуле Unit1.cpp):
Код

#include "Form1.h"
using namespace Test1; //сюда входит описание класса Form1

void Test1::Change_Button_Text() 
{
    Form1 form;
    form.ListBox1->Items->Clear();
}

Все запускается и компилируется без ошибок. Программа выполняется, но ничего с компонентом "ListBox1" не происходит :(

Автор: KelTron 16.2.2010, 10:15
Цитата(valeriyzf @  15.2.2010,  21:05 Найти цитируемый пост)
Но компилятор выдает ошибку:

Блин, невозможно привыкнуть к этому... в C++/CLR нужно ListBox^

Цитата(valeriyzf @  15.2.2010,  21:05 Найти цитируемый пост)
оставить просто тип (Form form), то у параметра form не будет компонента ListBox1

Ну это очевидно, я лишь показал принцип.

Цитата(valeriyzf @  15.2.2010,  21:05 Найти цитируемый пост)
 но ничего с компонентом "ListBox1" не происходит

Конечно, ты создаёшь новую форму, никак не связанную с той, что открыта - причём каким то странным способом - как структуру, что то там изменяешь и форма уничтожается.

Ты лучше покажи как и где ты создаёшь класс Test. Думаю лучшим решением будет передать форму в конструктор как параметр.

Автор: valeriyzf 16.2.2010, 21:31
Пример №1:
Код

((ListBox^)Application::OpenForms["Form1"]->Controls["ListBox_Type"])->Items->Clear();//РАБОТАЕТ!

Работает отлично!
Спасибо! Спасибо! Спасибо! 

Что мне нравится на этом форуме, так это что здесь не задают лишних вопросов, и не пересылают тебя на другие темы.
А сразу: Вопрос -> Ответ.
Еще раз спасибо!
----------------------------------------

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

Пример №3:
Логику работы я понял: нужно вызывать процедуру класса, передавая при этом саму форму, как параметр. Но появляется одна загвоздка.
Например:
Создаю чистый проект "Form_Control_forum" с чистой формой Form1 //не могу приатачить, весит в зипе >1.7Mb
На форму добавляю button1 и listBox1.
Далее через мастер добавляю класс Test (Test.h, Test.cpp).
В шапке класса пишу следующее:
Код

#pragma once
// если не добавить следующие две строчки, то тип Form1 не будет понятен конструктору
#include "Form1.h"
using namespace Form_Control_forum;
//--------------------------------------------------------------------
ref class Test // объявляем класс
{
public:
    void List_Box_Clear(Form1 form); // процедура, которая должна вызываться кнопкой button1 и очищать listBox1
};
//--------------------------------------------------------------------
void Test::List_Box_Clear(Form1 form) // описание этой процедуры
{
    form.listBox1->Items->Clear();
}

В процедуру обработки события кнопки button1 добавляю:
Код

    private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e)
             {
                Test::List_Box_Clear(this);
             }


Но чтобы эта процедура была здесь читаема конструктором, мне нужно добавить в шапку Form1.h следующее:
Код

#include "Test.h"

А так получается перекрёстное добавление шапок: Form1.h -> в Test.h, и наоборот: Test.h -> в Form1.h
Что в свою очередь пресекается компилятором...

Автор: KelTron 17.2.2010, 15:09
Это конечно всё изврат, но так работает..)  smile 
Файл Test.h заменяем на
Код

#pragma once

namespace Form_Control_forum {

    ref class Form1;

    ref class Test
    {
    public:
        static void List_Box_Clear(Form1^ form);
    };

}

Файл Test.cpp заменяем на
Код

#include "StdAfx.h"
#include "Test.h"
#include "Form1.h"

using namespace Form_Control_forum;

void Test::List_Box_Clear(Form1^ form)
{
    form->listBox1->Items->Clear();
}

Автор: valeriyzf 18.2.2010, 01:05
Да, скорее всего просто логика построения приложений на Visual C++ 2008 изначально на такую структуру не рассчитана.
Пользователя стараются направить на создание программ с определенной стандартной архитектурой.

Ok, еще раз Спасибо! smile
Ваши советы очень сильно выручили smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)