Тверской государственный университет
Опубликован: 02.12.2009 | Доступ: свободный | Студентов: 3204 / 514 | Оценка: 4.41 / 4.23 | Длительность: 11:54:00
ISBN: 978-5-9963-0259-8
Лекция 6:

Массивы

Организация ввода-вывода двумерных массивов

Ввод двумерного массива немногим отличается от ввода одномерного массива. Сложнее обстоит дело с выводом двумерного массива, если при выводе пытаться отобразить структуру массива. К сожалению, все три элемента управления, хорошо справляющиеся с отображением одномерного массива, плохо приспособлены для показа структуры двумерного массива. Хотя у того же элемента ListBox есть свойство MultiColumn, включение которого позволяет показывать массив в виде строк и столбцов, но это не вполне то, что нужно для наших целей - отображения структуры двумерного массива. Хотелось бы, чтобы элемент имел такие свойства, как Rows и Columns, а их у элемента ListBox нет. Нет их и у элементов ComboBox и CheckedListBox. Приходится обходиться тем, что есть. На рис. 6.5 показан пример формы, поддерживающей работу по вводу и выводу двумерного массива.

Форма, поддерживающая ввод и вывод двумерного массива

Рис. 6.5. Форма, поддерживающая ввод и вывод двумерного массива

Интерфейс формы схож с тем, что использовался для организации работы с одномерным массивом. Схожа и программная организация ввода-вывода элементов массива. Поэтому я не буду приводить код, поддерживающий работу с формой TwoDimArrayForm, надеясь, что читатель при желании сможет его восстановить. Остановлюсь лишь на одном моменте, позволяющем отображать двумерный массив в элементе управления ListBox так, чтобы сохранялась структура строк и столбцов массива. Этого можно добиться за счет программной настройки размеров элемента управления ListBox:

listBox1.Height = n * HEIGHT_LINE;
                listBox1.Width = m * 2 * HEIGHT_LINE;

Константа HEIGHT_LINE задает высоту строки в списке. Вначале водятся элементы первого столбца; когда весь столбец введен, автоматически следующее вводимое значение будет отображаться в первой строке в следующем столбце.

В общей ситуации, когда значения, вводимые пользователем, могут колебаться в широком диапазоне, трудно гарантировать отображение структуры двумерного массива. Однако ситуация не безнадежна. Есть и другие, более мощные и более подходящие для наших целей элементы управления. Если на элементах ListBox и подобных ему я останавливаться не буду, оставляя их для самостоятельного изучения, то об элементе DataGridView расскажу подробнее.

Элемент управления DataGridView и отображение массивов

Элемент управления DataGridView является последней новинкой в серии табличных элементов DataGrid, позволяющих отображать таблицы. Главное назначение этих элементов - связывание с таблицами внешних источников данных, прежде всего с таблицами баз данных. Мы же сейчас рассмотрим другое его применение - в интерфейсе, позволяющем пользователю вводить и отображать матрицы - двумерные массивы.

Рассмотрим классическую задачу умножения прямоугольных матриц C=A*B. Построим интерфейс, позволяющий пользователю задавать размеры перемножаемых матриц, вводить данные для исходных матриц A и B, перемножать матрицы и видеть результаты этой операции. На рис. 6.6 показан возможный вид формы, поддерживающей работу пользователя. Форма показана в тот момент, когда пользователь уже задал размеры и значения исходных матриц, выполнил умножение матриц и получил результат.

Форма с элементами DataGridView, поддерживающая работу с матрицами

увеличить изображение
Рис. 6.6. Форма с элементами DataGridView, поддерживающая работу с матрицами

На форме расположены три текстовых окна для задания размеров матриц, три элемента DataGridView для отображения матриц, три командные кнопки для выполнения операций, доступных пользователю. Кроме того, на форме присутствуют 9 меток (элементов управления label ), семь из которых видимы на рис. 6.6. В них отображается информация, связанная с формой и отдельными элементами управления. Текст у невидимых на рисунке меток появляется тогда, когда обнаруживается, что пользователь некорректно задал значение какого-либо элемента исходных матриц.

А теперь перейдем к описанию того, как этот интерфейс реализован. В классе Form2, которому принадлежит наша форма, зададим поля, определяющие размеры матриц, и сами матрицы:

//поля класса Form
        int m, n, p;    //размеры матриц
        double[,] A, B, C;  //сами матрицы

