Опубликован: 05.08.2010 | Доступ: свободный | Студентов: 2009 / 47 | Оценка: 4.50 / 4.40 | Длительность: 60:26:00
Лекция 5:

Работа с файлами и каталогами

Упражнение 7. Генератор случайных номеров

Иногда может потребоваться упорядоченный список номеров, сгенерированных случайным образом. В данном упражнении мы разработаем такую утилиту, используя рассмотренные классы работы с файлами. Номера будем размещать в текстовом файле. Настройку утилиты организуем через диалоговое окно, а для контроля процесса добавим консольный вывод.

  • Добавьте к решению командой File/Add/New Project новый проект типа Windows Forms Application с именем App7 и назначьте его стартовым
  • Командой Project/App7 Properties вызовите диалоговое окно настройки проекта и в выпадающем списке Output type вкладки Application установите значение Console Application
  • Разработайте интерфейс диалогового окна в соответствии с таблицей свойств
Таблица 18.14. Таблица свойств диалогового окна
Элемент Свойство Значение Пояснения
Form FormBorderStyle FixedDialog Фиксированный размер
Size 375; 385 Ширина и высота окна
MaximizeBox False Скрыть системную кнопку
MinimizeBox False Скрыть системную кнопку
Text Генератор случайных номеров Заголовок окна
StartPosition CenterScreen Начальное положение
Font Microsoft Sans Serif; 7,8pt Родительский шрифт (по умолчанию)
Label AutoSize False Подстройка размера под содержимое
BackColor Info Цвет фона
Text Генерирует список номеров случайным образом Содержимое
Font Arial; 12pt; style=Bold Шрифт
ForeColor Blue Цвет текста
TextAlign MiddleCenter Центрирование текста
Location 16; 8 Позиция относительно клиентской области формы
Label Text Куда разместить файл:
Button (Name) btnDirTarget Имя экземпляра кнопки
Text Browse Метка кнопки
TextBox (Name) txtDirTarget Путь к файлу
Label Text Имя текстового файла: Метка для txtFileName
TextBox (Name) txtFileName Текстовое поле для имени файла
Text ResultNumber.txt Имя файла по умолчанию
Label Text Нижняя граница диапазона: Текстовая метка
TextBox (Name) txtMin Текстовое поле для нижней границы генерируемых номеров
Text 0 Значение по умолчанию
Label Text Постоянный шаг: Текстовая метка
TextBox (Name) txtStep Дискрета приращения диапазона
Text 250 Шаг по умолчанию
Label Text Количество точек: Текстовая метка
TextBox (Name) txtCount Число генерируемых номеров
Text 2000 Значение по умолчанию
Label Text Верхняя граница диапазона: Метка
TextBox (Name) txtMax Расчет верхней границы
Text Пусто
ReadOnly True Только для чтения
Button (Name) btnExecute Кнопка выполнения
Text Execute Метка кнопки

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

  • Запустите приложение - пользовательский интерфейс будет выглядеть так

Создадим и заполним обработчики элементов управления в процедурном коде файла Form1.cs.

  • Добавьте в начало файла Form1.cs подключение библиотечного пространства имен System. IO для классов ввода-вывода
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
    
// Подключение дополнительных пространств имен
using System.IO;
  • В режиме Design двойным щелчком на заголовке формы (или ином незанятом компонентами месте) создайте обработчик начальной загрузки и заполните его так
int min, step, count, max;
        FolderBrowserDialog dialogFolder = new FolderBrowserDialog();
        private void Form1_Load(object sender, EventArgs e)
        {
            if (txtDirTarget.Text == String.Empty ||
                Directory.Exists(txtDirTarget.Text) == false)
            {
                dialogFolder.RootFolder =
                    System.Environment.SpecialFolder.MyComputer;
                dialogFolder.SelectedPath = "";
                txtDirTarget.Text = String.Empty;
            }
            else
            {
                dialogFolder.SelectedPath = txtDirTarget.Text;
            }
    
            dialogFolder.Description = 
                "Выберите место размещения текстового файла";
    
            min = Convert.ToInt32(txtMin.Text);
            step = Convert.ToInt32(txtStep.Text);
            count = Convert.ToInt32(txtCount.Text);
            max = min + step * count;
            txtMax.Text = max.ToString();
        }

