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

Разработка программ с графическим интерфейсом на С++ (Особенности объектно-ориентированной парадигмы программирования)

Содержание:

ВВЕДЕНИЕ

Разработка прикладного программного обеспечения (ПО) включает в себя концепцию взаимодействия человека с компьютером, и в этой области программы очень важен графический пользовательский интерфейс (Graphical User Interface – GUI). Визуальные виджеты, такие как флажки и кнопки, используются для управления информацией, имитирующей взаимодействие с программой. Хорошо продуманный графический интерфейс дает гибкую структуру, в которой сам интерфейс не зависит от функциональности приложения, но напрямую связан с ней. Это качество прямо пропорционально удобству использования приложения.

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

1980-е годы были революционными для GUI на всех платформах. Xerox Star и Apple Lisa представили основные функциональные возможности – от панели меню, элементов управления окнами, двойного щелчка значков до диалоговых окон и монохромных дисплеев. Эволюция и популярность пользовательского интерфейса продолжали выходить за рамки первоначальных идей. Его массовое использование сделало невозможным создание стандартного внешнего вида для GUI.

В конце XX и начале XXI века важную роль в визуализации данных при помощи программного обеспечения с графическим интерфейсом получили операционные системы (ОС). Как правило, запуск подобных программ осуществляется при помощи систем компании Microsoft. В то же время тенденция последних лет – использование кроссплатформенных средств для разработки программ – требует от разработчика предоставить пользователю возможность запустить готовый программный продукт на различных ОС, в том числе мобильных. Сегодня существует широкий спектр операционных систем, каждая из которых имеет популярный и узнаваемый графический интерфейс. Microsoft Windows и Mac OS X отлично подходят для ноутбуков и настольных компьютеров, а Android, Apple iOS и Windows Phone предоставляют известные графические интерфейсы для мобильных устройств.

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

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

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

Особенности объектно-ориентированной парадигмы программирования

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

Инструкции первых языков программирования, появившихся в начале 50-х годов XX века и ориентированных на конкретный компьютер, записывались в исходном коде и выполнялись последовательно. Данные, полученные при выполнении предыдущих инструкций, могли быть считаны из памяти или записаны в нее. Таким образом, программы представляли собой последовательность команд, которые должен был выполнить компьютер. Языки программирования, использующие этот подход (прежде всего, это машинные инструкции и язык ассемблера), образовали императивную парадигму программирования. В отличие от декларативного подхода, при котором задается спецификация решения задачи, в императивном широко используются операторы присваивания. Ранние императивные языки сложны для понимания и решения прикладных задач.

Развитие вычислительных устройств и компьютерной техники привело к появлению процедурных языков. Процедурные языки программирования, первые реализации которых относятся к концу 50-х годов, позволили разбивать задачи на шаги и решать их шаг за шагом, причем возможность определять каждый шаг в процессе решения задачи была предоставлена программисту. Эти языки использовали императивную парадигму, но последовательно выполняемые операторы могли быть собраны в подпрограммы, то есть более крупные целостные единицы кода, с помощью самого языка. Согласно некоторым классификациям, такой подход выделяется в самостоятельную парадигму, получившую название процедурной. К процедурным языкам программирования относятся, например, Паскаль, Си, Алгол, КОБОЛ и Фортран.

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

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

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

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

  1. Построением языка программирования, содержащего как можно больше типов данных, и выбором для каждого класса задач некоторого подмножества этого языка. Такой язык иногда называют языком-оболочкой. На роль языка-оболочки претендовал язык ПЛ/1, оказавшийся настолько сложным, что так и не удалось построить его формализованное описание. Отсутствие формализованного описания, однако, не помешало широкому применению ПЛ/1 как в Западной Европе, так и в СССР.
  2. Построением расширяемого языка, содержащего небольшое ядро и допускающего расширение, дополняющее язык типами данных и операторами, отражающими концептуальную сущность конкретного класса задач. Такой язык называют языком-ядром. Как язык-ядро были разработаны языки Симула и Алгол-68, не получившие широкого распространения, но оказавшие большое влияние на разработку других языков программирования.

Дальнейшим развитием второго пути явился объектно-ориентированный подход к программированию.

Основные идеи объектно-ориентированного подхода опираются на следующие положения:

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

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

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