Рассмотрим теперь, как выглядит обработчик события "Click" командной кнопки "Создать DataGridView". Предполагается, что пользователь разумен и, прежде чем нажать эту кнопку, задает размеры матриц в соответствующих текстовых окнах. Напомню, что при перемножении матриц размеры матриц должны быть согласованы - число столбцов первого сомножителя должно совпадать с числом строк второго сомножителя, а размеры результирующей матрицы определяются размерами сомножителей. Поэтому для трех матриц в данном случае достаточно задать не шесть, а три параметра, определяющие размеры.

Обработчик события выполняет три задачи - создает сами матрицы, осуществляет чистку элементов управления DataGridView, удаляя предыдущее состояние, затем добавляет столбцы и строки в эти элементы в полном соответствии с заданными размерами матриц. Вот текст обработчика:

private void button1_Click(object sender, EventArgs e)
   {
       //создание матриц
       m = Convert.ToInt32(textBox1.Text);
       n = Convert.ToInt32(textBox2.Text);
       p = Convert.ToInt32(textBox3.Text);
       A = new double[m, n];
       B = new double[n, p];
       C = new double[m, p];
      //Чистка DGView, если они не пусты
       int k =0;
       k = dataGridView1.ColumnCount;
       if (k != 0)
           for (int i = 0; i < k; i++)
               dataGridView1.Columns.RemoveAt(0);           
       dataGridView2.Columns.Clear();
       dataGridView3.Columns.Clear();      
       //Заполнение DGView столбцами 
       AddColumns(n, dataGridView1);
       AddColumns(p, dataGridView2);
       AddColumns(p, dataGridView3);
       //Заполнение DGView строками
       AddRows(m, dataGridView1);
       AddRows(n, dataGridView2);
       AddRows(m, dataGridView3);
   }

Прокомментирую этот текст.

  • Прием размеров и создание матриц, надеюсь, не требует дополнительных комментариев.
  • Чистка предыдущего состояния элементов DataGridView сводится к удалению столбцов. Продемонстрированы два возможных способа выполнения этой операции. Для первого элемента показано, как можно работать с коллекцией столбцов. Организуется цикл по числу столбцов коллекции, и в цикле выполняется метод RemoveAt, аргументом которого является индекс удаляемого столбца. Поскольку после удаления столбца происходит перенумерация столбцов, на каждом шаге цикла удаляется первый столбец, индекс которого всегда равен нулю. Удаление столбцов коллекции можно выполнить одним махом - вызывая метод Clear() коллекции, что и делается для остальных двух элементов DataGridView.
  • После чистки предыдущего состояния, можно задать новую конфигурацию элемента, добавив в него вначале нужное количество столбцов, а затем и строк. Эти задачи выполняют специально написанные процедуры AddColumns и AddRows. Вот их текст:
private void AddColumns(int n, DataGridView dgw)
   {
       //добавляет n столбцов в элемент управления dgw
       //Заполнение DGView столбцами
       DataGridViewColumn column;
       for (int i = 0; i < n; i++)
       {
           column = new DataGridViewTextBoxColumn();
           column.DataPropertyName = "Column" + i.ToString();
           column.Name = "Column" + i.ToString();
           dgw.Columns.Add(column);
       }      
   }
   private void AddRows(int m, DataGridView dgw)
   {
       //добавляет m строк в элемент управления dgw       
       //Заполнение DGView строками
       for (int i = 0; i < m; i++)
       {
        dgw.Rows.Add();
           dgw.Rows[i].HeaderCell.Value
               = "row" + i.ToString();
       }
   }

Приведу краткий комментарий.

  • Создаются столбцы в коллекции Columns по одному. В цикле по числу столбцов матрицы, которую должен отображать элемент управления DataGridView, вызывается метод Add этой коллекции, создающий очередной столбец. Одновременно в этом же цикле создается и имя столбца (свойство Name ), отображаемое в форме. Показана возможность формирования еще одного имени ( DataPropertyName ), используемого при связывании со столбцом таблицы внешнего источника данных. В нашем примере это имя не используется.
  • Создав столбцы, нужно создать еще и нужное количество строк у каждого из элементов DataGridView. Делается это аналогичным образом, вызывая метод Add коллекции Rows. Чуть по-другому задаются имена строк - для этого используется специальный объект HeaderCell, имеющийся у каждой строки и задающий ячейку заголовка.
  • После того как сформированы строки и столбцы, элемент DataGridView готов к тому, чтобы пользователь или программа вводила значения в ячейки сформированной таблицы.

