Visual C++: табличные компоненты и работа с ними
В этой статье мы рассмотрим на простых примерах основные приёмы работы с табличными компонентами .NET, среда для выполнения кода - Visual C++ (Studio) Express 2010 или выше.
Пример 1. Пишем приложение TableEditor1
для редактирования таблицы и сохранения её в формате XML.
На форму добавим компоненту dataGridView1
, а объекты DataTable
и DataSet
создадим программно.
Для этого опишем глобально в классе формы следующие величины:
private: String ^ BaseName; private: DataTable ^ Table; private: DataSet ^ Set;
На загрузку формы реализуем такой код (обработчик события Load
):
BaseName = "table.xml"; Table = gcnew DataTable(); Set = gcnew DataSet(); if (IO::File::Exists(BaseName) == false) { dataGridView1->DataSource = Table; Table->Columns->Add ("Имена"); Table->Columns->Add("Номера телефонов"); Set->Tables->Add(Table); } else { Set->ReadXml (BaseName); String ^ StringXML = Set->GetXml(); dataGridView1->DataMember = "Название таблицы"; dataGridView1->DataSource = Set; }
Перед закрытием формы выполним следующий код (обработчик события FormClosing
):
Table->TableName = "Название таблицы"; Set->WriteXml(BaseName);
Данные сохраняются в формате XML.
DataSet
представляет собой кэш данных, расположенный в оперативной памяти. DataSet
состоит из коллекции объектов класса DataTable
.
Доступ к ячейкам таблицы можно получить, используя свойства класса DataTable
(Rows
, Cols
, Item
) - но запись поля таблицы в файл может быть некорректной из-за того, что технология ADO.NET предусматривает кэширование данных.
Пример такого кода:
System::Data::DataRow ^ newRow = Table->NewRow(); Table->Rows->Add(newRow);
Поэтому следует пользоваться методами объекта DataSet
.
Скачать проект TableEditor1 в архиве .zip (13 Кб)
Пример 2. Пишем проект TableEditor2
для связанных таблиц.
Компонента DataGrid
- решение для показа связанных таблиц в одной компоненте, в DataGridView
такой возможности нет. Не все компоненты доступны по умолчанию, в том числе, и DataGrid
. Щёлкаем правой кнопкой мыши на панели элементов управления, Выбрать элементы, на вкладке "Компоненты .NET Framework" устанавливаем флажок возле элемента DataGrid
пространства имен System.Windows.Forms
, нажимаем ОК.
После этого DataGrid
можно добавить на форму.
Описаны глобально:
private: Boolean ShowClients; //Флажок-переключатель таблиц private: System::Data::DataSet ^ DataSet1;
На загрузку формы (обработчик события Load
):
ShowClients = true; //Создадим таблицу: System::Data::DataTable ^ Table = gcnew DataTable("Клиенты"); //Создадим и настроим столбец программно: DataColumn ^ Column = gcnew DataColumn("Название организации"); Column->ReadOnly = true; Column->Unique = true; Table->Columns->Add(Column); //Добавим столбцы с настройками по умолчанию, указав только названия: Table->Columns->Add("Контактное лицо"); Table->Columns->Add("Телефон"); //Создадим DataSet и добавим туда таблицу: DataSet1 = gcnew DataSet(); DataSet1->Tables->Add(Table); //Добавим в таблицу предустановленные записи об организациях-заказчиках Table->Rows->Add("НГАСУ", "Иванов Максим", "3234566"); Table->Rows->Add("НГТУ", "Сидорова Ксения", "3630313"); //Создадим вторую таблицу - "Заказы" System::Data::DataTable ^ Table2 = gcnew DataTable("Заказы"); DataColumn ^ Column2 = gcnew DataColumn("Номер заказа"); Column2->DataType = System::Type::GetType("System.Int32"); Column2->AutoIncrement = true; //Автоматический счётчик заказов Column2->ReadOnly = true; Column2->Unique = true; //Название организации - уникально! Table2->Columns->Add(Column2); Table2->Columns->Add("Объем заказа"); Table2->Columns->Add("Организация-заказчик"); //Добавим в DataSet вторую таблицу: DataSet1->Tables->Add(Table2); Table2->Rows->Add(1, "100000", "НГАСУ"); Table2->Rows->Add(2, "200000", "НГАСУ"); //Обеспечим отношение 1:N между первой и второй таблицами: DataColumn ^ Parent = DataSet1->Tables["Клиенты"]->Columns["Название организации"]; DataColumn ^ Child = DataSet1->Tables["Заказы"]->Columns["Организация-заказчик"]; DataRelation ^ Link1 = gcnew DataRelation("Ссылка на заказы клиента", Parent, Child); // В Parent значения в связываемом столбце должны быть уникальными, в Child - нет DataSet1->Tables["Заказы"]->ParentRelations->Add(Link1); dataGrid1->SetDataBinding(DataSet1, "Клиенты"); dataGrid1->CaptionText = "Родительская таблица \"Клиенты\""; dataGrid1->CaptionFont = gcnew System::Drawing::Font("Consolas", 11);
На нажатие кнопки (переключает между родительской и дочерней таблицами):
if (ShowClients == true) { dataGrid1->SetDataBinding(DataSet1, "Клиенты"); dataGrid1->CaptionText = "Родительская таблица \"Клиенты\""; } else { dataGrid1->SetDataBinding(DataSet1, "Заказы"); dataGrid1->CaptionText = "Дочерняя таблица \"Заказы\""; } ShowClients = !ShowClients;
Скачать проект TableEditor2 в архиве .zip (14 Кб)
Пример 3. Делаем всё по-современному - через DataGridView
. Подробнее об этом компоненте.
Он представляет собой прямоугольный массив ячеек, который можно рассматривать как коллекцию строк или столбцов.
Rows
- коллекция строк, имеет тип DataGridRowCollection
Columns
- коллекция столбцов, тип DataGridColumnCollection
Оба свойства индексируются как массивы для доступа к конкретной строке/столбцу, нумерация с нуля.
Cells
- коллекция ячеек из объекта DataGridRowCollection
, приведём пример доступа к ячейке:
try { MessageBox::Show(dataGridView1->Rows[1]->Cells[1]->Value->ToString()); } catch (...) { MessageBox::Show("Нет такой ячейки"); }
RowCount
, ColumnCount
- количество строк и столбцов
В несвязанном режиме компонент может отображать любые табличные данные.
Методы для добавления/удаления/редактирования строк относятся к коллекции Rows
и имеют типовые имена: Add
, Insert
, Clear
, AddCopy
, InsertCopy
, Remove
, RemoveAt
и могут иметь по несколько перегрузок каждая, например, для Add
есть версии Add()
, Add(КоличествоНовыхСтрок)
, Add (DataGridViewRow ^row)
, Add (... Object ^object)
Настройка внешнего вида компонента также типовая: такие свойства, как BackColor
, Alignment
, Font
и т.д. находятся в объекте типа DataGridViewCellStyle
Каждая ячейка представлена объектом System::Windows::Forms::DataViewCell
, за "личный" внешний вид ячейки отвечает свойство InheritedStyle
, вид по умолчанию - DefaultCellStyle
Примеры.
1. По нажатию кнопки перекрасим фон таблицы в розовый цвет:
dataGridView1->DefaultCellStyle->BackColor=Color::Pink;
2. ...или только фон выбранной ячейки:
if (cell_y>-1 && cell_x>-1) dataGridView1->Rows[cell_y]->Cells[cell_x]->Style->BackColor=Color::Green;
Значения cell_y
, cell_x
описаны глобально в классе формы:
private: int cell_y,cell_x;
инициализируются в обработчике её события Load
:
cell_y = cell_x = -1;
и получаются значения в обработчиках событий dataGridView1_KeyUp
, dataGridView1_MouseUp
(одинаковым кодом):
cell_y = dataGridView1->CurrentCell->RowIndex; cell_x = dataGridView1->CurrentCell->ColumnIndex;
3. Обработчик события dataGridView1_CellFormatting
для выделения текущей ячейки жёлтым фоном:
e->CellStyle->SelectionBackColor = Color::Yellow; e->CellStyle->SelectionForeColor = Color::Black;
4. Сделаем в dataGridView1
таблицу со значениями функции. Код по нажатию кнопки:
dataGridView1->Columns->Clear(); dataGridView1->ColumnCount=2; dataGridView1->Rows->Add (10); //Добавили 10 строк dataGridView1->Columns[0]->Name = "X"; dataGridView1->Columns[1]->Name = "Y(X)"; float x; int i; for (x=1.5,i=0; i<10; x+=0.1,i++) { dataGridView1->Rows[i]->Cells[0]->Value = Convert::ToString (x); dataGridView1->Rows[i]->Cells[1]->Value = Math::Round(x*x, 2).ToString(); //или dataGridView1->Rows[i]->Cells[1]->Value = (x*x).ToString("f"); }
5. Есть также множество событий, связанных с редактированием ячейки: CellBeginEdit
, CellEndEdit
, CellParsing
, CellValidating
, CellValidated
и т.д.
Например, по умолчанию наша таблица редактируется. Чтобы разрешить в первом столбце (Y(X)
) ввод только числовых значений, напишем следующий код, выполняемый по событию CellValueChanged
:
String ^Val = dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value->ToString(); if (e->ColumnIndex==1) { float val; bool A = Single::TryParse(Val, System::Globalization::NumberStyles::Number, System::Globalization::NumberFormatInfo::CurrentInfo, val); if (A==false) { dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value = lastValue; MessageBox::Show("Неверное число "+val.ToString(),"Ошибка"); } }
Величина lastValue
описана в классе формы:
private: float lastValue;
и, по событию CellBeginEdit
, сохраняет предыдущее значение, хранимое в ячейке:
if (e->ColumnIndex==1) lastValue = Convert::ToDouble(dataGridView1->Rows[e->RowIndex]->Cells[e->ColumnIndex]->Value);
Скачать проект TableEditor3 в архиве .zip (14 Кб)
16.03.2015, 15:33 [24147 просмотров]