Классы объектов часто удобно строить так, чтобы они образовывали иерархическую структуру. Например, класс “Студент”, описывающий абстрактного студента, может служить основой для построения классов “Студент 1 курса”, “Студент 2 курса” и т.д., которые обладают всеми свойствами студента вообще и некоторыми дополнительными свойствами, характеризующими студента конкретного курса. При разработке интерфейса с пользователем программы могут использовать объекты общего класса “Окно” и объекты классов специальных окон, например, окон информационных сообщений, окон ввода данных и т.п. В таких иерархических структурах один класс может рассматриваться как базовый для других, производных от него классов. Объект производного класса обладает всеми свойствами базового класса и некоторыми собственными свойствами, он может реагировать на те же типы сообщений от других объектов, что и объект базового класса и на сообщения, имеющие смысл только для производного класса. Обычно говорят, что объект производного класса наследует все свойства своего базового класса.

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

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

В С++ (и во многих других объектно-ориентированных алгоритмических языках, например, в Объектном Паскале) вводится новый тип данных – класс. Переменная типа класс называется объектом. Иногда объект называют также экземпляром класса. Формально описание класса напоминает структуру, но класс, кроме полей (переменных), содержит методы, которые задают допустимые действия над полями класса. Общее название для полей и методов – элементы класса.

В листинге 1 дается простейшее описание класса на языке С++.

Листинг 1. Описание класса на языке C++

class имя_класса {

private:

описание личных элементов класса

public:

описание общих элементов класса

};

Под личными элементами класса (private) понимаются такие элементы, которые могут использоваться только методами своего класса. К общим элементам класса (public) доступ разрешен в любом месте программы. Существуют и другие способы доступа к элементам класса.

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

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

Если внутри класса метод описан прототипом:

тип_результата имя_метода (список типов параметров),

то при полном описании вне класса метод имеет заголовок:

тип_результата имя_класса::имя_метода (список параметров),

т. е. в заголовке перед именем метода указывается имя класса (через знак ::).

Существуют особые методы класса: конструкторы и деструкторы. Назначение конструктора заключается в создании экземпляра класса и инициализации его полей. Имя конструктора совпадает с именем класса. Конструктор никогда не вызывается явно, его вызов осуществляется компилятором в момент создания экземпляра класса.

Деструктор вызывается для уничтожения экземпляра класса. Имя деструктора образуется как ~имя_класса. Деструктор может вызываться в программе явно или (что происходит обычно) его вызов обеспечивается компилятором в момент уничтожения экземпляра класса.

Наличие конструктора и деструктора для любого класса обязательно; при их отсутствии компилятор автоматически создает стандартные варианты конструктора и деструктора.

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

имя_класса имя_экземпляра(параметры конструктора);

Перед созданием динамического экземпляра класса (по аналогии с любыми динамическими переменными) необходимо объявить указатель на экземпляр:

имя_класса* указатель_на_экземпляр;

Динамический экземпляр класса создается с помощью оператора new, а уничтожается с помощью оператора delete:

указатель_на_экземпляр= new имя_класса (параметры конструктора);

delete указатель_на_экземпляр;

Метод класса (по аналогии с полем структуры) вызывается одним из следующих способов:

имя_экземпляра.имя_метода или имя_экземпляра->имя_метода

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

При идеальном выполнении принципа инкапсуляции поля класса могут быть только личными (private).

Ниже перечислены уровни инкапсуляции, т. е. уровни доступа к элементам класса:

  • private (личный). Этот уровень накладывает самые жесткие ограничения на доступ к элементам класса. Именно эти элементы могут быть использованы только методами данного класса. Как правило, поля класса объявляются private.
  • public (общий). Элементы класса данного уровня доступны из любой точки программы (самый «широкий» доступ).
  • protected (защищенный). Элементы класса данного класса доступны методам данного класса и его наследников.

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

Как правило, базовый класс является общим, производные – более специальными, конкретными. Естественно, у класса-наследника обычно больше полей и методов, чем у класса-предка, так как при наследовании обычно добавляются новые элементы.

Если имеется иерархия классов, то можно рассматривать защищенные (protected) элементы класса, которые доступны для методов своего класса и его наследников.

Наследование может быть единичным (наследник имеет одного предка) и множественным (количество предков больше 1). В Си++ допустимо множественное наследование.

Наследование может быть общим, личным и защищенным.

Видимость полей и функций базового класса из производного определяется секцией, в которой находится объявление компонента, и видом наследования (таблица 1):

Таблица 1. Видимость компонентов базового класса в производном

Вид наследования

Объявление компонентов в базовом классе

Видимость компонентов в производном классе