Рассмотрим теперь, как выглядит обработчик события "Click" следующей командной кнопки "Перенести данные в массив". Предполагается, что пользователь разумен и, прежде чем нажать эту кнопку, задает значения элементов перемножаемых матриц в соответствующих ячейках подготовленных таблиц первых двух элементов DataGridView. Обработчик события выполняет следующие задачи - в цикле читает элементы, записанные пользователем в таблицы DataGridView, проверяет их корректность и в случае успеха переписывает их в матрицы. Вот текст обработчика:

private void button2_Click(object sender, EventArgs e)
   {
       string elem = "";
       bool correct = true;
       for (int i = 0; i < m; i++)
           for (int j = 0; j < n; j++)
           {                    
              try
                {
                 elem=dataGridView1.Rows[i].Cells[j].Value.ToString();
                 A[i, j] = Convert.ToDouble(elem);
                 label8.Text = "";  
                 }
              catch (Exception any)
                 {
                   label8.Text = "Значение элемента" +
                  "A[" + i.ToString() +", " + j.ToString() + " ]"
                  + " не корректно. Повторите ввод!";
   dataGridView1.Rows[i].Cells[j].Selected= true;                                       
     return;
              }                   
           }
       for (int i = 0; i < n; i++)
           for (int j = 0; j < p; j++)
            {
               do
                {
                  correct = true;
                  try
                  {
              elem =
        dataGridView2.Rows[i].Cells[j].Value.ToString();                            
         B[i, j] = Convert.ToDouble(elem);
         label9.Text = "";
                      }
          catch (Exception any)
          {
            label9.Text = "Значение элемента" +
            "B[" + i.ToString() + ", " + j.ToString() + "]"
            + " не корректно. Повторите ввод!";
            dataGridView2.Rows[i].Cells[j].Selected=true;           
       Form3 frm = new Form3();
            frm.label1.Text = 
            "B[" + i.ToString() + "," + j.ToString() + "]= ";
            frm.ShowDialog();
         dataGridView2.Rows[i].Cells[j].Value = 
      frm.textBox1.Text;
            correct = false;
          }
                    } while (!correct);                     
                }
        }

Этот программный код нуждается в подробных комментариях.

  • Основная задача переноса данных из таблицы элемента DataGridView в соответствующий массив не вызывает проблем. Конструкция Rows[i].Cells[j] позволяет добраться до нужного элемента таблицы, после чего остается присвоить его значение элементу массива.
  • Как всегда при вводе основной проблемой является обеспечение корректности вводимых данных. Схема, рассматриваемая нами ранее, нуждается в корректировке. Дело в том, что ранее проверка корректности осуществлялась сразу же после ввода пользователем значения элемента. Теперь проверка корректности выполняется после того, как пользователь полностью заполнил таблицы, при этом некоторые элементы он мог задать некорректно. Просматривая таблицу, необходимо обнаружить некорректно заданные значения и предоставить возможность их исправления. В программе предлагаются два различных подхода к решению этой проблемы.
  • Первый подход демонстрируется на примере ввода элементов матрицы A. Как обычно, преобразование данных, введенных пользователем, в значение, допустимое для элементов матрицы А, помещается в охраняемый блок. Если данные некорректны и возникает исключительная ситуация, то она перехватывается универсальным обработчиком catch(Exception). Заметьте, в данном варианте нет цикла, работающего до тех пор, пока не будет введено корректное значение. Обработчик исключения просто прерывает работу по переносу данных, вызывая оператор return. Но предварительно он формирует информационное сообщение об ошибке и выводит его в форму. (Помните, специально для этих целей у формы были заготовлены две метки). В сообщении пользователю предлагается исправить некорректно заданный элемент и повторить ввод - повторно нажать командную кнопку "перенести данные в массив". Этот подход понятен и легко реализуем. Недостатком является его неэффективность, поскольку повторно будут переноситься в массив все элементы, в том числе и те, что были введены вполне корректно. У программиста такая ситуация может вызывать чувство неудовлетворенности своей работой.
  • На примере ввода элементов матрицы В продемонстрируем другой подход, когда исправляется только некорректно заданное значение. Прежде чем читать дальше, попробуйте найти собственное решение этой задачи. Это не так просто, как может показаться с первого взгляда. Для организации диалога с пользователем пришлось организовать специальное диалоговое окно, представляющее обычную форму с двумя элементами управления - меткой для выдачи информационного сообщения и текстовым окном для ввода пользователем корректного значения. При обнаружении ошибки ввода открывается диалоговое окно, в которое пользователь вводит корректное значение элемента и закрывает окно диалога. Введенное пользователем значение переносится в нужную ячейку таблицы DataGridView, а оттуда в матрицу.
  • При проектировании диалогового окна значение свойства формы FormBorderStyle, установленное по умолчанию как " sizeable ", следует заменить значением " FixedDialog ", что влияет на внешний вид и поведение формы. Важно отметить, что форма, представляющая диалоговое окно, должна вызываться не методом Show, а методом ShowDialog. Иначе произойдет зацикливание, начнут порождаться десятки диалоговых окон, прежде чем вы успеете нажать спасительную в таких случаях комбинацию Ctrl+ Alt + Del.

