011 – Приклад створення двовимірної матриці на формі. Аналог компоненту TStringGrid в Delphi.

Приклад створення двовимірної матриці на формі. Аналог компоненту TStringGrid в Delphi

Часто в задачах потрібно ввести числа або інші дані у двовимірний масив (матрицю) і мати можливість їх обробляти.

У роботі реалізовано аналог компоненту TStringGrid у Delphi для представлення даних у вигляді двовимірної таблиці рядків. Для цього використовується двовимірний масив елементів управління типу TextBox.


Зміст


Умова задачі

Скласти програму, яка здійснює добуток двох матриць розмірністю n. Матриці вводяться з клавіатури в окремій формі і заносяться у внутрішні структури даних. Користувач має можливість переглянути результуючу матрицю.

Також є можливість збереження результуючої матриці у текстовому файлі “Res_Matrix.txt”.

 


Виконання

1. Запуск Microsoft Visual Studio. Створення нового проекту

Детальний приклад завантаження Microsoft Visual Studio та створення додатку за шаблоном Windows Forms Application описується в темі:

Зберегти проект під довільним іменем.

 

2. Розробка основної форми Form1

Розробити форму за зразком, як показано на рисунку 1.

Розмістити на формі елементи управління таких типів:

  • чотири елементи управління типу Button. Автоматично буде створено чотири об’єкти (змінні) з іменами button1, button2, button3, button4;
  • три елементи управління типу Label з іменами label1, label2, label3;
  • один елемент управління типу TextBox, доступ до якого можна отримати за іменем textBox1.

Сформувати властивості елементів управління типу Button та Label:

    • в об’єкті button1 властивість Text = “Ввід матриці 1 …“;
    • в об’єкті button2 властивість Text = “Ввід матриці 2 …“;
    • в об’єкті button3 властивість Text = “Результат …“;
    • в об’єкті button4 властивість Text = “Зберегти у файлі “Res_Matr.txt” ”;
    • в елементі управління label1 властивість Text = “n = ”.

Для налаштування вигляду та поведінки форми потрібно виконати такі дії:

  • встановити назву форми. Для цього властивість Text = “Добуток матриць”;
  • властивість StartPosition = “CenterScreen” (форма розміщується в центрі екрану);
  • властивість ControlBox = “false” (приховати кнопки управління формою).

C# Windows Forms Форма додаткуРис. 1. Форма додатку

 

3. Розробка другорядної форми Form2

У другорядній формі Form2 будуть вводитись вхідні матриці та виводитись вихідний результат.

Детальний приклад створення нової форми в MS Visual Studio – C# описаний тут.

Додати нову форму до додатку, викликавши команду

Project -> Add Windows Form …

У вікні, що відкриється, вибрати Windows Form. Ім’я файлу залишити без змін «Form2.cs».



Розмістити на формі у будь-якому місці елемент управління типу Button (рис. 2). У результаті буде отримано об’єкт з іменем button1.

В елементі управління button1 налаштовуємо такі властивості:

  • властивість Text = “OK”;
  • властивість DialogResult = “OK” (рис. 3). Це означає, що при натиску (кліку мишкою) на button1 вікно закриється з кодом повернення рівним “OK”;
  • властивість Modifiers = “Public”. Це означає, що кнопка button1 буде видимою з інших модулів (з форми Form1).

Налаштувати властивості форми Form2:

  • властивість Text = “Ввід матриці”;
  • властивість StartPosition = “CenterScreen” (форма розміщується в центрі екрану);
  • властивість ControlBox = “false” (приховати кнопки управління формою).

C# Windows Forms Форма Form2Рис. 2. Форма Form2 після налаштування

C# Windows Forms Властивість DialogResultРис. 3. Властивість DialogResult елемента управління button1 форми Form2

 

4. Ввід внутрішніх змінних

Наступний крок – введення внутрішніх змінних у текст модуля “Form1.cs”.

Для цього спочатку потрібно активувати модуль “Form1.cs”.

У тексті модуля “Form1.cs” додаємо такий код:

...
namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        const int MaxN = 10; // максимально допустима розмірність матриці
        int n = 3; // поточна розмірність матриці
        TextBox[,] MatrText = null; // матриця елементів типу TextBox
        double[,] Matr1 = new double[MaxN, MaxN]; // матриця 1 дійсних чисел
        double[,] Matr2 = new double[MaxN, MaxN]; // матриця 2 дійсних чисел
        double[,] Matr3 = new double[MaxN, MaxN]; // результуюча матриця
        bool f1; // прапорець, що вказує про введені дані у матриці Matr1
        bool f2; // прапорець, що вказує про введені дані у матриці Matr2
        int dx = 40, dy = 20; // ширина та висота комірки у MatrText[,]
        Form2 form2 = null;   // екземпляр (об'єкт) класу форми Form2

        public Form1()
        {
            InitializeComponent();
        }
    }
}

...

Пояснимо призначення вищенаведених змінних:

  • MaxN – максимально-допустима розмірність матриці;
  • n – розмірність матриці, введена користувачем з клавіатури в елементі управління TextBox1;
  • MatrText – двовимірна матриця елементів управління типу TextBox. У цю матрицю будуть вводитись елементи матриці у вигляді рядків. Ввід даних буде формуватись у формі Form2;
  • Matr1, Matr2 – матриці елементів типу double, в які будуть копіюватись дані з матриці MatrText;
  • Matr3 – результуюча матриця, яка рівна добутку матриць Matr1 та Matr2;
  • f1, f2 – змінні, що визначають, чи були введені дані відповідно у матриці Matr1 та Matr2;
  • dx, dy – габарити однієї комірки типу TextBox у матриці MatrText;
  • form2 – об’єкт класу форми Form2, за яким буде отримано доступ до цієї форми.

 

5. Програмування події Load форми Form1

Процес програмування будь-якої події у Microsoft Visual C# детально описаний тут.

Лістинг обробника події Load форми Form1 наступний:

private void Form1_Load(object sender, EventArgs e)
{
  // І. Ініціалізація елементів управління та внутрішніх змінних
  textBox1.Text = "";
  f1 = f2 = false; // матриці ще не заповнені
  label2.Text = "false";
  label3.Text = "false";

  // ІІ. Виділення пам'яті та налаштування MatrText
  int i, j;

  // 1. Виділення пам'яті під форму Form2
  form2 = new Form2();

  // 2. Виділення пам'яті під саму матрицю
  MatrText = new TextBox[MaxN, MaxN];

  // 3. Виділення пам'яті для кожної комірки матриці та її налаштування
  for (i = 0; i < MaxN; i++)
    for (j = 0; j < MaxN; j++)
    {
      // 3.1. Виділити пам'ять
      MatrText[i, j] = new TextBox();

      // 3.2. Занулити цю комірку
      MatrText[i, j].Text = "0";

      // 3.3. Встановити позицію комірки у формі Form2
      MatrText[i, j].Location = new System.Drawing.Point(10 + i * dx, 10 + j * dy);

      // 3.4. Встановити розмір комірки
      MatrText[i, j].Size = new System.Drawing.Size(dx, dy);

      // 3.5. Поки що приховати комірку
      MatrText[i, j].Visible = false;

      // 3.6. Додати комірку MatrText[i,j] у форму form2
      form2.Controls.Add(MatrText[i, j]);
    }
}

Пояснимо деякі фрагменти коду у методі Form1_Load().

Подія Load генерується (викликається) в момент завантаження будь-якої форми. Оскільки форма Form1 є головною формою додатку, то подія Load форми Form1 буде викликатись одразу після запуску додатку на виконання. Тому, сюди доцільно ввести початкову ініціалізацію елементів управління та внутрішніх змінних програми. Ці елементи управління можуть бути викликані з інших методів класу.

В обробнику події Form1_Load() виділяється пам’ять для двовимірної матриці рядків MatrText один лише раз. При завершенні додатку ця пам’ять буде автоматично звільнена.

Пам’ять виділяється у два етапи:

  • для самої матриці MatrText як двовимірного масиву;
  • для кожного елементу матриці, який є складним об’єктом типу TextBox.

