Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Алгоритмизация как основной этап разработки программ

Содержание:

ВВЕДЕНИЕ

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

Прежде чем начать проектирование прикладных программ, специалисту необходимо изучить методологию разработки программного обеспечения (которая также может быть важной и для конечного пользователя этих программ), в общем случае подразумевающей выполнение следующих этапов [8.]:

  • постановку задачи;
  • формализацию задачи;
  • алгоритмизацию (разработку алгоритма решения задачи);
  • программирование (разработку программного кода задачи на языке программирования);
  • составление описания (документации).

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

На этом этапе разработчику будет необходимо спроектировать алгоритмы. Это означает, что нужно помнить о стратегиях, которые используются для решения задач, чтобы применять их к технологиям программирования. Эти алгоритмы могут быть разработаны с использованием блок-схем или псевдокода.

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

Однако иногда необходим компромисс между другими факторами. Например, эффективность может быть принесена в жертву ради высокой степени надежности. Разработка алгоритмов для решения простых задач может быть простой, но разработка алгоритмов для больших и сложных задач может быть сложной и трудоемкой. Хотя этот пример может касаться только простых задач, используемые методы важны при разработке алгоритмов и для сложных задач. Один общий подход к большим и сложным задачам – использовать нисходящий дизайн. Нисходящее проектирование начинается в верхней части структурной схемы с общей формулировкой задачи, написанной точным, формальным способом для обеспечения высокоуровневой спецификации алгоритма. Этот способ предполагает разделение на отдельные логические части, для решения которых предоставляется общая спецификация. Эти части соответствуют основным модулям в конечном алгоритме. Затем части подразделяются и составляются инструкции. Наконец, алгоритм достигает той стадии, когда общая спецификация состоит из вычислений, сравнений и доступа к данным, и может быть запрограммирован без дальнейшего объяснения.

Цель данной курсoвой работы состоит в том, чтобы получить представление об основных этапах разработки программы для решения определенной задачи, используя алгоритмы для решения ее отдельных подзадач.

Для достижения цели в курсовой работе были поставлены следующие задачи:

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

В процессе выполнения работы все поставленные задачи были успешно выполнены.

Роль этапа алгоритмизации в процессе разработки программ

Понятие алгоритма и его свойства

Алгоритмом называется точное и понятное предписание исполнителю совершить последовательность действий, направленных на решение поставленной задачи [6.]. Слово «алгоритм» происходит от имени математика Аль Хорезми, который сформулировал правила выполнения арифметических действий. Первоначально под алгоритмом понимали только правила выполнения четырех арифметических действий над числами. В дальнейшем это понятие стали использовать вообще для обозначения последовательности действий, приводящих к решению любой поставленной задачи. Говоря об алгоритме вычислительного процесса, необходимо понимать, что объектами, к которым применялся алгоритм, являются данные. Алгоритм решения вычислительной задачи представляет собой совокупность правил преобразования исходных данных в результатные.

Основными свойствами [1.] алгоритма являются:

  • детерминированность (определенность). Предполагает получение однозначного результата вычислительного процесса при заданных исходных данных. Благодаря этому свойству процесс выполнения алгоритма носит механический характер;
  • результативность. Указывает на наличие таких исходных данных, для которых реализуемый по заданному алгоритму вычислительный процесс должен через конечное число шагов остановиться и выдать искомый результат;
  • массовость. Это свойство предполагает, что алгоритм должен быть пригоден для решения всех задач данного типа;
  • дискретность. Означает расчлененность определяемого алгоритмом вычислительного процесса на отдельные этапы, возможность выполнения которых исполнителем (компьютером) не вызывает сомнений.

Алгоритм должен быть формализован по некоторым правилам посредством конкретных изобразительных средств. К ним относятся следующие способы записи [2.] алгоритмов: словесный, формульно-словесный, графический, язык операторных схем, алгоритмический язык.

Наибольшее распространение благодаря своей наглядности получил графический (блок-схемный) способ записи алгоритмов.

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

При всем многообразии алгоритмов решения задач в них можно выделить три основных вида вычислительных процессов [5.]:

  • линейный;
  • ветвящийся;
  • циклический.

Линейным называется такой вычислительный процесс, при котором все этапы решения задачи выполняются в естественном порядке следования записи этих этапов.

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

Циклом называется многократно повторяемый участок вычислений. Вычислительный процесс, содержащий один или несколько циклов, называется циклическим. По количеству выполнения циклы делятся на циклы с определенным (заранее заданным) числом повторений и циклы с неопределенным числом повторений. Количество повторений последних зависит от соблюдения некоторого условия, задающего необходимость выполнения цикла. При этом условие может проверяться в начале цикла – тогда речь идет о цикле с предусловием, или в конце — тогда это цикл с постусловием.

Программа и данные

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

Итак, программа представляет собой последовательность исполняемых однозначных инструкций, написанных на компьютерном языке. Компьютер может понимать инструкции различных типов: инструкции ввода / вывода для ввода данных в компьютер и вывода ответов из него; переместить инструкции для перестановки данных; арифметические инструкции для выполнения расчетов; контрольные инструкции для контроля выбора и повторения действий; логические инструкции, помогающие компьютеру делать выбор. Эти типы инструкций доступны на большинстве языков программирования. Например, в языке программирования Си есть инструкции, предназначенные для того, чтобы контролировать, где данные хранятся в памяти компьютера [3.]. Входные данные относятся к данным, отправленным процессору компьютера из файла на автоматическом запоминающем устройстве или из внешнего источника. Ввод может осуществляться с клавиатуры или с автоматического устройства, такого как метеостанция.