Обработчик события "Click" командной кнопки "Умножить матрицы" выполняет ответственные задачи - реализует умножение матриц и отображает полученный результат в таблице соответствующего элемента DataGridView. Но оба эти действия выполняются естественным образом, не требуя, кроме циклов, никаких специальных средств и программистских ухищрений. Я приведу программный код без дополнительных комментариев:

private void button3_Click(object sender, EventArgs e)
        {
            MultMatr(A, B, C);
            FillDG();          
        }
	void MultMatr(double[,] A, double[,] B, double[,] C)
        {
            int m = A.GetLength(0);
            int n = A.GetLength(1);
            int p = B.GetLength(1);
            double S =0;
            for(int i=0; i < m; i++)
                for (int j = 0; j < p; j++)
                {
                    S = 0;
                    for (int k = 0; k < n; k++)
                        S += A[i, k] * B[k, j];
                    C[i, j] = S;
                }
        }	
void FillDG()
        {
            for (int i = 0; i < m; i++)
                for (int j = 0; j < p; j++)
                    dataGridView3.Rows[i].Cells[j].Value
                        = C[i, j].ToString();
        }
Задачи (ввод, вывод и другие простые задачи с массивами)
  • 1. Организуйте в консольном приложении ввод и вывод одномерного массива строкового типа.
  • 2. Организуйте в Windows-приложении ввод и вывод одномерного массива строкового типа.
  • 3. Организуйте в консольном приложении ввод массива "Сотрудники", содержащего фамилии сотрудников. Введите массив "Заявка", элементы которого содержат фамилии сотрудников и, следовательно, должны содержаться в массиве сотрудников. Обеспечьте контроль корректности ввода данных.
  • 4. Организуйте в Windows-приложении ввод массива "Сотрудники", содержащего фамилии сотрудников. Введите массив "Заявка", элементы которого содержат фамилии сотрудников и, следовательно, должны содержаться в массиве сотрудников. Обеспечьте контроль корректности ввода данных.
  • 5. Организуйте в Windows-приложении ввод массива "Сотрудники", содержащего фамилии сотрудников. Создайте массив "Заявка", элементы которого должны содержаться в массиве сотрудников. Для создания массива "Заявка" постройте форму "Два списка", содержащую два элемента ListBox, источником данных для первого из них служит массив "Сотрудники". Пользователь переносит данные из первого списка во второй, формируя данные для массива "Заявка". После формирования данные переносятся в массив. Для построения формы используйте шаблон, описанный в лекции 24 учебника.
  • 6. Организуйте в консольном приложении ввод и вывод двумерного массива строкового типа.
  • 7. Организуйте в Windows-приложении ввод и вывод двумерного массива строкового типа.
  • 8. Организуйте в консольном приложении ввод массива "Сотрудники" из двух столбцов, содержащего фамилии и имена сотрудников. Введите массив "Заявка" той же структуры, элементы которого должны содержаться в массиве сотрудников. Обеспечьте контроль корректности ввода данных. Организуйте вывод обоих массивов.
  • 9. Организуйте в Windows-приложении ввод массива "Сотрудники" из двух столбцов, содержащего фамилии и имена сотрудников. Введите массив "Заявка" той же структуры, элементы которого должны содержаться в массиве сотрудников. Обеспечьте контроль корректности ввода данных. Организуйте вывод обоих массивов.
  • 10. (*) Организуйте в консольном приложении ввод и вывод массива "Машины", содержащего 4 столбца: "Владелец", "Марка", "Номер", "Год Выпуска". При вводе данных обеспечьте их корректность. Поле "Владелец" должно быть строкой в формате "фамилия имя", где фамилия и имя должны начинаться с большой буквы и состоять из букв алфавита кириллицы, включая дефис. Номер машины должен соответствовать формату, принятому для номеров машин. При выводе сохраняйте структуру массива.
  • 11. (*) Организуйте в Windows-приложении ввод и вывод массива "Машины", содержащего 4 столбца: "Владелец", "Марка", "Номер", "Год Выпуска". При вводе данных обеспечьте их корректность. Поле "Владелец" должно быть строкой в формате "фамилия имя", где фамилия и имя должны начинаться с большой буквы и состоять из букв алфавита кириллицы, включая дефис. Номер машины должен соответствовать формату, принятому для номеров машин. При выводе сохраняйте структуру массива.
  • 12. (*) В консольном приложении уже построен массив "Машины" (см. задача 3.9). Построить массив "Цветные машины", в котором к столбцам массива "Машины" добавляется 5-й столбец "Цвет". Организуйте диалог с пользователем, выясняя цвет для каждой машины из массива "Машины".
  • 13. (*) В Windows-приложении уже построен массив "Машины" (см. задача 3.10) . Построить массив "Цветные машины", в котором к столбцам массива "Машины" добавляется 5-й столбец "Цвет". Организуйте диалог с пользователем, выясняя цвет для каждой машины из массива "Машины".
  • 14. Организуйте в консольном приложении ввод и вывод одномерного массива арифметического типа (от byte до double).
  • 15. Организуйте в Windows-приложении ввод и вывод одномерного массива арифметического типа (от byte до double).
  • 16. Организуйте в консольном приложении ввод массива "Сотрудники", содержащего фамилии сотрудников, и массива "Зарплата". Обеспечьте контроль корректности ввода данных о зарплате, проверяя диапазон возможных значений.
  • 17. Организуйте в Windows-приложении ввод массива "Сотрудники", содержащего фамилии сотрудников, и массива "Зарплата". Обеспечьте контроль корректности ввода данных о зарплате, проверяя диапазон возможных значений.
  • 18. Организуйте в консольном приложении ввод и вывод матрицы - двумерного массива арифметического типа.
  • 19. Организуйте в Windows-приложении ввод и вывод матрицы - двумерного массива арифметического типа.
  • 20. Организуйте в консольном приложении ввод массива декартовых координат n точек на плоскости. Вычислите массив полярных координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 21. Организуйте в Windows-приложении ввод массива декартовых координат n точек на плоскости. Вычислите массив полярных координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 22. Организуйте в консольном приложении ввод массива полярных координат n точек на плоскости. Вычислите массив декартовых координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 23. Организуйте в Windows-приложении ввод массива полярных координат n точек на плоскости. Вычислите массив декартовых координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 24. Организуйте в консольном приложении ввод массива декартовых координат n точек в трехмерном пространстве. Вычислите массив полярных координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 25. Организуйте в Windows-приложении ввод массива декартовых координат n точек в трехмерном пространстве. Вычислите массив полярных координат этих точек и организуйте вывод этого массива. Обеспечьте контроль вводимых значений.
  • 26. Организуйте в консольном приложении ввод и вывод массива декартовых координат n точек на плоскости. Вычислите массив, содержащий все комбинации из трех точек исходного массива, такие, что точки могут рассматриваться как вершины некоторого треугольника на плоскости. Организуйте вывод этого массива.
  • 27. Организуйте в Windows-приложении ввод и вывод массива декартовых координат n точек на плоскости. Вычислите массив, содержащий все комбинации из трех точек исходного массива, такие, что точки могут рассматриваться как вершины некоторого треугольника на плоскости. Организуйте вывод этого массива.
Дарья Федотова
Дарья Федотова
Надежда Савина
Надежда Савина

Записалась на платный курс Программирование на С# http://www.intuit.ru/studies/professional_retraining/951/video_courses/356/info. Оплату пока не производила.

Могу ли я скачать/прочитать текст прослушиваемых лекций? Особенно интересуют задания