private

не доступны

private

protected

private

public

private

private

не доступны

protected

protected

protected

public

protected

private

не доступны

public

protected

protected

public

public

Как видно из таблицы 1, при общем наследовании общие и защищенные элементы класса-предка сохраняют свой уровень инкапсуляции и в классе-наследнике. При личном наследовании общие и защищенные элементы класса-предка становятся личными для класса-наследника. При защищенном наследовании защищенные элементы сохраняют свой уровень в классе-наследнике, а общие становятся защищенными. Независимо от вида наследования, личные элементы базового класса недоступны в производных классах. Таким образом, чтобы «достать» их из производного класса, надо использовать унаследованные общие и защищенные методы класса-предка.

Описание производного класса в общем виде:

class Имя_производного_класса:

Вид_наследования_1 Имя_базового_класса_1,

Вид_наследования_2 Имя_базового_класса_2,

...

Вид_наследования_n Имя_базового_класса_n,

{

Описание_добавляемых_элементов_производного_класса

};

Если Вид_наследования не указан, то по правилу умолчания принимается public.

Самая простая ситуация — это единичное общее наследование. Заголовок производного класса в этом случае имеет вид:

class имя_наследника: public имя предка; // можно без public

Современные способы построения интерфейсов

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

Для языка программирования C++ как наиболее популярного средства разработки ПО на сегодняшний день имеются несколько способов построения интерфейсов клиентских приложений. Основными операционными системами, используемыми для этой цели, являются Microsoft Windows (MS Windows) и Linux. Главным средством разработки программ для ОС семейства Windows является интегрированная среда разработки (IDE) MS Visual Studio (VS) с основными языками C++ и C#. Точно так же, как и в случае с Windows, лицензия VS для коммерческих продуктов является платной.

Программисты имеют долгую историю разработки приложений с GUI под Windows с использованием языков C и C++. Первые опыты восходят к временам Windows 2.0, когда использовался 16-битный API Windows на основе C, и для отображения окна требовались десятки строк кода. С годами уровень абстракции становился все выше и лучше. В 1992 году Microsoft выпустила библиотеку классов Microsoft Foundation версии 1.0 в составе Workbench для программистов. В выпусках версий Microsoft Windows 3.X операционная система использовала библиотеку, называемую Win16, которая содержала все необходимые функции и объекты, используемые для создания приложений с графическим интерфейсом пользователя. Эта библиотека немного облегчила «общение» с операционной системой и создание довольно привлекательных приложений [1.].

Через некоторое время Microsoft выпустила Microsoft Windows 95, а затем Windows 98. Библиотека операционной системы также была обновлена ​​до Win32.

Поскольку использование Win32 требовало хорошего уровня понимания и работы, Microsoft выпустила настроенную версию библиотеки Win32, чтобы ее было легче понять. Библиотека Microsoft Foundation Class (MFC) Library версии 1.0 представляла собой набор из порядка 60 классов, предназначенных для оборачивания оконных частей и элементов рисования 16-разрядного API Windows. Win32 была написана на C, и MFC создавалась написана для разработчиков на C / C++ [5.]. Чтобы сделать программирование под Windows доступным для всех, Microsoft создала Microsoft Visual Basic как настоящую среду графического программирования. Visual Basic использовала другой, более простой язык, называемый Basic, как основу. Первым следствием их этого было то, что Visual Basic по своей сути не «понимал» Win32. Чтобы позволить программистам Visual Basic использовать то, что было доступно в Win32, его программисты должны были импортировать необходимые функции. Это привело к тому, что программисты Visual C++ использовали одну библиотеку, а программисты Visual Basic – другую; это только одна из многих проблем [2.].

К 2002 году MFC Library версии 7.0 увеличилась до более чем 200 классов. Несмотря на то, что MFC являлась мощным средством, во многих местах она страдала от того, что является лишь тонким слоем по сравнению с Win32 API, а также для многих программистов трудной для эффективного использования. Прямой доступ к Win32 API был все еще необходим для разработки приложений Windows, особенно потому, что планка базовых функций, необходимых для приложений Windows, продолжала расти. Как следствие, разработка любого нетривиального приложения с графическим интерфейсом Windows отнимала много времени и усилий. В то же время с ростом Интернета, клиент-серверных приложений, требовательных баз данных, коммуникационного программного обеспечения и т.д. Microsoft решила создать новую библиотеку, которая будет понятна и будет использоваться многими различными языками.