Вывод относится к данным, отправленным с процессора компьютера на автоматические устройства хранения данных или на внешнее устройство [7.]. Вывод может быть напечатан, отображен на экране компьютера, записан на накопитель, диск или дискету, нанесен на карту (визуализирован) на графическом устройстве или использован для управления автоматическим устройством. Внутренняя перестановка данных, во время которой значения копируются из одной ячейки памяти в другую, достигается главным образом с помощью инструкций присваивания, которые выглядят как простые уравнения. Например, инструкция языка Си «a = b;» не означает, что a и b – это одно и то же, а то, что a присваивается (назначается) то же значение, что и b. Фактически значение, содержащееся в ячейке памяти с именем b, копируется в ячейку памяти с именем a. После того как оператор выполнит оператор a = b, ячейка памяти a будет содержать то же значение, что и ячейка памяти b. Арифметические инструкции состоят из основных арифметических операций сложения, вычитания, умножения, деления, остатка и возведения в степень (возведения в степень), а также присваивания значения переменной. Таким образом, инструкция «а = 2,5 + 6,5 / 3,25;» означает, что значение 4,5 рассчитывается как значение, назначенное для переменной a. Арифметические выражения оцениваются компьютером с тем же приоритетом, что и в математике. В этом примере деление выполняется перед сложением. Команды управления используются для переключения с одного набора команд на другой в зависимости от логического сравнения значений данных. Например, компьютер может выбирать между сложением или вычитанием в зависимости от того, является ли число положительным или нет: «if (x > 0) z = x + 5; else z = x – 5;»

Управляющие инструкции всегда включают сравнение одного значения с другим. Все сравнения приводят к ответу «истина» или «ложь», что становится основой для контрольного решения.

Сбор связанной между собой информации, подлежащей обработке прикладной программой, такой как температура, усредненная за определенный период времени, называется данными [9.]. Данные обычно хранятся в файле на диске. Файл данных представляет собой хранилище и содержит структурированную коллекцию данных. Входные данные должны быть систематизированы. Каждая программа включает в себя описание структуры данных, чтобы компьютер знал, как ее интерпретировать. Если программа должна найти свои входные данные на диске, данные должны быть введены в файл данных. Входные данные также могут быть введены непосредственно в исполняющую программу. Когда значения данных вводятся напрямую, особенно важно, чтобы программа проверяла данные перед их использованием. В любом случае конец входных данных должен быть узнаваемым. Когда значения данных вводятся напрямую, в качестве конечного символа используется специальный управляющий символ.

Данные, сгенерированные компьютером для вывода, могут быть разных типов: решения математических уравнений, числа, рисунки, графики, текстовые материалы или специальные символы [10.]. Выходные данные должны быть правильно отформатированы для устройства вывода с соответствующим интервалом по вертикали и горизонтали. Данные должны быть представлены в удобной форме. Вывод данных должен быть понятным и простым в использовании. Хороший вывод данных стоит потраченного времени на его разработку и форматирование.

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

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

Формализация и проектирование алгоритма

Для того, чтобы проанализировать задачу, помимо написания точной спецификации алгоритма, пользователь должен написать точные спецификации для входных и выходных данных. Эти спецификации должны включать начальные условия и граничные условия, которые связаны с математическими моделями и вычислительным моделированием, в дополнение к используемым уравнениям или формулам. Некоторые задачи не имеют точных решений. Такие задачи должны быть проанализированы на предмет способов получения приближенных решений, определения качества этих решений и необходимой степени точности. Побочные эффекты, различные варианты и возможные исключительные случаи также должны быть рассмотрены. Как только проблема будет четко понята и соответствующие побочные эффекты будут решены, можно начинать программирование [13.].

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

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

После того, как задача была четко сформулирована и проанализирована, а данные уточнены, решение может быть разработано [13.]. Оно включает в себя проектирование ввода, вывода, внутренних данных, разработку алгоритма и разработку тестовых данных для алгоритма. Например, компьютер должен знать, состоят ли значения данных из целых или действительных чисел и находятся ли они в принятом десятичном или экспоненциальном формате. Он должен знать, сколько значений данных ожидается и как определить конец списка значений данных. Если алгоритм включает в себя повторные вычисления, предполагаемые предварительные условия и постусловия должны быть распознаны. На этапе проектирования алгоритм может быть представлен структурными схемами, псевдокодом и/или блок-схемами или другими методами логического представления.

Разработка программы для решения поставленной задачи

Постановка задачи и анализ предметной области

В качестве решаемой задачи рассмотрена разработка приложения для обучения работы с графической библиотекой объектно-ориентированного языка программирования высокого уровня C#. Анализ предметной области выполняется далее.

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

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

Методическая структура педагогических программных средств, которые характеризуют программированный подход к обучению, подразумевает наличие нескольких блоков [9.]:

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

Таким образом, можно определить следующие функции разрабатываемого приложения:

  • корректная презентация информации в виде совокупности разделов, каждый из которых состоит из теоретической либо практической части;
  • обеспечение проверки изученной информации;
  • сохранение материалов и результатов тестирования.