Після виділення пам’яті для кожного об’єкту здійснюється налаштування основних внутрішніх властивостей (позиція, розмір, текст, видимість у деякій формі).

Також кожна створена комірка додається (розміщується) до форми Form2 з допомогою методу Add() з класу Controls. Кожна новостворена комірка може бути додана у будь-яку іншу форму.

 

6. Розробка додаткового методу занулення даних у матриці MatrText

Для того, щоб декілька разів не використовувати занулення рядків матриці MatrText, потрібно створити власний метод (наприклад, Clear_MatrText()).

Лістинг методу Clear_MatText() наступний:

private void Clear_MatrText()
{
  // Занулення комірок MatrText
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
      MatrText[i, j].Text = "0";
}

 

7. Програмування події кліку на кнопці button1Ввід матриці 1 …»)

При натиску на button1 потрібно викликатись вікно вводу нової матриці. Розмір матриці залежить від значення n.

Лістинг обробника події кліку на кнопці button1 наступний:

private void button1_Click(object sender, EventArgs e)
{
  // 1. Читання розмірності матриці
  if (textBox1.Text == "") return;
  n = int.Parse(textBox1.Text);

  // 2. Занулити комірки MatrText
  Clear_MatrText();

  // 3. Налаштування властивостей комірок матриці MatrText
  //    з прив'язкою до значення n та форми Form2
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
    {
      // 3.1. Порядок табуляції
      MatrText[i, j].TabIndex = i * n + j + 1;

      // 3.2. Зробити комірку видимою
      MatrText[i, j].Visible = true;
    }

  // 4. Корегування розмірів форми
  form2.Width = 10 + n * dx + 20;
  form2.Height = 10 + n * dy + form2.button1.Height + 50 ;

  // 5. Корегування позиції та розмірів кнопки на формі Form2
  form2.button1.Left = 10;
  form2.button1.Top = 10 + n * dy + 10;
  form2.button1.Width = form2.Width - 30;

  // 6. Виклик форми Form2
  if (form2.ShowDialog() == DialogResult.OK)
  {
    // 7. Перенесення рядків з форми Form2 у матрицю Matr1
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        if (MatrText[i, j].Text != "")
          Matr1[i, j] = Double.Parse(MatrText[i, j].Text);
        else
          Matr1[i, j] = 0;

        // 8. Дані в матрицю Matr1 внесено
        f1 = true;
        label2.Text = "true";
  }
}

У вищенаведеному лістингу читається значення n. Після цього здійснюється налаштування комірок матриці рядків MatrText.

На основі введеного значення n формуються розміри форми form2 та позиція кнопки button1.

Якщо у формі Form2 користувач натиснув на кнопці OK (button2), то рядки з MatrText переносяться у двовимірну матрицю дійсних чисел Matr1. Перетворення з рядка в дійсне число виконується методом Parse() з класу Double.

Також формується змінна f1, яка вказує що дані в матрицю Matr1 внесено.

 

8. Програмування події кліку на кнопці button2 (“Ввід матриці 2…“)

Лістинг обробника події кліку на кнопці button2 подібний до лістингу обробника події кліку на кнопці button1. Тільки відрізняється кроками 7-8. На цьому відрізку формуються матриця Matr2 та змінна f2.

private void button2_Click(object sender, EventArgs e)
{
  // 1. Читання розмірності матриці
  if (textBox1.Text == "") return;
  n = int.Parse(textBox1.Text);

  // 2. Онулити комірки MatrText
  Clear_MatrText();

  // 3. Налаштування властивостей комірок матриці MatrText
  //    з прив'язкою до значення n та форми Form2
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
    {
      // 3.1. Порядок табуляції
      MatrText[i, j].TabIndex = i * n + j + 1;

      // 3.2. Зробити комірку видимою
      MatrText[i, j].Visible = true;
    }

  // 4. Корегування розмірів форми
  form2.Width = 10 + n * dx + 20;
  form2.Height = 10 + n * dy + form2.button1.Height + 50;

  // 5. Корегування позиції та розмірів кнопки на формі Form2
  form2.button1.Left = 10;
  form2.button1.Top = 10 + n * dy + 10;
  form2.button1.Width = form2.Width - 30;

  // 6. Виклик форми Form2
  if (form2.ShowDialog() == DialogResult.OK)
  {
    // 7. Перенесення рядків з форми Form2 у матрицю Matr2
    for (int i = 0; i < n; i++)
      for (int j = 0; j < n; j++)
        Matr2[i, j] = Double.Parse(MatrText[i, j].Text);

    // 8. Матриця Matr2 сформована
    f2 = true;
    label3.Text = "true";
  }
}

 