Чтобы решить растущие проблемы в разработке приложений, в начале 2002 года Microsoft выпустила новую среду программирования для платформы Windows. Эта среда, известная как .NET Framework, предоставила управляемую среду выполнения для приложений, а также большой набор библиотек, известный как библиотека классов .NET Framework для разработчиков. .NET Framework управляет памятью и безопасностью, что делает приложения более надежными. Библиотека классов .NET Framework предоставляет обширную, богатую и унифицированную библиотеку классов, доступную одинаково для любого языка .NET, включая Managed Extensions для C++ – управляемой версии C++, которую Microsoft предоставляет программистам .NET. Часть .NET Framework, Windows Forms (WinForms), представляет собой набор классов для создания клиентских приложений Windows [1.,3.]. Альтернативой WinForms является Windows Presentation Foundation (WPF), ставшая популярной с появлением более современных версий ОС (таких как Windows 7 и Windows 8). Microsoft также разработала другие языки, такие как C#, J#, JScript, и другие среды программирования, которые использовали эти языки, также являющиеся частью семейства, совместно использующего библиотеку .NET Framework.

Наиболее подходящим вариантом для низкобюджетных проектов остается операционная система Linux. Кроме того, что большинство дистрибутивов этой ОС являются свободно распространяемыми, до сих пор имеется ряд бесплатных средств для разработки ПО для этой системы. Одним из наиболее распространенных средств для программирования на языках C, C++ и QML является кроссплатформенная свободная IDE под названием Qt Creator. Эта среда была разработана Trolltech (Digia) для работы с фреймворком Qt; первоначальное кодовое название – Greenhouse. Qt Creator включает в себя графический интерфейс отладчика и визуальные средства разработки интерфейса как с использованием виджетов QtWidgets (аналог WinForms), так и QML. Альтернативой WPF является Qt Quick. Qt Creator платный для закрытых проектов.

Для дальнейшего изучения и создания некорпоративного приложения была выбрана среда разработки Microsoft Visual Studio 2010 с инструментарием WinForms.

Visual Studio и Windows Forms

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

Большая часть работы с пользовательским интерфейсом включает понимание кода, который объединяет все элементы вместе. VS предварительно генерирует этот код, упрощая работу программиста. После того, как весь дизайн и функциональность будут завершены, автоматически будет создан файл с расширением *.exe для запуска программы внутри и вне VS.

Прикладное программирование в основном состоит из объектов, называемых элементами управления. Эти элементы управления используются пользователями разрабатываемого приложения для взаимодействия с компьютером. Одна из задач разработчика приложения состоит в выборе необходимых объектов, добавления их в приложение и последующей настройки их поведения [4.].

Windows Forms – это средство для работы с окнами, а не полноценный фреймворк для создания приложений, такой как MFC, который предоставляет больше возможностей, чем Windows Forms, для создания автономных приложений на основе документов [4.]. Например, для создания текстового редактора при помощи MFC необходимо выбрать правильные параметры и написать всего несколько строк кода. Приложение будет включать в себя панель состояния, панель инструментов (плавающая), все реализованные пункты меню «Файл», «Редактировать» и «Справка», в том числе список использованных файлов, справку по печати и контекстную справку. Однако вместо создания приложений на основе документов программисты стремятся создавать больше приложений на основе HTML или приложений, которые взаимодействуют с бизнес-объектами или серверами баз данных. Именно для этого используются .NET Framework и Windows Forms.

Это не значит, что Windows Forms нельзя использовать для создания хороших приложений на основе документов. Фактически, поскольку Windows Forms – это всего лишь небольшая часть из более чем 2000 классов, представленных в .NET Framework, вполне вероятно, что, если что-то не представлено в Windows Forms, оно предоставляется где-то еще в .NET Framework. Например, сама Windows Forms не предоставляет никакой поддержки сериализации, но остальная часть библиотеки классов .NET Framework предоставляет несколько способов сериализации объектов [1.].

В этом главное отличие MFC от Windows Forms. MFC задумывался как замена базового Win32 API, но это не помешало росту Win32 API. Фактически, поскольку MFC рос за эти годы, функциональность базовой ОС увеличилась как минимум в десять раз. Windows Forms, с другой стороны, предназначен для замены только оконной части Win32 [4.]. Конечно, Framework никогда не заменит весь Win32 API, но так как большинство новых функциональных возможностей, добавленных в Windows в обозримом будущем, будут добавлены в Framework, это выход. Таким образом, хотя Windows Forms не может делать все, что делает MFC, он предоставляет впечатляющий набор функций, которые могут упростить жизнь разработчикам приложений на стороне клиента, включая вещи, которые MFC вообще не делает.