При разработке приложения учитывалась специфика выбранного учебного материала по изучению основ графической библиотеки языка. Основные положения легли в основу поставленной задачи. Теоретический блок представлен дополнительными материалами – файлами электронных книг по выбранной тематике.

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

Таким образом, разработка приложения для обучения является решением актуальной задачи создания прикладного программного обеспечения для повышения эффективности изучения объектно-ориентированного программирования.

Выбор языка программирования и среды разработки

C# был разработан в качестве конкурента языка Java; подразумевалось, что он будет чистым объектно-ориентированным языком программирования. C# дебютировал в 2000 году на конференции профессиональных разработчиков, где основным докладчиком был основатель Microsoft Билл Гейтс. В то же время была представлена среда разработки Visual Studio .NET.

Высокоуровневый язык программирования C# является флагманом разработки от Microsoft. Можно выделить следующие плюсы [12.] языка, отличающие его от конкурентов:

  1. Доступность

Если для Java необходимо отдельно устанавливать виртуальную машину, то .NET-разработка требует только .NET-платформы, которая есть на большинстве компьютеров с ОС Windows. Соответственно, оптимизация исполняемого кода ложится на платформу, что облегчает жизнь разработчика.

  1. Универсальность

Приложения C# функционируют на всех компьютерах с ОС Windows – притом можно указывать версию .NET Framework для работы с более ранними версиями. Среда разработки Xamarin также распространяет C# на Unix-системы, C# отныне является кроссплатформенным языком.

  1. Эргономичность

Поставляемые пакеты NuGet, интерактивное взаимодействие с объектами, ADO/OLE/Entity/ASP, интеллектуальная подсказка, одно из самых широчайших и полезных сообществ.

  1. Инновационность

С# стал флагманом не просто так – именно в нем реализуются многие особенности архитектуры программ, протоколов, принципов работы с памятью, структурами данных, подходов и принципов проектирования.

C# – отличный язык для корпоративных приложений, но у него есть некоторые недостатки. Поскольку C# является частью .NET Framework, сервер, на котором выполняется приложение, должен иметь Windows. Другими словами, любому приложению .NET требуется платформа Windows для выполнения. Многие новые компании работают с серверами Linux, поскольку это намного более дешевая среда. Microsoft перестает поддерживать старые платформы .NET после нескольких обновлений операционных систем. Например, старые серверы Windows 2000 могут поддерживать только приложения .NET 2.0. Хотя установка старой операционной системы кажется ошибкой, многие корпоративные организации сохраняют старые операционные системы из-за множества проблем, которые может привести к обновлению платформы. Основные обновления серверной архитектуры должны быть протестированы и утверждены перед развертыванием, что увеличивает время и затраты на разработку. Если организация использует рабочие станции и серверы Windows, .NET проще всего интегрировать. C# может использоваться для автоматизации, такой как Windows Services или веб-приложения.

Microsoft Visual Studio – это современная интегрированная среда, предназначенная для разработки программного обеспечения [4.]. Visual Studio включает в себя редактор исходного кода с поддержкой технологии IntelliSense и возможностью простейшего рефакторинга кода. Встроенный отладчик может работать как отладчик уровня исходного кода, так и отладчик машинного уровня. Присутствует удобный редактор форм для упрощения создания графического интерфейса приложения, веб-редактор, дизайнер классов и дизайнер схемы базы данных. Visual Studio позволяет создавать и подключать сторонние дополнения (плагины) для расширения функциональности практически на каждом уровне, включая добавление поддержки систем контроля версий исходного кода.

Основными преимуществами [4.] Visual Studio являются:

  • система проверки и дополнения ввода текста IntelliSense;
  • быстрый рефакторинг кода;
  • простая реализация общих задач и индивидуальный подход;
  • быстрое создание высококачественного кода;
  • возможность реализации идей и решений для широкого спектра платформ, включая Windows, Windows Server, веб-среду, облачную среду, Office и SharePoint;
  • огромное количество плагинов;
  • возможность интеграции проектов на разных языках;
  • поддержка множества языков, заточенных под необходимую задачу.

Главными недостатками среды является ее ориентированность на платформу .NET и тот факт, что точно так же, как и в случае с Windows, лицензия VS для коммерческих продуктов является платной.

Плюсы C# в целом перевешивают минусы, поэтому в качестве языка для разработки программного обеспечения был выбран именно этот язык программирования, более производительный и портативный.

Таким образом, в следующих разделах рассматривается разработка обучающей программы с тестовым контролем знаний, для создания которой был выбран язык программирования высокого уровня C#, а также интерфейс программирования приложений Windows.Forms, являющийся частью Microsoft .NET Framework. С помощью Windows.Forms можно создавать приложения с полнофункциональным графическим интерфейсом, в то же время простые в использовании и обновлении. Выбранный язык программирования вместе со средой разработки позволяет полностью реализовать программу, отвечающую всем предъявленным ей требованиям.

Этапы формализации и алгоритмизации

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

  • Главный модуль программы (MainForm – титульная форма с заставкой);
  • Тестовый модуль (TestForm – форма для прохождения итогового теста);
  • Модуль результатов (ResultsForm – форма для просмотра результатов тестирования).

Структурная схема разрабатываемого приложения приведена на рис. 1.

