Разработка прикладного программного обеспечения (ПО) включает в себя концепцию взаимодействия человека с компьютером, и в этой области программы очень важен графический пользовательский интерфейс (Graphical User Interface – GUI). Визуальные виджеты, такие как флажки и кнопки, используются для управления информацией, имитирующей взаимодействие с программой. Хорошо продуманный графический интерфейс дает гибкую структуру, в которой сам интерфейс не зависит от функциональности приложения, но напрямую связан с ней. Это качество прямо пропорционально удобству использования приложения.
Установление связи между пользовательским интерфейсом и функциональностью приложения успешно реализуется с конца 1970-х годов. Xerox PARC был основным разработчиком пользовательских интерфейсов, в том числе первого в мире, Alto, из которого получены большинство графических интерфейсов общего назначения.
1980-е годы были революционными для GUI на всех платформах. Xerox Star и Apple Lisa представили основные функциональные возможности – от панели меню, элементов управления окнами, двойного щелчка значков до диалоговых окон и монохромных дисплеев. Эволюция и популярность пользовательского интерфейса продолжали выходить за рамки первоначальных идей. Его массовое использование сделало невозможным создание стандартного внешнего вида для GUI.
Графический интерфейс. Как создать программу на C++
В конце XX и начале XXI века важную роль в визуализации данных при помощи программного обеспечения с графическим интерфейсом получили операционные системы (ОС). Как правило, запуск подобных программ осуществляется при помощи систем компании Microsoft. В то же время тенденция последних лет – использование кроссплатформенных средств для разработки программ – требует от разработчика предоставить пользователю возможность запустить готовый программный продукт на различных ОС, в том числе мобильных. Сегодня существует широкий спектр операционных систем, каждая из которых имеет популярный и узнаваемый графический интерфейс. Microsoft Windows и Mac OS X отлично подходят для ноутбуков и настольных компьютеров, а Android, Apple iOS и Windows Phone предоставляют известные графические интерфейсы для мобильных устройств.
Цель данной курсовой работы – научиться создавать графический интерфейс пользователя, обеспечивая при этом удобство для пользователя и функциональность приложения на высоком уровне. Для достижения цели в курсовой работе были поставлены следующие задачи:
- изучить современные способы построения графических интерфейсов пользователя;
- выбрать среду разработки для создания приложения на языке программирования C++ с графическим пользовательским интерфейсом;
- получить представление об основных особенностях выбранной среды;
- выполнить разработку программы в выбранной среде разработки с использованием графического пользовательского интерфейса.
Предметом курсовой работы является графический интерфейс пользователя.
Особенности объектно-ориентированной парадигмы программирования
Выбор парадигмы программирования, определяющей успешность реализации программного продукта, и соответствующего ей языка программирования имеет решающее значение для специалиста в области информационных технологий и программирования. За последние 50 лет появились сотни языков, поддерживающих различные парадигмы, некоторые из них используют несколько парадигм (такие языки называют мультипарадигменными). Однако, несмотря на большое количество языков программирования, существует несколько действительно важных концепций программирования, и не так много языков, которые были бы актуальны на протяжении более десяти лет. Именно парадигмы программирования определяют общий способ проектирования прикладных программ. Парадигмой программирования называют используемый различными языками подход к программированию, то есть, проще говоря, набор идей и понятий, определяющих стиль написания программ.
Как создать графический интерфейс на Python с нуля
Инструкции первых языков программирования, появившихся в начале 50-х годов XX века и ориентированных на конкретный компьютер, записывались в исходном коде и выполнялись последовательно. Данные, полученные при выполнении предыдущих инструкций, могли быть считаны из памяти или записаны в нее.
Таким образом, программы представляли собой последовательность команд, которые должен был выполнить компьютер. Языки программирования, использующие этот подход (прежде всего, это машинные инструкции и язык ассемблера), образовали императивную парадигму программирования. В отличие от декларативного подхода, при котором задается спецификация решения задачи, в императивном широко используются операторы присваивания. Ранние императивные языки сложны для понимания и решения прикладных задач.
Развитие вычислительных устройств и компьютерной техники привело к появлению процедурных языков. Процедурные языки программирования, первые реализации которых относятся к концу 50-х годов, позволили разбивать задачи на шаги и решать их шаг за шагом, причем возможность определять каждый шаг в процессе решения задачи была предоставлена программисту. Эти языки использовали императивную парадигму, но последовательно выполняемые операторы могли быть собраны в подпрограммы, то есть более крупные целостные единицы кода, с помощью самого языка. Согласно некоторым классификациям, такой подход выделяется в самостоятельную парадигму, получившую название процедурной. К процедурным языкам программирования относятся, например, Паскаль, Си, Алгол, КОБОЛ и Фортран.
Процедурный подход потребовал структурирования будущей программы, разделения ее на отдельные процедуры. При разработке отдельной процедуры о других процедурах требовалось знать только их назначение и способ вызова. Появилась возможность перерабатывать отдельные процедуры, не затрагивая остальной части программы, сокращая при этом затраты труда и машинного времени на разработку и модернизацию программ.
Следующим шагом в углублении структурирования программ стало так называемое структурное программирование, при котором программа в целом и отдельные процедуры рассматривались как последовательности канонических структур: линейных участков, циклов и разветвлений. Появилась возможность читать и проверять программу как последовательный текст, что повысило производительность труда программистов при разработке и отладке программ. С целью повышения структурности программы были выдвинуты требования к большей независимости подпрограмм, подпрограммы должны связываться с вызывающими их программами только путем передачи им аргументов, использование в подпрограммах переменных, принадлежащих другим процедурам или главной программе, стало считаться нежелательным.
Процедурное и структурное программирование затронули прежде всего процесс описания алгоритма как последовательности шагов, ведущих от варьируемых исходных данных к искомому результату. Для решения специальных задач стали разрабатываться языки программирования, ориентированные на конкретный класс задач: на системы управления базами данных, имитационное моделирование и т.д. При разработке трансляторов все больше внимания стало уделяться обнаружению ошибок в исходных текстах программ, обеспечивая этим сокращение затрат времени на отладку программ.
Все универсальные языки программирования, несмотря на различия в синтаксисе и используемых ключевых словах, реализуют одни и те же канонические структуры: операторы присваивания, циклы и разветвления. Во всех современных языках присутствуют предопределенные (базовые) типы данных (целые и вещественные арифметические типы, символьный и, возможно, строковый тип), имеется возможность использования агрегатов данных, в том числе массивов и структур (записей). Для арифметических данных разрешены обычные арифметические операции, для агрегатов данных обычно предусмотрена только операция присваивания и возможность обращения к элементам агрегата. Вместе с тем при разработке программы для решения конкретной прикладной задачи желательна возможно большая концептуальная близость текста программы к описанию задачи. Например, если решение задачи требует выполнения операций над комплексными числами или квадратными матрицами, желательно, чтобы в программе явно присутствовали операторы сложения, вычитания, умножения и деления данных типа комплексного числа, сложения, вычитания, умножения и обращения данных типа квадратной матрицы. Решение этой проблемы возможно несколькими путями:
- Построением языка программирования, содержащего как можно больше типов данных, и выбором для каждого класса задач некоторого подмножества этого языка. Такой язык иногда называют языком-оболочкой. На роль языка-оболочки претендовал язык ПЛ/1, оказавшийся настолько сложным, что так и не удалось построить его формализованное описание. Отсутствие формализованного описания, однако, не помешало широкому применению ПЛ/1 как в Западной Европе, так и в СССР.
- Построением расширяемого языка, содержащего небольшое ядро и допускающего расширение, дополняющее язык типами данных и операторами, отражающими концептуальную сущность конкретного класса задач. Такой язык называют языком-ядром. Как язык-ядро были разработаны языки Симула и Алгол-68, не получившие широкого распространения, но оказавшие большое влияние на разработку других языков программирования.
Дальнейшим развитием второго пути явился объектно-ориентированный подход к программированию.
Основные идеи объектно-ориентированного подхода опираются на следующие положения:
- Программа представляет собой модель некоторого реального процесса, части реального мира.
- Модель реального мира или его части может быть описана как совокупность взаимодействующих между собой объектов.
- Объект описывается набором параметров, значения которых определяют состояние объекта, и набором операций (действий), которые может выполнять объект.
- Взаимодействие между объектами осуществляется посылкой специальных сообщений от одного объекта к другому. Сообщение, полученное объектом, может потребовать выполнения определенных действий, например, изменения состояния объекта.
- Объекты, описанные одним и тем же набором параметров и способные выполнять один и тот же набор действий представляют собой класс однотипных объектов.
С точки зрения языка программирования класс объектов можно рассматривать как тип данного, а отдельный объект — как данное этого типа. Определение программистом собственных классов объектов для конкретного набора задач должно позволить описывать отдельные задачи в терминах самого класса задач (при соответствующем выборе имен типов и имен объектов, их параметров и выполняемых действий).
Таким образом, объектно-ориентированный подход предполагает, что при разработке программы должны быть определены классы используемых в программе объектов и построены их описания, затем созданы экземпляры необходимых объектов и определено взаимодействие между ними.
Классы объектов часто удобно строить так, чтобы они образовывали иерархическую структуру. Например, класс “Студент”, описывающий абстрактного студента, может служить основой для построения классов “Студент 1 курса”, “Студент 2 курса” и т.д., которые обладают всеми свойствами студента вообще и некоторыми дополнительными свойствами, характеризующими студента конкретного курса.
При разработке интерфейса с пользователем программы могут использовать объекты общего класса “Окно” и объекты классов специальных окон, например, окон информационных сообщений, окон ввода данных и т.п. В таких иерархических структурах один класс может рассматриваться как базовый для других, производных от него классов. Объект производного класса обладает всеми свойствами базового класса и некоторыми собственными свойствами, он может реагировать на те же типы сообщений от других объектов, что и объект базового класса и на сообщения, имеющие смысл только для производного класса. Обычно говорят, что объект производного класса наследует все свойства своего базового класса.
Некоторые параметры объекта могут быть локализованы внутри объекта и недоступны для прямого воздействия извне объекта. Например, во время движения объекта-автомобиля объект-водитель может воздействовать только на ограниченный набор органов управления (рулевое колесо, педали газа, сцепления и тормоза, рычаг переключения передач) и ему недоступен целый ряд параметров, характеризующих состояние двигателя и автомобиля в целом.
Объектно-ориентированный подход к программированию эффективен в тех случаях, когда некоторый реально существующий предмет характеризуется очень большим числом параметров. Тогда подпрограммы, описывающие алгоритмы обработки или функционирования такого предмета, имеют настолько большое число формальных параметров, что программирование их вызовов слишком трудоемко и сопряжено с большим количеством ошибок.
Эффективным методом программирования таких задач является создания в программе объекта, соответствующего предмету. Этот объект будет включать в себя данные, соответствующие параметрам предмета, и подпрограммы (в C++ функции), описывающие алгоритмы обработки или функционирования предмета. Данные объекта должными являться по умолчанию доступными для алгоритмов объекта (как бы быть глобальными для этих алгоритмов) и не включаться в списки параметров соответствующих подпрограмм. Таким образом, количество параметров подпрограмм существенно уменьшится.
В С++ (и во многих других объектно-ориентированных алгоритмических языках, например, в Объектном Паскале) вводится новый тип данных – класс. Переменная типа класс называется объектом. Иногда объект называют также экземпляром класса. Формально описание класса напоминает структуру, но класс, кроме полей (переменных), содержит методы, которые задают допустимые действия над полями класса. Общее название для полей и методов – элементы класса.
В листинге 1 дается простейшее описание класса на языке С++.
Листинг 1. Описание класса на языке C++
описание личных элементов класса
описание общих элементов класса
Под личными элементами класса (private) понимаются такие элементы, которые могут использоваться только методами своего класса. К общим элементам класса (public) доступ разрешен в любом месте программы. Существуют и другие способы доступа к элементам класса.
Поля класса описываются внутри класса как обычные переменные. Методы – это функции, которые можно применять к полям. Считается хорошим стилем программирования, что внутри класса методы задаются своими прототипами. Вне класса (ниже его описания) приводится полное описание метода. Очень короткие методы можно полностью описывать внутри класса.
Как правило, поля являются личными элементами класса, т. е. доступ к полям разрешен только внутри методов класса. Это положение можно рассматривать как простейшую формулировку принципа инкапсуляции.
Если внутри класса метод описан прототипом:
тип_результата имя_метода (список типов параметров),
то при полном описании вне класса метод имеет заголовок:
тип_результата имя_класса::имя_метода (список параметров),
т. е. в заголовке перед именем метода указывается имя класса (через знак ::).
Существуют особые методы класса: конструкторы и деструкторы. Назначение конструктора заключается в создании экземпляра класса и инициализации его полей. Имя конструктора совпадает с именем класса. Конструктор никогда не вызывается явно, его вызов осуществляется компилятором в момент создания экземпляра класса.
Деструктор вызывается для уничтожения экземпляра класса. Имя деструктора образуется как ~имя_класса. Деструктор может вызываться в программе явно или (что происходит обычно) его вызов обеспечивается компилятором в момент уничтожения экземпляра класса.
Наличие конструктора и деструктора для любого класса обязательно; при их отсутствии компилятор автоматически создает стандартные варианты конструктора и деструктора.
Экземпляры класса могут создаваться автоматически или динамически. Уничтожение автоматически созданных экземпляров классов происходит также автоматически при завершении выполнения блока функции, в котором они были определены. Определение (описание) автоматического экземпляра класса может встречаться в любом месте функции и имеет вид:
имя_класса имя_экземпляра(параметры конструктора);
Перед созданием динамического экземпляра класса (по аналогии с любыми динамическими переменными) необходимо объявить указатель на экземпляр:
Динамический экземпляр класса создается с помощью оператора new, а уничтожается с помощью оператора delete:
указатель_на_экземпляр= new имя_класса (параметры конструктора);
Метод класса (по аналогии с полем структуры) вызывается одним из следующих способов:
имя_экземпляра.имя_метода или имя_экземпляра->имя_метода
Инкапсуляция – такое объединение внутри класса полей и методов, при котором доступ к полю возможен только путем вызова соответствующего метода.
При идеальном выполнении принципа инкапсуляции поля класса могут быть только личными (private).
Ниже перечислены уровни инкапсуляции, т. е. уровни доступа к элементам класса:
- private (личный). Этот уровень накладывает самые жесткие ограничения на доступ к элементам класса. Именно эти элементы могут быть использованы только методами данного класса. Как правило, поля класса объявляются private.
- public (общий). Элементы класса данного уровня доступны из любой точки программы (самый «широкий» доступ).
- protected (защищенный). Элементы класса данного класса доступны методам данного класса и его наследников.
Наследование – это возможность определения для базового класса (предка) иерархии производных классов (наследников), в каждом из которых доступны элементы базового класса (их описание становится частью описания производного класса). Иначе говоря, наследование – механизм, посредством которого класс может наследовать элементы другого класса и добавлять к ним свои элементы.
Как правило, базовый класс является общим, производные – более специальными, конкретными. Естественно, у класса-наследника обычно больше полей и методов, чем у класса-предка, так как при наследовании обычно добавляются новые элементы.
Если имеется иерархия классов, то можно рассматривать защищенные (protected) элементы класса, которые доступны для методов своего класса и его наследников.
Наследование может быть единичным (наследник имеет одного предка) и множественным (количество предков больше 1). В Си++ допустимо множественное наследование.
Наследование может быть общим, личным и защищенным.
Видимость полей и функций базового класса из производного определяется секцией, в которой находится объявление компонента, и видом наследования (таблица 1):
Таблица 1. Видимость компонентов базового класса в производном
Объявление компонентов в базовом классе
Видимость компонентов в производном классе
Источник: www.evkova.org
Как написать программу с интерфейсом
Механизм наследования очень удобен, но он имеет свои ограничения. В частности мы можем наследовать только от одного класса, в отличие, например, от языка С++, где имеется множественное наследование.
В языке Java подобную проблему частично позволяют решить интерфейсы. Интерфейсы определяют некоторый функционал, не имеющий конкретной реализации, который затем реализуют классы, применяющие эти интерфейсы. И один класс может применить множество интерфейсов.
Чтобы определить интерфейс, используется ключевое слово interface . Например:
interface Printable
Как написать программу с интерфейсом
Создание интерфейса пользователя сводится к выбору из палитры компонентов необходимые для работы программы компоненты Delphi, служащие интерфейсом управления, а также интерфейсом отображения информации, и перенесение их на Форму с последующей компоновкой.
- Программа должна помогать выполнить задачу, а не становиться этой задачей.
- При работе с программой пользователь не должен ощущать себя дураком.
- Программа должна работать так, чтобы пользователь не считал компьютер дураком.
Второй принцип заключается в пренебрежении интеллектуальными способностями пользователей. На собственном опыте мне известно, что часто пользователи не только не умеют работать за компьютером, но и просто боятся предпринять что-либо самостоятельно. Поэтому интерфейс пользователя должен быть максимально дружественным.
Тем более, что опасения пользователей зачастую оправданны, ведь стоимость программы, да и самого компьютера не идёт ни в какое сравнение со стоимостью, например, созданной многолетними усилиями базы данных. Именно поэтому программист при создании интерфейса пользователя обязан всегда встраивать в программу «защиту от дурака» — от неправильных действий и ввода пользователем неверных данных. Но некоторые программисты чересчур увлекаются такой защитой, делают ее слишком назойливой, и в результате работа программы напоминает знаменитое «шаг влево, шаг вправо считается побегом»! И то, что программист создаёт как решение проблемы, само начинает создавать проблемы.
Для соблюдения второго принципа не нужно позволять программе «исправлять» действия пользователя и указывать, что как именно ему действовать, загоняя в узкие рамки. Также не следует чрезмерно увлекаться выводом информационных сообщений-подсказок, особенно диалоговых, это отвлекает пользователя от работы. А лучше вообще предусмотреть возможность отключения подсказок.
Третий принцип заключается в том, чтобы создавать программу с максимально возможными «умственными» способностями. Несмотря на быстрое развитие компьютерной техники, даже широко распространённые программы лишь весьма условно можно назвать имеющими искуственный интеллект. Они мешают работе пользователя, выводя на экран диалоговые окна с глупыми вопросами, вызывающими недоумение даже в простейших ситуациях. В результате пользователи в сердцах восклицают: «Ну и тупая же эта машина»!
У меня лично вызывают раздражение постоянные вопросы практически всех текстовых редакторов о том, не сохранить ли изменённый текст, хотя первоначальный и нынешний текст не отличаются ни символом. Да, я что-то набирал, но потом вернул всё назад, неужели нельзя сообразить! Приходится проверять, не испортил ли я всё-таки что-нибудь.
- Стандартные элементы интерфейса
- Небольшая палитра инструментов
- Одинаковое расстояние между элементами управления
- TabOrder. «Правильный» порядок
- Выбор шрифтов
- Выбор цветов
- Альтернативное управление
- Кирпичики интерфейса
Стандартные элементы интерфейса
Используйте стандартные для данного элемента интерфейса компоненты. Встретив Вашу программу, пользователь не будет терять время на знакомство, а сразу приступит к работе — это один из признаков профессионально сделанной программы.
Небольшая палитра инструментов
Старайтесь использовать не слишком большое количество разнообразных компонентов. И естественно, использовав где-то в одном месте один стандартный компонент, в аналогичном случае также применяйте именно его.
Одинаковое расстояние между элементами управления
Располагайте элементы интерфейса на одинаковом расстоянии между собой. Разбросанные как попало компоненты создают ощущение непрофессионально сделанного продукта. И наоборот, тщательно выверенное размещение на Форме кнопок, переключателей, флажков и других компонентов, составляющих интерфейс — признак качественной работы.
TabOrder. «Правильный» порядок
TabOrder — это порядок перемещения экранного курсора по элементам управления при нажатии клавиши Tab. В правильно написанной программе курсор перемещается, следуя логике работы пользователя с программой. При создании же программы программист часто меняет компоненты, одни удаляет, другие добавляет по мере необходимости. В результате в готовой программе курсор хаотично скачет по Форме. Завершив программу, не забывайте настроить TabOrder.
Выбор шрифтов
Шрифты просто оставьте в покое. Заданные по умолчанию самой Delphi шрифты подойдут для любой системы, на которой может работать Ваша программа. Полужирный шрифт используйте только для выделения важных элементов. Применение же курсива и особенно подчёркивания, которое пользователь может принять за гиперссылку — дурной тон.
Выбор цветов
Что касается цветов элементов интерфейса, то также, как и в случае со шрифтами, лучше оставьте их стандартными, по умолчанию. Delphi использует системную палитру Windows, и пользователь, изменив её, легко настроит цвета под себя.
Альтернативное управление
Профессионально сделанная программа должна иметь возможность управляться не только мышкой, но и с клавиатуры. Не должно быть функций, доступных выполнению только мышью (рисование в графических редакторах не в счёт!). Для наиболее используемых функций следует предусмотреть «горячие клавиши» для их быстрого вызова.
Кирпичики интерфейса
- соответствия элемента управления выполняемой им задаче;
- правил, по которым функционирует элемент управления.
На этой страничке рассматриваются правила создания некоторых элементов интерфейса.
Для того, чтобы расположить относительно друг друга компоненты в правильном порядке, сначала необходимо их выделить. Можно просто обвести мышкой область на Форме, в которой содержатся выбранные компоненты. Или, удерживая «Shift», указать той же мышкой каждый подлежащий выделению компонент. Повторный щелчок мышкой по выделенному компоненту (при нажатом «Shift») снимает с него выделение.
Выделенными компонентами можно управлять как единым целым — передвигать по Форме, присвоить значение одинаковым свойствам, скопировать (для установки, например, на другую Форму), даже удалить.
Диалог выравнивания компонентов
Выбрав пункт Center, мы расположим компоненты так, что их центры будут располагаться на одной линии по горизонтали или вертикали, а пункт перемещает компоненты в центр окна, также по горизонтали или вертикали.
В этом же меню строка Tab Order. вызывает появление диалогового окна, управляющего перемещением курсора по элементам интерфейса при нажатии клавиши Tab. В момент появления Формы на экране курсор будет находиться, естественно, на компоненте, располагающемся на первой строчке диалогового окна. И далее будет перемещаться вниз по списку.
На диалоговом окне две синие стрелочки «вверх» и «вниз» управляют положением выделенного компонента. Выделяйте нужный компонент, стрелками перемещайте на нужную строчку в списке, и так далее.
- Bring to Front
- Send to Back
Источник: delphi-manual.ru