В приложении Windows Forms используются две широкие категории объектов: формы и элементы управления. Объекты, используемые в приложении Windows Forms, хранятся в библиотеках, также называемых сборками. Как и обычные библиотеки, эти сборки имеют расширение .dll (что означает динамически подключаемую библиотеку). Чтобы использовать один из этих объектов, нужно знать имя сборки, в которой он хранится. Затем необходимо добавить ссылку на эту сборку в создаваемом приложении.

Типичное приложение Windows Forms имеет как минимум одну форму. Форма – это просто окно, которое является единицей пользовательского интерфейса, которая обнаруживаются у Microsoft начиная с Windows 1.0 [6.]. Единственная форма в приложении Windows Forms обычно является основной формой, что означает, что она является либо родительской, либо владельцем любой другой формы, которая может отображаться в течение жизненного цикла приложения. Здесь отображается главное меню, а также панель инструментов, панель состояния и т.д. Когда основная форма исчезает, приложение закрывается.

Основной формой приложения может быть простое окно с сообщением, диалоговое окно, окно SDI, окно MDI или что-то более сложное, например, в таких приложениях, как Visual Studio .NET, с несколькими дочерними окнами, окнами инструментов и плавающими панелями инструментов.

После того как создана очередная форма приложения, ее нужно подготовить к отображению на экране. Об этом позаботится класс Application, спроектированный для запуска приложения, обработки его сообщений, а также остановки приложения. Класс Application предоставляет перегруженный метод Run(), который можно использовать для запуска программы. Одна из версий этого метода принимает форму в качестве аргумента. Эта форма должна быть первой или основной формой приложения; она будет отображаться при запуске приложения.

Visual Studio имеет большой выбор опций для создания графического интерфейса. Как показано на рисунке 1, в зависимости от выбранного языка, существуют типы различных проектов, которые можно выбрать, такие как приложение MFC, консольное приложение Windows и приложение Windows Forms. Каждое из этих различных типов приложений может использоваться для общего интерфейса. Тем не менее, у каждого из них есть свои собственные специальные атрибуты, независимо от того, отличаются ли они от кода, который генерируют, или от типа методов, которые они использовали для создания реальной формы.

Если выбрано приложение Windows Forms, то на экране появится пустая форма для приложения Windows, которая послужит основой для графического интерфейса, как показано на рисунке 2. Все типы графического интерфейса пользователя состоят из основных инструментов формы: кнопки, текстовые поля, метки, флажки и т.д. [3.] Более интуитивно понятные элементы управления, которые составляют основу GUI, непосредственным образом соотносится с функциональностью приложения [8.]. В то же время большое количество элементов управления может снизить уровень удобства пользователя в реальном графическом интерфейсе.

Ключевая функция, которую Visual Studio реализует в своей IDE, – это метод перетаскивания. Этот метод позволяет пользователю выбрать любой инструмент, который должен быть частью окончательного графического интерфейса пользователя, и перетащить его в форму окна. С помощью этого метода предварительно генерируется код, который работает параллельно с инструментами. Это устраняет сложную и трудоемкую задачу сопоставления кода с каждым инструментом [9.]. Поскольку в графическом интерфейсе может быть огромное количество различных и похожих элементов управления, при использовании Visual Studio используется простое соглашение об именах. Каждый инструмент, помещенный в форму, имеет окно настроек, которое расшифровывает то, как называется инструмент и что происходит при нажатии на этот инструмент, а также многие другие параметры макета. Это позволяет пользователю организовать GUI более эффективно, чем иметь инструменты, которые невозможно декодировать в коде [1.,4.]. Код за графическим интерфейсом очень важен, так как он сообщает приложению о функциональности программы. Как уже указывалось ранее, код предварительно генерируется в формате, понятном даже начинающему программисту. Двойной щелчок на любом инструменте в графическом интерфейсе приведет к сгенерированному коду, который вызовет функцию. На рисунке 3 приведена такая функция – она обрабатывает нажатие кнопки button1.

Рисунок 1 – Различные типы приложений при создании проекта

Рисунок 2 – Пустая форма, генерируемая при создании проекта

Рисунок 3 – Сгенерированная функция обработки нажатия кнопки

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

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

Рисунок 4 – Вид панели меню