За пределы функции вынесены поля-члены для их видимости в других обработчиках класса. В самом обработчике выполняется начальная инициализация этих переменных. Для выбора каталога используется стандартный диалог FolderBrowserDialog, который при запуске приложения устанавливается на вершину файловой системы компьютера, если выполняются указанные условия. Для явного преобразования типов используется библиотечный класс System.Convert.

  • В режиме Design выделите кнопку btnDirTarget, откройте панель Properties, щелкните на пиктограмме Events, найдите событие Click и двойным щелчком на правой ячейке сетки свойств создайте обработчик, который заполните так
private void btnDirTarget_Click(object sender, EventArgs e)
        {
            dialogFolder.ShowDialog();
            txtDirTarget.Text = dialogFolder.SelectedPath;
        }

Обработчик запускает диалог выбора папки, при закрытии которого путь сохраняется и отображается в текстовом поле txtDirTarget. Далее мы планируем этот путь использовать для создания текстового файла с именем из поля txtFileName. Выбранный путь записывается в поле.

Здесь есть одна тонкость. Текстовое поле может редактироваться пользователем и, таким образом, может содержать недостоверный путь. Можно, конечно, создавать каталог программно, если он не существует, но для тренировки мы просто заблокируем это поле для редактирования. Если присвоить txtDirTarget свойство ReadOnly=True, то оно будет серым и некрасивым. Другая возможность - просто запретить ввод символов в это поле, что мы сейчас и сделаем.

  • Выделите текстовое поле txtDirTarget, в панели Properties установите режим Events и двойным щелчком на поле значений события KeyPress создайте обработчик со следующим кодом
private void txtDirTarget_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }
  • Запустите приложение, выберите папку и попробуйте редактировать поле - стрелки и клавиша Delete продолжают функционировать

Добъем это поле окончательно.

  • Выделите текстовое поле txtDirTarget, в панели Properties установите режим Events и двойным щелчком на поле значений события KeyDown создайте обработчик со следующим кодом
private void txtDirTarget_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }
  • Запустите приложение - теперь поле полностью нередактируется, хотя и принимает курсор и фокус ввода

Таким образом, мы видим, что с помощью событий KeyDown и KeyPress можно контролировать пользовательский ввод в экземпляр текстового поля. Применим этот факт для фильтрации цифровых клавиш в текстовых полях txtMin, txtStep и txtCount, которые должны принимать только целые числа. Создадим для них общие обработчики, поскольку условие ограничения по вводу только цифр для них общее. Но прежде нам нужно узнать, в какой последовательности срабатывают события KeyDown и KeyPress.

  • В режиме Design выделите (можно частично) с помощью лассо курсора (по русски - просто обведите, а используемое здесь словоблудие, чтобы привыкали к терминам) сразу 3 упомянутых текстовых поля и в панели Properties/Events задайте для них имена обработчиков, как показано на снимке

  • Заполните созданные обработчики кодом вывода информации на консоль
private void txt_KeyDown(object sender, KeyEventArgs e)
        {
            Console.WriteLine("KeyDown");
        }
    
        private void txt_KeyPress(object sender, KeyPressEventArgs e)
        {
            Console.WriteLine("KeyPress");
        }
  • Запустите приложение - получится последовательность
KeyDown
KeyPress

Зная эту последовательность срабатывания, можно запрограммировать фильтр для пропуска только цифр.

  • Заполните общие обработчики следующим кодом
bool isNumber;
        private void txt_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            isNumber =
                e.KeyCode >= Keys.D0 && e.KeyCode <= Keys.D9 // keyboard - основная клавиатура
                || e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9 // keypad - дополнительная клавиатура
                || e.KeyCode == Keys.Back;
        }
    
        private void txt_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
        {
            // Запрещаем в текстовом поле лишние символы
            if (!isNumber)
                e.Handled = true;
        }