9. Програмування події Leave втрати фокусу введення елементом управління textBox1

У програмі може виникнути ситуація, коли користувач змінює значення n. У цьому випадку повинні заново формуватись прапорці f1 та f2. Також змінюється розмір матриці MatrText, що виводиться у формі Form2.

Зміну значення n можна проконтролювати з допомогою події Leave елементу управління textBox1. Подія Leave генерується в момент втрати фокусу введення елементом управління textBox1 (рис. 4).

C# Windows Forms Подія Leave елемент управління textBox1Рис. 4. Подія Leave елементу управління textBox1

Лістинг обробника події Leave наступний:

private void textBox1_Leave(object sender, EventArgs e)
{
  int nn;
  nn = Int16.Parse(textBox1.Text);
  if (nn != n)
  {
    f1 = f2 = false;
    label2.Text = "false";
    label3.Text = "false";
  }
}

 

10. Програмування події кліку на кнопці button3Результат»)

Виведення результату буде здійснюватись у ту саму форму, в якій вводились матриці Matr1 та Matr2. Добуток цих матриць спочатку буде сформовано в матриці Matr3. Потім значення з Matr3 переноситься в MatrText і відображається на формі Form2.

Лістинг обробника події кліку на кнопці button3.

// Вивід результату
private void button3_Click(object sender, EventArgs e)
{
  // 1. Перевірка, чи матриці введено
  if (!((f1 == true) && (f2 == true))) return;

  // 2. Обчислення добутку матриць. Результат в Matr3
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
    {
      Matr3[j,i] = 0;
      for (int k = 0; k < n; k++)
          Matr3[j, i] = Matr3[j, i] + Matr1[k, i] * Matr2[j, k];
    }

  // 3. Занесення даних в MatrText
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
      {
        // 3.1. Порядок табуляції
        MatrText[i, j].TabIndex = i * n + j + 1;

        // 3.2. Перевести число в рядок
        MatrText[i, j].Text = Matr3[i, j].ToString();
      }

  // 4. Виведення форми
  form2.ShowDialog();
}

 

11. Програмування події кліку на кнопці button4Зберегти у файлі «Res_Matr.txt”)

Для збереження результуючої матриці Matr3 потрібно використати можливості класу FileStream.

Клас FileStream описаний в модулі System.IO. Тому на початку додатку потрібно додати такий код:

using System.IO;

Лістинг обробника події кліку на кнопці button4 наступний:

private void button4_Click(object sender, EventArgs e)
{
  FileStream fw = null;
  string msg;
  byte[] msgByte = null;

  // 1. Відкрили файл для запису
  fw = new FileStream("Res_Matr.txt", FileMode.Create);

  // 2. Запис матриці результату у файл
  // 2.1. Спочатку записати к-сть елементів матриці Matr3

  // новий рядок
  msg = n.ToString() + "\r\n";

  // перевести рядок у байтовий масив
  msgByte = Encoding.Default.GetBytes(msg);

  // записати байтовий масив у файл
  fw.Write(msgByte, 0, msgByte.Length);

  // 2.2. Тепер записати саму матрицю
  msg = "";
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < n; j++)
    {
      msg = msg + Matr3[i, j].ToString() + "  ";
    }

    // новий рядок у текстовому файлі
    msg = msg + "\r\n"; 
  }

  // перевести рядок у байтовий масив
  msgByte = Encoding.Default.GetBytes(msg);

  // записати байтовий масив у файл
  fw.Write(msgByte, 0, msgByte.Length);

  // 3. Закрити файл
  if (fw != null) fw.Close();
}

 

12. Запуск додатку на виконання

Тепер можна запускати додаток на виконання.