Visual Studio – это IDE с весьма отличительной особенностью: она не только предварительно генерирует функции, которые соответствуют щелчкам мыши по элементам в интерфейсе, но также генерирует переменные, необходимые для программы. Структура программы организована таким образом, что ссылки на переменные в форме осуществляются путем указания на форму и получения доступа к переменным. Чтобы сделать это, пользователь должен будет ссылаться на указатель на форму в форме. Этот процесс кажется сложным, но он просто выполняется с помощью оператора this, за которым следует знак ->. Это действие позволяет получить доступ к таким элементам формы, как объекты и переменные. На рисунке 5 показано, как код ссылается на переменные в форме.

Помимо привлекательной графики пользовательский интерфейс должен иметь определенное предназначение. Так, например, обработка текста, считанного из текстовых полей, может осуществляться в соответствии с выбранным флажком (при их наличии). На рисунке 6 показаны несколько различных окончательных форм графического интерфейса, которые были созданы в Visual Studio.

Рисунок 5 – Отображение ссылок на переменные в коде формы

Логика всего интерфейса идет рука об руку с тем, что появляется на нем. Операторы if и while можно использовать для улучшения общей производительности. Например, может быть несколько операторов if, которые будут отключать текстовые поля в зависимости от переключателей или циклов while, которые могут работать, предоставляя пользователю время на цикл. Если приложение включает в себя выпадающие меню, они могут напрямую соотноситься с кодом и повышать удобство для пользователя, сводя к минимуму количество действий, которые пользователь должен выполнить, чтобы повысить удобство использования. Функциональность приложения диктует пользовательский интерфейс, и как только это будет принято, интерактивность должна быть улучшена [7.].

Рисунок 6 – Различные GUI, созданные в Visual Studio

Разработка программы с графическим интерфейсом на C++

В этом разделе выполняется программная реализация приложения на языке программирования C++. Для написания используется IDE Microsoft Visual Studio 2010 с интерфейсом программирования приложений Windows Forms. Для построения графиков используется элемент управления Microsoft Chart для Microsoft.NET Framework 4.0 [10.].

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

Реализация программного средства начинается с создания формы Form1 и добавления на нее двух элементов richTextBox1 и richTextBox2 (текстовые поля для ввода текста и вывода найденных слов соответственно), трех элементов label1, label2, label3 (метки для подписи текстовых полей и текста задания), а также элемента button1 (кнопка, по нажатию которой осуществляется выполнение задания). Настройка и внешний вид элементов формы осуществляется при помощи мыши. Вид формы приведен на рисунке 7.

Следующий этап – создание собственного класса с методами, позволяющими выполнить задание. Класс MyClassFindWords содержит закрытое поле words (массив строк, в котором хранятся слова переданного текста), а также открытые методы getWords (функция, возвращающая все найденные слова согласно заданию) и setTextForAnalyze (функция, разбивающая переданный в виде строки текст в массив строк – слов текста). Этот класс объявлен в заголовочном файле MyClasses.h (листинг 2).

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

Листинг 2. Объявление собственного класса на языке C++

public ref class MyClassFindWords

{

array <System::String^>^ words;

public:

System::String^ getWords(); void setTextForAnalyze(System::String ^a);

};

Теперь остается определить объявленные методы в отдельном файле MyClasses.cpp. Подобное отделение объявления от реализации позволяет упростить управление классом и работу с ним. Для использования заголовков (то есть прототипов объявленных методов) необходимо добавить строку #include "MyClasses.h".

Метод setTextForAnalyze получает массив слов, используя строку, содержащую последовательность символов, позволяющую разделить текст по словам. Согласно указанным делителям текст разбивается на подстроки (листинг 3).

Листинг 3. Реализация функции setTextForAnalyze

void MyClassFindWords::setTextForAnalyze(System::String^ text)

{

System::String^ delimStr = " ,.!:\t\n";

words = text->Split( delimStr->ToCharArray());

}

Исходный код функции getWords с комментариями приводится в листинге 4.

Листинг 4. Реализация функции getWords

System::String^ MyClassFindWords::getWords()

{

// Строка, содержащая только согласные буквы

System::String^ s = "бвгджзйклмнпрстфхцчшщ";

// Результирующая строка, содержащая искомые слова

System::String^ resultText = "";

// Проход по массиву

for(int j = 0; j < words->Length; j++ )

{

int count = 0; // количество согласных

System::String^ word = words[j];

// Цикл по всем буквам текущего слова

for(int k = 0; k < word->Length; k++)

// Цикл по всем согласным буквам

for(int i = 0; i < s->Length; i++)

if(s[i] == word[k])

count++;

if (count == 3)

resultText = resultText + " " + word;

}

// Вернуть найденные слова

return resultText;

}

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