Рис. 1 – Структурная схема обучающей программы

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

Важнейшим алгоритмом тестового модуля является обработка подтверждения выбранного варианта ответа для текущего вопроса. В этом случае осуществляется переход к следующему вопросу теста; данные формы, в том числе заголовок, обновляются, а текст ответа добавляется в список выбранных ответов, который используется для просмотра результатов. При совпадении выбранного варианта с правильным счетчик верных ответов увеличивается. По окончании теста все вопросы можно распечатать. Блок-схема этого этапа приведена на рис.2.

Создание объекта формы для прохождения тестирования подразумевает получение данных из файла и добавление их на форму в процессе выполнения теста (рис. 3).

Печать вопросов теста выполняется встроенными средствами языка C# построчно (рис. 4).

Проектирование программы

Дополнительный учебный материал, используемый в приложении, представлен каталогом электронных книг по основам изучаемой темы. Книги в формате pdf расположены в директории по пути \bin\Debug\books. Как показано в листинге 1, обработчик кнопки для открытия каталога запускает ресурс системного процесса и связывает его с новым компонентом Process.

Листинг 1. Обработка кнопки «Дополнительные материалы»

private void addStuffButton_Click(object sender, EventArgs e)

{

Process.Start(Application.StartupPath + @"\books");

}

Рис. 1 – Фрагмент блок-схемы, описывающий обработку подтверждения ответа в тесте

Рис. 2 – Фрагмент блок-схемы, описывающий создание объекта формы для теста

Рис. 3 – Фрагмент блок-схемы, описывающий обработку печати

Структура приложения позволяет перейти к тестовому модулю из любого другого модуля программы. Вопросы и ответы для итогового теста загружаются из текстовых файлов «questions.txt» и «answers.txt», расположенных в директории по пути \bin\Debug. В листинге 2 приводятся все глобальные переменные этого модуля, необходимые для организации тестирования.

Листинг 2. Глобальные переменные класса TestForm

// путь к файлу с вопросами для теста:

string path = Application.StartupPath + @"/questions.txt",

// путь к файлу с номерами правильных ответов:

path2 = Application.StartupPath + @"/answers.txt",

path3 = "", // путь к файлу с результатами теста

name = "", // ФИО того, кто проходит тест

text = ""; // текст, считываемый из файла

// список строковых массивов, каждый из которых

// содержит вопрос, варианты ответа и правильный ответ:

List<string[]> test = new List<string[]>();

// список строк - выбранных ответов:

List<string> checkedAnswers = new List<string>();

int j = 0, // номер текущего вопроса

checkedAnswer = 1, // номер выбранного ответа

score = 0; // количество правильных ответов

Конструктор формы тестового модуля создает объект формы с компонентами, получает данные для теста из файла и загружает их на форму (см. рис. 3). Для этих целей предназначены функции FillTestInformation (листинг 3) и FillTestForm (листинг 4).

Листинг 3. Заполнение тестовой информации

private void FillTestInformation()

{

// считывание текста вопросов из файла:

text = File.ReadAllText(path);

// разбиение текста в массив строк, исключая пустые строки:

string[] ls = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

// считывание правильных ответов и разбиение в массив строк:

string[] rightAnswers = File.ReadAllText(path2).Split(new char[] { '[', ']', ',' }, StringSplitOptions.RemoveEmptyEntries);

// номер ячейки в массиве rightAnswers,

// содержащей правильный ответ на соответствующий вопрос:

int k = 1;

// Цикл по количеству считанных строк.

// Каждая пятая строка соответствует новому вопросу.

for (int i = 0; i < ls.Length; i += 5)

{

// получение строки вопроса:

string q = ls[i].Split(')')[1];

// получение строки с первым вариантом ответа:

string var1 = ls[i + 1].Split(')')[1];

// получение строки cо вторым вариантом ответа:

string var2 = ls[i + 2].Split(')')[1];

// получение строки с третьим вариантом ответа:

string var3 = ls[i + 3].Split(')')[1];

// получение строки с четвертым вариантом ответа:

string var4 = ls[i + 4].Split(')')[1];

// добавление массива строк в список:

test.Add(new string[6] { q, var1, var2, var3, var4, rightAnswers[k] });

k++; // переход к следующему правильному ответу

}

}

Листинг 4. Заполнение компонентов теста на форме

private void FillTestForm()

{

questionTextBox.Text = test.ElementAt(j)[0];

radioButton1.Text = test.ElementAt(j)[1];

radioButton2.Text = test.ElementAt(j)[2];

radioButton3.Text = test.ElementAt(j)[3];

radioButton4.Text = test.ElementAt(j)[4];

}

Обработка подтверждения ответа в тесте в соответствии с изображенным на рис. 2 фрагментом блок-схемы представлена в листинге 5.

Листинг 5. Обработка кнопки «Подтвердить»

private void acceptButton_Click_1(object sender, EventArgs e)