В первом обработчике формируется флаг isNumber, а во втором обработчике этот флаг используется для отфильтровывания цифр. Последовательность срабатывания событий обеспечивает нам нужный конвейер действий.

Создадим еще один обработчик, в котором 'на лету' будет пересчитываться значение последнего текстового поля txtMax по данным других полей. Но прежде добавим маркеры исходных текстовых полей в код начальной инициализации, чтобы в общем обработчике можно было их идентифицировать (различать) и индивидуально обрабатывать.

  • Добавьте в функцию Form1_Load() следующий код
private void Form1_Load(object sender, EventArgs e)
        {
            ...................................................
    
            // Маркируем элементы для распознавания в общем обработчике
            txtMin.Name = "Min";
            txtStep.Name = "Step";
            txtCount.Name = "Count";
        }
  • В режиме Design выделите все три поля txtMin, txtStep и txtCount одновременно и создайте для них в панели Properties для события TextChanged общий обработчик с именем (нужно вручную ввести в поле) result_TextChanged, который заполните так
private void result_TextChanged(object sender, EventArgs e)
        {
            // Следим, чтобы редактируемое поле не оказалось пустым
            TextBox txtBox = (TextBox)sender;// Приводим ссылку к типу элемента
            if (txtBox.Text == String.Empty)
            {
                switch (txtBox.Name)
                {
                    case "Min":
                        txtMin.Text = "0";
                        break;
                    case "Step":
                        txtStep.Text = "0";
                        break;
                    case "Count":
                        txtCount.Text = "0";
                        break;
                }
            }
    
            // Конвертируем разными способами
            min = Convert.ToInt32(txtMin.Text);
            step = Int32.Parse(txtStep.Text);
            int.TryParse(txtCount.Text, out count);
    
            max = min + step * count;
            txtMax.Text = max.ToString();
        }
Алексей Бабушкин
Алексей Бабушкин

При выполнении в лабораторной работе упражнения №1 , а именно при выполнении нижеследующего кода:

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Xna.Framework.Graphics;

   

namespace Application1

{

    public partial class MainForm : Form

    {

        // Объявим поле графического устройства для видимости в методах

        GraphicsDevice device;

   

        public MainForm()

        {

            InitializeComponent();

   

            // Подпишемся на событие Load формы

            this.Load += new EventHandler(MainForm_Load);

   

            // Попишемся на событие FormClosed формы

            this.FormClosed += new FormClosedEventHandler(MainForm_FormClosed);

        }

   

        void MainForm_FormClosed(object sender, FormClosedEventArgs e)

        {

            //  Удаляем (освобождаем) устройство

            device.Dispose();

            // На всякий случай присваиваем ссылке на устройство значение null

            device = null;       

        }

   

        void MainForm_Load(object sender, EventArgs e)

        {

            // Создаем объект представления для настройки графического устройства

            PresentationParameters presentParams = new PresentationParameters();

            // Настраиваем объект представления через его свойства

            presentParams.IsFullScreen = false; // Включаем оконный режим

            presentParams.BackBufferCount = 1;  // Включаем задний буфер

                                                // для двойной буферизации

            // Переключение переднего и заднего буферов

            // должно осуществляться с максимальной эффективностью

            presentParams.SwapEffect = SwapEffect.Discard;

            // Устанавливаем размеры заднего буфера по клиентской области окна формы

            presentParams.BackBufferWidth = this.ClientSize.Width;

            presentParams.BackBufferHeight = this.ClientSize.Height;

   

            // Создадим графическое устройство с заданными настройками

            device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware,

                this.Handle, presentParams);

        }

   

        protected override void OnPaint(PaintEventArgs e)

        {

            device.Clear(Microsoft.Xna.Framework.Graphics.Color.CornflowerBlue);

   

            base.OnPaint(e);

        }

    }

}

Выбрасывается исключение:

Невозможно загрузить файл или сборку "Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d" или один из зависимых от них компонентов. Не удается найти указанный файл.

Делаю все пунктуально. В чем может быть проблема?