Листинг 5. Обработка нажатия на кнопку button1

private: System::Void button1_Click

(System::Object^ sender, System::EventArgs^ e)

{

MyClassFindWords^ classFind =

gcnew MyClassFindWords();

classFind->setTextForAnalyze(richTextBox1->Text);

richTextBox2->Text = classFind->getWords();

}

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

Рисунок 8 – Пример работы созданного приложения

ЗАКЛЮЧЕНИЕ

В ходе выполнения курсовой работы были рассмотрены принципиальные особенности, связанные с созданием и использованием графического интерфейса в приложениях на языке С/С++ в среде MS Visual Studio, приведены основные возможности Windows.Forms, а также конкретный пример создания и использования пользовательского графического интерфейса. Таким образом, выполнены все поставленные задачи, и цель курсовой работы достигнута в полном объеме.

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

        1. Давыдов В.Г. Visual С++. Разработка Windows-приложений с помощью MFS и API функций– СПб.: БХВ – Петербург, 2008. – 576 с.
        2. Культин Н.Б. Delphi 6. Программирование на Object Pascal. – СПб.: БХВ – Петербург, 2012. – 528 с.
        3. Троелсен Э. Язык программирования C# 5.0 и платформа .NET 4.5, 6-е изд.: ООО И.Д. Вильямс, 2013 - 1312 с.
        4. Оберг Роберт Дж., Торстейнсон,Питер. Архитектура .NET и программирование с помощью Visual C++. :Пер.с англ. М.:Издательский дом "Вильям", 2002. 656 с.
        5. Шилдт Герберт. Полный справочник по С, 4-ое издание.: Пер. с англ. – М.: Издательский дом «Вильямс», 2015. – 704 с.
        6. Яцюк О. Основы графического дизайна на базе компьютерных технологий (+СD), 2014, 240 c.
        7. Джеффри Рихтер CLR via C#. Программирование на платформе .NET Framework 4.0 на языке C#. 3-е изд. = CLR via C#, 3 ed. — СПб.: Питер, 2011. — ISBN 978-5-459- 00297-3
        8. Костельцев А. GTK+. Разработка переносимых графических интерфейсов. – BHV – Санкт-Петебург, 2013. – 368 с. ISBN: 5941571615
        9. Richard Coyne. The Tuning of Place: Sociable Spacer and Pervasive Digital Media - MIT Press. 2018. – p.52 – 344 p. ISBN 9780262013918.
        10. Средства построения графиков для .NET // Хабрахабр [Электронный ресурс]. – URL: http://habrahabr.ru/post/204308/ (дата обращения: 22.04.2019).

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

Файл Form1.h:

#pragma once

#include "MyClasses.h"