{

// получение правильного ответа для текущего вопроса:

int rightAnswer = int.Parse(test.ElementAt(j)[5]);

// добавление текста выбранного ответа в список:

checkedAnswers.Add(test.ElementAt(j)[checkedAnswer]);

// Если правильный ответ = выбранному, то

if (rightAnswer == checkedAnswer)

score++; // увеличить количество правильных ответов

// Если текущий вопрос не последний, то

if (j < test.Count - 1)

{

j++; // перейти к следующему вопросу

// и поменять заголовок формы

this.Text = "Вопрос " + (j + 1);

FillTestForm(); // ввести данные на форму

}

else // иначе

{

// строка с результатом:

string result = "Результат: " + score.ToString() + " правильных ответов из " + test.Count.ToString();

// процент правильных ответов:

double percentage = (double) score / test.Count * 100;

// если процент правильных ответов не превышает 40, // то оценка за тест = 2. Кнопка вывода результатов // по-прежнему неактивна.

if (percentage <= 40)

MessageBox.Show(result + "\n Ваша оценка: 2 (неудовлетворительно)");

else // иначе

// вывести оценку в зависимости от набранных баллов

// и сделать активной кнопку вывода результатов

{

if (percentage > 85)

MessageBox.Show(result + "\n Ваша оценка: 5 (отлично)");

if (percentage > 60 && percentage <= 85)

MessageBox.Show(result + "\n Ваша оценка: 4 (хорошо)");

if (percentage > 40 && percentage <= 60)

MessageBox.Show(result + "\n Ваша оценка: 3 (удовлетворительно)");

resultsButton.Enabled = true;

}

// сделать активной кнопку печати теста:

printTest.Enabled = true;

}

}

После прохождения теста его вопросы можно распечатать. В случае успешной сдачи теста (при получении любой оценки, кроме неудовлетворительной) также могут быть распечатаны результаты. Обработка печати приводится листинге 6.

Листинг 6. Обработка создания документа для печати теста или его результатов

private void printDocument2_PrintPage(object sender, PrintPageEventArgs e)

{

int charactersOnPage = 0; // число символов на странице

int linesPerPage = 0; // число строк на странице

//Установить значение числа символов charactersOnPage и //числа строк linesPerPage, которое будет соответствовать //границам страницы:

e.Graphics.MeasureString(text,this.Font, e.MarginBounds.Size, StringFormat.GenericTypographic, out charactersOnPage, out linesPerPage);

// Нарисовать строку в пределах границы страницы:

e.Graphics.DrawString(text,this.Font,Brushes.Black, e.MarginBounds, StringFormat.GenericTypographic);

// Удалить часть строки, которая была напечатана:

text = text.Substring(charactersOnPage);

// Проверить, нужно ли еще печатать страницы:

e.HasMorePages = (text.Length > 0);

}

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

Схема классов программы представлена на рис. 5.

Диаграмма прецедентов программы представлена на рис. 6.

Рис. 4 – Состав классов программы

Рис. 5 – Диаграмма прецедентов

Описание программы

Обучающая программа содержит три формы. На главной (титульной) форме приложения расположены кнопки для перехода к дополнительным материалам курса и итоговому тесту, а также заставка в виде gif-анимации. Здесь необходимо ввести фамилию, имя и отчество (ФИО) того, кто проходит тест, а также путь к файлу для записи результатов теста (при успешном прохождении). Вид формы приводится на рис. 7.

Вопросы и ответы итогового теста загружаются на тестовую форму из текстовых файлов «questions.txt» и «answers.txt», расположенных в директории по пути \bin\Debug. Вопросы теста имеют одиночный тип выбора ответов – варианты представлены радиокнопками, а непосредственный выбор осуществляется по нажатию на кнопку «Подтвердить». Кроме того, теоретическая форма содержит кнопку возврата к главной форме программы, а также кнопки для печати вопросов и просмотра результатов, которые неактивны во время прохождения теста. Вид формы после ответа на последний тестовый вопрос приведен на рис. 8.

Рис. 6 – Вид главной формы приложения

По окончании прохождения теста его вопросы можно распечатать и выполнить сохранение результатов в текстовый файл с именем, заданным на главной форме программы. В случае оценки 3 и выше доступен переход к форме с результатами (рис. 9). После нажатия на кнопку просмотра ответов результаты будут записаны в заданный в начале программы текстовый файл (рис. 10).

Рис. 7 – Вид тестовой формы после ответа на последний вопрос теста

Рис. 8 – Вид тестовой формы после успешного прохождения теста

Рис. 9 – Вид тестовой формы после нажатия на кнопку просмотра ответов

Форма для просмотра результатов теста содержит кнопки возврата к главной форме приложения и к тестовой форме, а также кнопку для печати результатов тестирования. Вид формы приведен на рис. 11.

Рис. 10 – Вид формы для просмотра результатов тестирования

ЗАКЛЮЧЕНИЕ

В ходе выполнения работы были подробно рассмотрены основные этапы разработки программ, получено представление о понятиях алгоритма, программы и данных.

В рамках данной курсовой работы также были выполнены все этапы разработки программы: подробно проанализирована рассмотренная предметная область, спроектирован пользовательский интерфейс обучающего приложения с интуитивно-понятным для пользователя управлением, а также описаны его основные алгоритмы. Результатом выполнения работы является созданный на языке высокого уровня C# с помощью интерфейса программирования приложений Windows.Forms программный продукт для обучения графической библиотеке языка C#, который является полностью функциональным (все необходимые функции в нем реализованы). Несмотря на это, допускается его дальнейшая модернизация как в плане пользовательского интерфейса, так и с точки зрения функциональных и алгоритмических возможностей в следующей версии приложения. В качестве одного из возможных усовершенствований может выступать модуль регистрации пользователей с хранением допустимых в системе тестирования логинов и паролей, принцип работы которого основан на записи и чтении из файла ос­новной информации о пользователях программы.