namespace Task2 {

using namespace System;

using namespace System::ComponentModel;

using namespace System::Collections;

using namespace System::Windows::Forms;

using namespace System::Data;

using namespace System::Drawing;

/// <summary>

/// Summary for Form1

/// </summary>

public ref class Form1 : public System::Windows::Forms::Form

{

public:

Form1(void)

{

InitializeComponent();

//

//TODO: Add the constructor code here

//

}

protected:

/// <summary>

/// Clean up any resources being used.

/// </summary>

~Form1()

{

if (components)

{

delete components;

}

}

protected:

private: System::Windows::Forms::Label^ label1;

private: System::Windows::Forms::Label^ label2;

private: System::Windows::Forms::Label^ label3;

private: System::Windows::Forms::Button^ button1;

private: System::Windows::Forms::RichTextBox^ richTextBox1;

private: System::Windows::Forms::RichTextBox^ richTextBox2;

private:

/// <summary>

/// Required designer variable.

/// </summary>

System::ComponentModel::Container ^components;

#pragma region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

void InitializeComponent(void)

{

this->label1 = (gcnew System::Windows::Forms::Label());

this->label2 = (gcnew System::Windows::Forms::Label());

this->label3 = (gcnew System::Windows::Forms::Label());

this->button1 = (gcnew System::Windows::Forms::Button());

this->richTextBox1 = (gcnew System::Windows::Forms::RichTextBox());

this->richTextBox2 = (gcnew System::Windows::Forms::RichTextBox());

this->SuspendLayout();

//

// label1

//

this->label1->AutoSize = true;

this->label1->Location = System::Drawing::Point(26, 27);

this->label1->Name = L"label1";

this->label1->Size = System::Drawing::Size(437, 13);

this->label1->TabIndex = 1;

this->label1->Text = L"Задание: Найти все слова в тексте, которые содержат только три согласных буквы";

//

// label2

//

this->label2->AutoSize = true;

this->label2->Location = System::Drawing::Point(26, 59);

this->label2->Name = L"label2";

this->label2->Size = System::Drawing::Size(92, 13);

this->label2->TabIndex = 2;

this->label2->Text = L"Исходный текст:";

//

// label3

//

this->label3->AutoSize = true;

this->label3->Location = System::Drawing::Point(498, 59);

this->label3->Name = L"label3";

this->label3->Size = System::Drawing::Size(101, 13);

this->label3->TabIndex = 4;

this->label3->Text = L"Найденные слова:";

//

// button1

//

this->button1->Location = System::Drawing::Point(341, 407);

this->button1->Name = L"button1";

this->button1->Size = System::Drawing::Size(131, 35);

this->button1->TabIndex = 5;

this->button1->Text = L"Поиск слов";

this->button1->UseVisualStyleBackColor = true;

this->button1->Click += gcnew System::EventHandler(this, &Form1::button1_Click);

//

// richTextBox1

//

this->richTextBox1->Location = System::Drawing::Point(29, 85);

this->richTextBox1->Name = L"richTextBox1";

this->richTextBox1->Size = System::Drawing::Size(281, 357);

this->richTextBox1->TabIndex = 6;

this->richTextBox1->Text = L"";

//

// richTextBox2

//

this->richTextBox2->Location = System::Drawing::Point(501, 85);

this->richTextBox2->Name = L"richTextBox2";

this->richTextBox2->Size = System::Drawing::Size(281, 357);

this->richTextBox2->TabIndex = 7;

this->richTextBox2->Text = L"";

//

// Form1

//

this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);

this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;

this->ClientSize = System::Drawing::Size(816, 454);

this->Controls->Add(this->richTextBox2);

this->Controls->Add(this->richTextBox1);

this->Controls->Add(this->button1);

this->Controls->Add(this->label3);

this->Controls->Add(this->label2);

this->Controls->Add(this->label1);

this->Name = L"Form1";

this->Text = L"Контрольная работа №2 (Вариант 11)";

this->ResumeLayout(false);

this->PerformLayout();

}

#pragma endregion

private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e)

{

// Создаем экземпляр собственного класса для поиска слов

MyClassFindWords^ classFind = gcnew MyClassFindWords();

// Передаем текст в класс

classFind->setTextForAnalyze(richTextBox1->Text);

// Запрашиваем слов с тремя согласными и выводим их

richTextBox2->Text = classFind->getWords();

}

};

}

Файл MyClasses.h:

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

public ref class MyClassFindWords

{

array <System::String^>^ words; // Массив слов с их описанием

public:

// Функция возвращает все найденные слова с 3 согласными

System::String^ getWords();

// Функция получает текст для анализа

void setTextForAnalyze(System::String ^a);

};

Файл MyClasses.cpp:

#include "stdafx.h"

#include "MyClasses.h"

void MyClassFindWords::setTextForAnalyze(System::String^ text)

{

// Разбиваем переданный текст на слова

System::String^ delimStr = " ,.!:\t\n"; //Последовательность символов, разделяющих текст по словам

// Получаем массив слов разделяя текст на подстроки согласно указанным делителям

words = text->Split( delimStr->ToCharArray());

}

// Функция возвращает все найденные слова с 3 согласными

System::String^ MyClassFindWords::getWords()

{

// Строка, содержащие только согласные буквы

System::String^ s = "бвгджзйклмнпрстфхцчшщ";

// Результирующая строка, содержащая искомые слова

System::String^ resultText = "";

// Проходим по массиву

for(int j = 0; j < words->Length; j++ )

{

int count = 0; // количество согласных в слове

System::String^ word = words[j]; // текущее слово

// Цикл по всем буквам слова

for(int k = 0; k < word->Length; k++)

// Цикл по всем согласным буквам

for(int i = 0; i < s->Length; i++)

if(s[i] == word[k])

count++;

if (count == 3)

resultText = resultText + " " + word;

}

// Возвращаем найденные слова

return resultText;

}