Таким образом, все цели и задачи курсовой работы выполнены в полном объеме.

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

  1. Аршинов М. Н. Коды и математика / М.: Наука, 1983. – 257 с.
  2. Буркатовская Ю. Б. Быстродействующие алгоритмы деления полиномов в арифметике по модулю два / Ю. Б. Буркатовская, А. Н. Мальчуков, А. Н. Осокин // Изв. Томск. политехн. ун-та. – 2006. – № 1 (309). – с. 19–24.
  3. Демидович, Е.М. Основы алгоритмизации и программирования. Учебное пособие / Е. М. Демидович. - 2-е изд., испр. и доп. - СПб. : БХВ - Петербург, 2008. - 440 с.
  4. Документация по семейству продуктов Visual Studio [Электронный ресурс]. – Режим доступа: https://docs.microsoft.com/ru-ru/visualstudio/?view=vs-2019 – (Дата обращения – 15.06.2020).
  5. Коробейников А. Г, Ю.А.Гатчин. Математические основы криптологии. Учебное пособие / СПб: СПб ГУ ИТМО, 2004. – 106 с.
  6. Коутинхо С. Введение в теорию чисел. Алгоритм RSA / М.: Постчаркет, 2001. – 328 с.
  7. Мыцко Е. А. Особенности программной реализации вычисления контрольной суммы CRC32 на примере PKZIP, WINZIP, ETHERNET / Е. А. Мыцко, А. Н. Мальчуков // Вестн. науки Сибири. – 2011. – № 1 (1). – с. 279–282.
  8. Олифер В. Г. Компьютерные сети. Принципы, технологии, протоколы / В. Г. Олифер, Н. А. Олифер. ‒ СПб.: Питер, 2008. ‒ 958 с.
  9. Темников Ф. Е. Теоретические основы информационной техники: учеб. пособие. – 2-е изд., испр. и доп. / Ф. Е. Темников, В. А. Афонин, В. И. Дмитриев. – М.: Энергия, 1979. – 512 с.
  10. Яковлев В. В. Оценка влияния помех на производительность протоколов канального уровня / В. В. Яковлев, Ф. И. Кушназаров // Изв. Петерб. гос. ун-та путей сообщения. – СПб.: ПГУПС, 2015. – Вып. 1 (42). – с. 133–138.
  11. Arthur-Durett K. The Weakness Of Winrar Encrypted Archives To Compression Side-channel Attack, Open Access Theses, Purdue University, 2014
  12. C# docs [Электронный ресурс]. – Режим доступа: https://docs.microsoft.com/ru-ru/dotnet/csharp/ – (Дата обращения – 16.06.2020).
  13. Systems Engineering and Software Development Life Cycle Framework [Электронный ресурс]. – Режим доступа: http://opensdlc.org/mediawiki/index.php?title=Main_Page – (Дата обращения – 15.06.2020).

Приложение 1. Исходные коды программ

Листинг А1. Исходный код модуля MainForm.cs

using System;

using System.Diagnostics;

using System.Windows.Forms;

namespace TeachingApp

{

// Главная форма (меню выбора)

public partial class MainForm : Form

{

/*

* Конструктор формы - создает объект формы с находящимися на нем компонентами

*/

public MainForm()

{

InitializeComponent();

}

/*

* Обработчик закрытия формы - выполняет выход из приложения

*/

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)

{

Application.Exit();

}

/*

* Обработчик кнопки "Дополнительные материалы" - открывает папку books при помощи системного процесса

*/

private void addStuffButton_Click(object sender, EventArgs e)

{

Process.Start(Application.StartupPath + @"\books");

}

/*

* Обработчик кнопки "Итоговый тест"

*/

private void testButton_Click(object sender, EventArgs e)

{

// получаем ФИО и путь к файлу для записи результатов из формы:

string name = nameTextBox.Text;

string path = resultPathTextBox.Text;

// проверяем, что данные введены:

if (string.IsNullOrEmpty(name))

{

MessageBox.Show("ФИО не заданы!", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Error);

return;

}

if (string.IsNullOrEmpty(path))

{

MessageBox.Show("Имя выходного файла не задано!", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Error);

return;

}

TestForm test = new TestForm(name, path); // создаем новую форму для прохождения теста

test.Show(); // показываем ее

this.Dispose(false); // уничтожаем текущую форму

}

}

}

Листинг А2. Исходный код модуля TestForm.cs

using System;

using System.Collections.Generic;

using System.Drawing;

using System.Drawing.Printing;

using System.IO;

using System.Linq;

using System.Windows.Forms;

namespace TeachingApp

{

// Форма для прохождения тестирования

public partial class TestForm : Form

{

string path = Application.StartupPath + @"/questions.txt", // путь к файлу с вопросами для теста

path2 = Application.StartupPath + @"/answers.txt", // путь к файлу с номерами правильных ответов

path3 = "", // путь к файлу с результатами теста

name = "", // ФИО того, кто проходит тест

text = ""; // текст, считываемый из файла

List<string[]> test = new List<string[]>(); // тест - список строковых массивов, каждый из которых содержит вопрос, варианты ответа и правильный ответ

List<string> checkedAnswers = new List<string>(); // список строк - выбранных ответов

int j = 0, // номер текущего вопроса

checkedAnswer = 1, // номер выбранного ответа

score = 0; // количество правильных ответов

/*

* Функция заполнения тестовой информации

*/

private void FillTestInformation()

{

text = File.ReadAllText(path); // считывание текста вопросов из файла

string[] ls = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); // разбиение текста в массив строк, исключая пустые строки

string[] rightAnswers = File.ReadAllText(path2).Split(new char[] { '[', ']', ',' }, StringSplitOptions.RemoveEmptyEntries); // считывание правильных ответов и разбиение в массив строк

int k = 1; // номер ячейки в массиве rightAnswers, содержащей правильный ответ на соответствующий вопрос (индексируется с единицы, т.к. rightAnswers[0] содержит строку текста, предшествующую числовым значениям

// Цикл по количеству считанных строк. Каждая пятая строка соответствует новому вопросу.

for (int i = 0; i < ls.Length; i += 5)

{

string q = ls[i].Split(')')[1]; // получение строки вопроса

string var1 = ls[i + 1].Split(')')[1]; // получение строки с первым вариантом ответа

string var2 = ls[i + 2].Split(')')[1]; // получение строки cо вторым вариантом ответа

string var3 = ls[i + 3].Split(')')[1]; // получение строки с третьим вариантом ответа

string var4 = ls[i + 4].Split(')')[1]; // получение строки с четвертым вариантом ответа

test.Add(new string[6] { q, var1, var2, var3, var4, rightAnswers[k] }); // добавление массива строк в список

k++; // переход к следующему правильному ответу

}

}

/*

* Функция заполнения компонентов теста на форме

*/

private void FillTestForm()

{

questionTextBox.Text = test.ElementAt(j)[0];

radioButton1.Text = test.ElementAt(j)[1];

radioButton2.Text = test.ElementAt(j)[2];

radioButton3.Text = test.ElementAt(j)[3];

radioButton4.Text = test.ElementAt(j)[4];

}

/*

* Конструктор формы - создает объект формы с находящимися на нем компонентами

*/

public TestForm(string nm, string pth)

{

this.name = nm;

this.path3 = pth;

InitializeComponent();

FillTestInformation(); // получаем данные теста из файла

FillTestForm(); // вводим данные на форму

this.Text = "Вопрос 1"; // меняем заголовок формы

}

/*

* Обработчик закрытия формы - выполняет выход из приложения

*/

private void TestForm_FormClosing(object sender, FormClosingEventArgs e)

{

Application.Exit();

}

/*

* Обработчик кнопки "Вернуться к стартовой форме"

*/

private void backToMenuButton_Click(object sender, EventArgs e)

{

MainForm mf = new MainForm(); // создаем новую форму для ввода ФИО

mf.Show(); // показываем ее

this.Dispose(false); // уничтожаем текщую форму

}

/*

* Обработчик кнопки "Посмотреть ответы"

*/

private void resultsButton_Click(object sender, EventArgs e)

{

ResultsForm rf = new ResultsForm(name, path3, test, checkedAnswers); // создаем объект формы результатов теста

rf.Show(); // показываем ее

this.Dispose(false); // уничтожаем текущую форму

}

/*

* Обработчик создания документа для печати теста

*/

private void printDocument2_PrintPage(object sender, PrintPageEventArgs e)

{

int charactersOnPage = 0; // число символов на странице

int linesPerPage = 0; // число строк на странице

// Устанавливаем значение числа символов charactersOnPage и числа строк linesPerPage, которое будет соответствовать границам страницы.

e.Graphics.MeasureString(text, this.Font,

e.MarginBounds.Size, StringFormat.GenericTypographic,

out charactersOnPage, out linesPerPage);

// Рисуем строку в пределах границы страницы

e.Graphics.DrawString(text, this.Font, Brushes.Black,

e.MarginBounds, StringFormat.GenericTypographic);

// Удаляем часть строки, которая была напечатана

text = text.Substring(charactersOnPage);

// Проверяем, нужно ли еще печатать страницы

e.HasMorePages = (text.Length > 0);

}

/*

* Обработчик печати теста

*/

private void printTest_Click(object sender, EventArgs e)

{

printDocument2.Print();

}

/*

* Обработчик кнопки "Подтвердить"

*/

private void acceptButton_Click_1(object sender, EventArgs e)

{

int rightAnswer = int.Parse(test.ElementAt(j)[5]); // получение правильного ответа для текущего вопроса

checkedAnswers.Add(test.ElementAt(j)[checkedAnswer]); // добавление текста выбранного ответа в список

// Если правильный ответ = выбранному, то

if (rightAnswer == checkedAnswer)

score++; // увеличиваем количество правильных ответов

// Если текущий вопрос не последний,

if (j < test.Count - 1)

{

j++; // переходим к следующему вопросу

this.Text = "Вопрос " + (j + 1); // меняем заголовок формы

FillTestForm(); // вводим данные на форму

}

else // иначе

{

string result = "Результат: " + score.ToString() + " правильных ответов из " + test.Count.ToString(); // строка с результатом

double percentage = (double) score / test.Count * 100; // процент правильных ответов

if (percentage <= 40) // если процент правильных ответов не превышает 40, то оценка за тест = 2. Кнопка вывода результатов по-прежнему неактивна.

MessageBox.Show(result + "\n Ваша оценка: 2 (неудовлетворительно)");

else // иначе выводим оценку в зависимости от набранных баллов и делаем активной кнопку вывода результатов

{

if (percentage > 85)

MessageBox.Show(result + "\n Ваша оценка: 5 (отлично)");

if (percentage > 60 && percentage <= 85)

MessageBox.Show(result + "\n Ваша оценка: 4 (хорошо)");

if (percentage > 40 && percentage <= 60)

MessageBox.Show(result + "\n Ваша оценка: 3 (удовлетворительно)");

resultsButton.Enabled = true; // делаем активной кнопку вывода результатов

}

printTest.Enabled = true; // делаем активной кнопку печати теста

}

}

/*

* Обработчик события изменения выбранного варианта ответа

*/

private void radioButtons_CheckedChanged(object sender, EventArgs e)

{

// Получение выбранного номера ответа по тегу соответствующей радиокнопки

checkedAnswer = int.Parse((sender as RadioButton).Tag.ToString());

}

}

}

Листинг А3. Исходный код модуля ResultsForm.cs

using System;

using System.Collections.Generic;

using System.Drawing;

using System.IO;

using System.Linq;

using System.Windows.Forms;

namespace TeachingApp

{

// Форма для просмотра результатов тестирования

public partial class ResultsForm : Form

{

string text = "", // печатаемый текст

path = "", // путь к файлу с результатами теста

name = ""; // ФИО того, кто проходит тест

/*

* Конструктор формы - создает объект формы с находящимися на нем компонентами

*/

public ResultsForm(string nm, string pth, List<string[]> test, List<string> checkedAnswers)

{

this.name = nm;

this.path = pth;

InitializeComponent();

resultsTextBox.Text += "ФИО: " + name; // добавление строки с ФИО того, кто проходил тест

resultsTextBox.Text += Environment.NewLine; // переход на новую строку

// Цикл по количеству вопросов в тесте

for (int i = 0; i < test.Count; i++)

{

resultsTextBox.Text += "Вопрос " + (i + 1) + ": " + test.ElementAt(i)[0]; // добавление строки вопроса

resultsTextBox.Text += Environment.NewLine; // переход на новую строку

resultsTextBox.Text += "Варианты ответов: ";

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += "а) " + test.ElementAt(i)[1]; // добавление первого варианта ответа

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += "б) " + test.ElementAt(i)[2]; // добавление второго варианта ответа

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += "в) " + test.ElementAt(i)[3]; // добавление третьего варианта ответа

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += "г) " + test.ElementAt(i)[4]; // добавление четвертого варианта ответа

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += "Ваш ответ: " + checkedAnswers.ElementAt(i); // добавление текста выбранного ответа

resultsTextBox.Text += Environment.NewLine;

int number = int.Parse(test.ElementAt(i)[5]); // нахождение номера правильного ответа

resultsTextBox.Text += "Правильный ответ: " + test.ElementAt(i)[number]; // добавление текста правильного ответа

resultsTextBox.Text += Environment.NewLine;

resultsTextBox.Text += Environment.NewLine; // доп. пустая строка между вопросами

}

text = resultsTextBox.Text;

StreamWriter sw = new StreamWriter(path);

sw.Write(text);

sw.Close();

MessageBox.Show("Результаты записаны в файл " + path + "!", "Сообщение", MessageBoxButtons.OK, MessageBoxIcon.Information);

}

/*

* Обработчик закрытия формы - выполняет выход из приложения

*/

private void ResultsForm_FormClosing(object sender, FormClosingEventArgs e)

{

Application.Exit();

}

/*

* Обработчик кнопки "Вернуться к стартовой форме"

*/

private void backToMenuButton_Click(object sender, EventArgs e)

{

MainForm mf = new MainForm(); // создаем новую форму для ввода ФИО

mf.Show(); // показываем ее

this.Dispose(false); // уничтожаем текущую форму

}

/*

* Обработчик кнопки "Вернуться к прохождению теста"

*/

private void textButton_Click(object sender, EventArgs e)

{

TestForm test = new TestForm(name, path); // создаем новую форму для прохождения теста

test.Show(); // показываем ее

this.Dispose(false); // уничтожаем текущую форму

}

/*

* Обработчик создания документа для печати теста

*/

private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)

{

int charactersOnPage = 0; // число символов на странице

int linesPerPage = 0; // число строк на странице

// Устанавливаем значение числа символов charactersOnPage и числа строк linesPerPage, которое будет соответствовать границам страницы.

e.Graphics.MeasureString(text, this.Font,

e.MarginBounds.Size, StringFormat.GenericTypographic,

out charactersOnPage, out linesPerPage);

// Рисуем строку в пределах границы страницы

e.Graphics.DrawString(text, this.Font, Brushes.Black,

e.MarginBounds, StringFormat.GenericTypographic);

// Удаляем часть строки, которая была напечатана

text = text.Substring(charactersOnPage);

// Проверяем, нужно ли еще печатать страницы

e.HasMorePages = (text.Length > 0);

}

/*

* Обработчик печати результатов теста

*/

private void printButton_Click(object sender, EventArgs e)

{

printDocument1.Print();

}

}

}