Как писать графические программы

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

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

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

Меня вот часто спрашивают студенты — как сделать что-нибудь графическое на C++? Много лет уже спрашивают. Уже устал отвечать — не знаю.

Конечно, не каждый язык должен иметь стандартную поддержку графики. Даже универсальный. Но вот от языка для обучения (а язык Паскаль используется в основном для обучения) поддержку графики — ждут.

В старом добром Бейсике — чем он подкупал — на Корветах там всяких, Атари и Синклерах — загрузил среду, написал

Circle(100,100,50)

и получил на экране кружочек — прямо поверх кода. Это потом с появленим MS DOS, где основным режимом стал текстовый, все усложнилось.

На старом добром Turbo Pascal был такой замечательный модуль Graph — подключил его, написал пару строчек непонятных заклинаний — и рисуй себе все что угодно аж 256 цветами! Вот эти заклинания:

uses Graph; var GraphDriver,GraphMode: integer; begin InitGraph(GraphDriver,GraphMode,’d:turbobgi’); end.

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

Вообщем, прошли те времена — появилась Windows, а в ней основной режим — графический.

Прошли ли? Меня до сих пор спрашивают, почему в PascalABC нет модуля Graph? Отвечаю, что не мог больше терпеть. Но нет-нет да мелькнет в Интернете на форуме пост какого-нибудь новичка — представляете, настолько плохой PascalABC, что даже графики в нем нет или она там какая-то своя! Не та, что описана в груде книжек по Турбо-Паскалю, а другая!

Вот об этой другой графике мы и поговорим.

Те, кто программировал графические приложения под Windows, знают, что рисовать лучше всего в обработчике события WM_PAINT или OnPaint (последнее — если используется какой-нибудь объектный каркас для Windows-приложения). В этом обработчике нельзя рисовать долго, поскольку программа на время его работы блокируется. А если рисовать в других обработчиках, то нарисованное стирается при следующей перерисовке окна. Короче — куча проблем!

Идея была простой: создать графическую библиотеку, подключающуюся крайне просто, где эти проблемы были бы решены. Еще лучше, если графическое приложение будет похоже на обычную программу: чтобы сразу после begin можно было писать графические команды.

Решение было найдено — вот эта простейшая программа:

uses GraphABC; begin Rectangle(10,10,100,100); end.

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

Вот несколько очень простых графических программок — совершенно бесполезны — чистое баловство!

Программа 1. Показывает использование процедуры SetPixel и функции RGB.

uses GraphABC; begin for var x:=0 to Window.Width-1 do for var y:=0 to Window.Height-1 do SetPixel(x,y,RGB(2*x-y,x-3*y,x+y)); end.

Программа 2. Рисование звездочки. Показывает использование процедур MoveTo и LineTo, а также полярных координат.

uses GraphABC; const n = 17; // количество точек n1 = 7; // через сколько точек соединять begin var a := -Pi/2; var Center := Window.Center; var Radius := Window.

Height/2.2; MoveTo(Round(Center.X+Radius*cos(a)),Round(Center.

Y+Radius*sin(a))); for var i:=1 to n do begin a += n1*2*Pi/n; LineTo(Round(Center.X+Radius*cos(a)),Round(Center.Y+Radius*sin(a))); end; end.

Пример 3. Цифровые часы. Показывает использование процедуры TextOut, а также функций TextWidth, TextHeight.

uses GraphABC,System; begin Font.Size := 80; var x0 := (Window.

Width — TextWidth(’00:00:00′)) div 2; var y0 := (Window.Height — TextHeight(’00:00:00′)) div 2; while True do begin var t := DateTime.

Now; var s := string.Format(‘::’,t.Hour,t.

Minute,t.Second); TextOut(x0,y0,s); Sleep(1000); end; end.

Ну вот, для введения и достаточно.

А симпатичные примеры на графику строк эдак на 10-15 — пожалуйста — пишите в комментариях!

Источник: pascalabc.net

Как написать программу с графическим интерфейсом на c

Не Windows единой: как писать кроссплатформенные приложения с GUI на C#

КАКИЕ ЕСТЬ ГРАФИЧЕСКИЕ БИБЛИОТЕКИ НА JAVA? GUI НА JAVAFX

Лучшая Графическая (GUI) Библиотека Для Python | Tkinter VS WxPython VS PyQt(PySide) VS Kivy

Урок № 26. Первое графическое приложение

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

Доброго времени суток! В этом уроке мы создадим Ваше первое приложение с графическим интерфейсом в MS Visual Studio. Это будет своего рода «Hello World» для графических приложений. Скажу сразу, что использование Windows Forms — не единственный способ создания графических приложений (приложения с графическим интерфейсом пользователя) для C# программистов, но начать изучение лучше именно с этого. И так, запускаем Visual Studio.

Читайте также:
Что такое отладка программы что называется тестом

Запустили? Тогда к делу! Идем в главное меню и выбираем пункт «Файл — Создать — Проект», как показано на рисунке ниже.

  • в левой части выбираем «Шаблоны — Visual C# — Windows»;
  • в основной области выбираем элемент «Приложение Windows Forms»;
  • в нижней части окна вводим имя проекта и указываем его расположение на диске.

В общем, как показано на рисунке ниже.

Указали что нужно? Тогда нажимайте на кнопку «OK». Теперь вы должны увидеть примерно следующее (основные области выделены прямоугольниками):

Только что созданный проект

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

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

Для этого, выделим в дизайнере форму (для этого, можно просто кликнуть левой кнопкой мыши по форме) и перейдем в блок свойств, в котором найдем строку «Text» (слово текст, ищем в левом столбце), как показано на рисунке ниже.

Свойство «Text» основной формы приложения

Обратите внимание, в левом столбце указано имя (название свойства), а в правом — его значение.

В данном случае, мы имеем дело с текстовым свойством, и его значение, отображается в заголовке окна, так что, давайте теперь укажем там что-то свое, например, что-то вроде: «Главное окно», как показано на рисунке ниже:

Теперь, можно собрать проект и запустить. Для этого идем в главное меню и выбираем пункт «Сборка — Собрать решение». А потом запускаем приложение, для этого выбираем пункт «Отладка — Запуск без отладки» в главном меню. В результате Вы должны увидеть окно следующее окно.

Окно первого графического приложения

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

Почему C++ не подходит для написания графических пользовательских интерфейсов

Я люблю C++, но.

Сразу оговорюсь, что C++ мой любимый язык, я на нем пишу практически «с детства» и отрицать его важность, как лучшего одного из лучших языков для написания программ для любых целей, не буду. Тем более не вижу смысла начинать очередной холивар или меряться «указками». Это статья — лишь описание неудачного опыта работы с языком, объясняющая некоторые его аспекты, знание которых поможет другим программистам в будущем.

Однажды я столкнулся с развивающейся библиотекой GUI класса. С точки зрения C++, а точнее его классов, экземпляров и иерархий, этот язык представляется невероятно близким к концепции управления GUI, в частности таким элементам, как виджеты, окна классов и подокна. OO модели C++ и оконной системы тем не менее разные.

C++ был задуман как «статический» язык с охватом лексем, статической проверкой типов и иерархий определенных во время компиляции. Окна и их объекты с другой стороны, по своей природе динамичны, они обычно живут за рамкам отдельной процедуры или блока, с помощью которой были созданы; иерархии виджетов в значительной степени определены расположением, видимостью и потоками событий.

Основы графического пользовательского интерфейса, такие как динамические и геометрические иерархии окон и управления, протекания событий, не поддерживаются непосредственно синтаксисом С++ либо его семантикой. Таким образом, эти функции должны быть воспроизведены в коде C++ GUI. Это приводит к дублированию графического инструментария, или функциональности оконного менеджера, код «раздувается», мы вынуждены отказываться от многих «сильных» особенностей C++ (например, проверки типов во время компиляции). В статье приведено несколько простых примеров C++ / GUI «не стыковок».

Не создавайте конструкторы (или, по крайней мере, не используйте их)

Когда полученный класс переопределяет виртуальный метод родительского класса, надо иметь в виду, что переопределение не вступает в силу, пока конструктор базового класса выполняется. Это особенно раздражает, когда объекты запрашивают виджеты, которые реагируют на события GUI. Предположим, что класс Basic_Window был предназначен для создания ванильного черно-белого окна на экране:

Здесь gt_create_window() отвечает за низкоуровневый вызов основного графического инструментария (например, xvt_win_create()). Эта функция выделяет место под данные инструментария, уведомляет оконный менеджер, регистрирует этот объект, как получателя событий, и в примере выше, инициализирует графический вывод в окно на экране.
Предположим, мы хотим создать экземпляр Basic_Window, но с красным фоном. Обычно, чтобы изменить поведение класса, надо извлечь из него и переопределить соответствующие виртуальные методы. Мы пишем:

class RedWindow : public Basic_Window
public:
RedWindow(Rect rect) : Basic_Window(Rect rect) <>
>;
RedWindow red_window(default_rect);

Но red_window появится белым, а не красным! Чтобы создать RedWindow, родительский объект должен быть создан первым. После завершения Basic_Window::Basic_Window(), виртуальные таблицы RedWindow вступают в силу, метод handle_create_event() становится неприменимым, и конструктор RedWindow() выполняется.

Конструктор Basic_Window() регистрирует объект графического инструментария, который мгновенно начинает посылать события объекту (например, CREATE-событие). Конструктор Basic_Window() еще не закончен (это не гарантировано), поэтому переопределенный виртуальный метод еще не на месте. Таким образом, CREATE-событие будет обрабатываться Basic_Window::handle_create_event(). Виртуальные таблицы RedWindow класса будут созданы лишь тогда, когда базовый класс полностью построен, то есть, когда окно уже на экране. Изменение цвета окна на данном этапе приведет к досадной ошибке.

Читайте также:
Написать программу которая определяет количество цифр в числе

Есть простой обходной путь: запретить каждому конструктору регистрировать объект графического инструментария. Обработка событий будет построена таким образом, чтобы сдержать окончание инициализации до производных классов. Очень заманчиво рассматривать виджеты на экране, как «лицо» объекта GUI приложения в памяти. Как показывает приведенный выше пример, эта связь между экраном и C++ объектом реализовать не так просто: они рождаются отдельно.

Нет синтаксических средств переключения событий

Предположим, что библиотека классов включает в себя графический интерфейс класса PictWindow, который отображает фотографию в окно:

Монитор порта, отладка

Как мы с вами знаем из урока “Что умеет микроконтроллер“, у многих микроконтроллеров есть интерфейс UART, позволяющий передавать и принимать различные данные. У интерфейса есть два вывода на плате – пины TX и RX. На большинстве Arduino-плат к этим пинам подключен USB-UART преобразователь (расположен на плате), при помощи которого плата может определяться компьютером при подключении USB кабеля и обмениваться с ним информацией. На компьютере создаётся виртуальный COM порт (последовательный порт), к которому можно подключиться при помощи программ-терминалов и принимать-отправлять текстовые данные. Таким же образом кстати работают некоторые принтеры и большинство станков с ЧПУ.

В самой Arduino IDE есть встроенная “консоль” – монитор порта, кнопка с иконкой лупы в правом верхнем углу программы. Нажав на эту кнопку мы откроем сам монитор порта, в котором будут настройки:

Если с отправкой, автопрокруткой, отметками времени и кнопкой очистить вывод всё и так понятно, то конец строки и скорость мы рассмотрим подробнее:

  • Конец строки: тут есть несколько вариантов на выбор, чуть позже вы поймёте, на что они влияют. Лучше поставить нет конца строки, так как это позволит избежать непонятных ошибок на первых этапах знакомства с платформой.
  • Нет конца строки – никаких дополнительных символов в конце введённых символов после нажатия на кнопку отправка или клавишу Enter.
  • NL – символ переноса строки в конце отправленных данных.
  • CR – символ возврата каретки в конце отправленных данных.
  • NL+CR – и то и то.

Объект Serial

Начнём знакомство с одним из самых полезных инструментов Arduino-разработчика – Serial, который идёт в комплекте со стандартными библиотеками. Serial позволяет как просто принимать и отправлять данные через последовательный порт, так и наследует из класса Stream кучу интересных возможностей и фишек, давайте сразу их все рассмотрим, а потом перейдём к конкретным примерам.

Serial.begin(speed)

Запустить связь по Serial на скорости speed (измеряется в baud, бит в секунду). Скорость можно поставить любую, но есть несколько “стандартных” значений. Список скоростей для монитора порта Arduino IDE:

  • 300
  • 1200
  • 2400
  • 4800
  • 9600 чаще всего используется, можно назвать стандартной
  • 19200
  • 38400
  • 57600
  • 115200 тоже часто встречается
  • 230400
  • 250000
  • 500000
  • 1000000
  • 2000000 – максимальная скорость, не работает на некоторых китайских платах

Прекратить связь по Serial. Также освобождает пины RX и TX.
Serial.available()
Возвращает количество байт, находящихся в буфере приёма и доступных для чтения.
Serial.availableForWrite()

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

Serial.write(val), Serial.write(buf, len)

Отправляет в порт val численное значение или строку, или отправляет количество len байт из буфера buf. Важно! Отправляет данные как байт (см. таблицу ASCII), то есть отправив 88 вы получите букву X: Serial.write(88); .

Serial.print(val), Serial.print(val, format)

Отправляет в порт значение val – число или строку, фактически “печатает”. В отличие от write выводит именно текст, т.е. отправив 88, вы получите 88: Serial.print(88); . Отправляет любые стандартные типы данных: численные, символьные, строковые. Также методы print()/println() имеют несколько настроек для разных данных, что делает их очень удобным инструментом отладки:

Serial.print(78); // выведет 78 Serial.print(1.23456); // 1.23 (по умолч. 2 знака) Serial.print(‘N’); // выведет N Serial.print(«Hello world.»); // Hello world. // можно сделать форматированный вывод в стиле Serial.print(«i have » + String(50) + » apples»); // выведет строку i have 50 apples // вместо чисел можно пихать переменные byte appls = 50; Serial.print(«i have » + String(appls) + » apples»); // выведет то же самое

format позволяет настраивать вывод данных: BIN, OCT, DEC, HEX выведут число в соответствующей системе счисления: двоичная, восьмеричная, десятичная (по умолчанию) и 16-ричная. Цифра после вывода float позволяет настраивать выводимое количество знаков после точки:

Serial.print(78, BIN); // вывод «1001110» Serial.print(78, OCT); // вывод «116» Serial.print(78, DEC); // вывод «78» Serial.print(78, HEX); // вывод «4E» Serial.print(1.23456, 0); // вывод «1» Serial.print(1.23456, 2); // вывод «1.23» Serial.print(1.23456, 4); // вывод «1.2345»
Serial.println(), Serial.println(val), Serial.println(val, format)

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

Serial.flush()
Ожидает окончания передачи данных.
Serial.peek()

Возвращает текущий байт с края буфера, не убирая его из буфера. При вызове Serial.read() будет считан тот же байт, но из буфера уже уберётся.

Serial.read()
Читает и возвращает крайний символ из буфера.
Serial.setTimeout(time)

Устанавливает time (миллисекунды) таймаут ожидания приёма данных для следующих ниже функций. По умолчанию равен 1000 мс (1 секунда).

Serial.find(target), Serial.find(target, length)

Читает данные из буфера и ищет набор символов target (тип char ), опционально можно указать длину length. Возвращает true , если находит указанные символы. Ожидает передачу по таймауту.

Читайте также:
Как сделать мод на Майнкрафт без программ

// будем искать слово hello char target[] = «hello»; void setup() < Serial.begin(9600); >void loop() < if (Serial.available() >0) < if (Serial.find(target)) Serial.println(«found»); // вывести found, если было послано >>
Serial.findUntil(target, terminal)

Читает данные из буфера и ищет набор символов target (тип char ) либо терминальную строку terminal. Ожидает окончания передачи по таймауту, либо завершает приём после чтения terminal.

Serial.readBytes(buffer, length)

Читает данные из порта и закидывает их в буфер buffer (массив char[] или byte[] ). Также указывается количество байт, который нужно записать – length (чтобы не переполнить буфер).

Serial.readBytesUntil(character, buffer, length)

Читает данные из порта и закидывает их в буфер buffer (массив char[] или byte[] ), также указывается количество байт, который нужно записать – length (чтобы не переполнить буфер) и терминальный символ character. Окончание приёма в buffer происходит при достижении заданного количества length, при приёме терминального символа character (он в буфер не идёт) или по таймауту

Serial.readString()

Читает порт, формирует из данных строку String , и возвращает её (урок про стринги). Заканчивает работу по таймауту.

Serial.readStringUntil(terminator)

Читает порт, формирует из данных строку String , и возвращает её (урок про стринги). Заканчивает работу по таймауту или после приёма символа terminator (символ char ).

Serial.parseInt(), Serial.parseInt(skipChar)

Читает целочисленное значение из порта и возвращает его (тип long ). Заканчивает работу по таймауту. Прерывает чтение на всех знаках, кроме знака – (минус). Можно также отдельно указать символ skipChar, который нужно пропустить, например кавычку-разделитель тысяч (10’325’685), чтобы принять такое число.

Serial.parseFloat()
Читает значение с плавающей точкой из порта и возвращает его. Заканчивает работу по таймауту.

Плоттер

Помимо монитора последовательного порта, в Arduino IDE есть плоттер – построитель графиков в реальном времени по данным из последовательного порта. Достаточно отправлять значение при помощи команды Serial.println(значение) и открыть плоттер по последовательному соединению, например построим график значения с аналогового пина A0:

void setup() < Serial.begin(9600); >void loop()

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

значение1 пробел_или_запятая значение2 пробел_или_запятая значение3 пробел_или_запятая перенос_строки

Давайте выведем значения с аналоговых пинов A0, A1 и A2:

void setup() < Serial.begin(9600); >void loop()

Получим вот такие графики:

blank

В Arduino IDE с версии 1.8.10 добавили возможность подписать графики, для этого перед выводом нужно отправить названия в виде название 1, название 2, название n с переносом строки, и дальше просто выводить данные:

Отправка в порт

blank

Рассмотрим самый классический пример для всех языков программирования: Hello World!

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

Давайте вспомним урок циклы и массивы и выведем в порт элементы массива:

void setup() < Serial.begin(9600); byte arr[] = ; for (byte i = 0; i < 8; i++) < Serial.print(arr[i]); Serial.print(‘ ‘); >> void loop()

Вывод: 0 50 68 85 15 214 63 254 – элементы массива, разделённые пробелами.

Чтение из порта

Проблемы возникают при попытке принять данные в порт. Дело в том, что метод read() читает один символ, а если вы отправите длинное число или строку – программа получит его по одному символу. Чтение сложных данных называется парсинг. Его можно делать вручную, об этом мы поговорим в отдельном уроке из блока “Алгоритмы”. В рамках этого урока рассмотрим встроенные инструменты для парсинга Serial.

Чтобы не нагружать программу чтением пустого буфера, нужно использовать конструкцию

if (Serial.available()) < // тут читаем >

Таким образом чтение будет осуществляться только в том случае, если в буфере есть какие-то данные.

Парсинг цифр

Для чтения целых цифр используем Serial.parseInt() , для дробных – Serial.parseFloat() . Пример, который читает целое число и отправляет его обратно:

void setup() < Serial.begin(9600); >void loop() < if (Serial.available()) < int val = Serial.parseInt(); Serial.println(val); >>

Если при парсинге у вас появляются лишние цифры – поставьте “Нет конца строки” в настройках монитора порта

Вы заметите, что после отправки проходит секунда, прежде чем плата ответит в порт. Эта секунда является таймаутом, о котором мы говорили чуть выше. Программа ждёт секунду после принятия последнего символа, чтобы все данные успели прийти. Секунда это очень много, ожидать, скажем, 50 миллисекунд. Это можно сделать при помощи метода setTimeout() .

void setup() < Serial.begin(9600); Serial.setTimeout(50); >void loop() < if (Serial.available()) < int val = Serial.parseInt(); Serial.println(val); >>

Теперь после отправки цифры программа будет ждать всего 50 мс и ответит гораздо быстрее!

Парсинг текста

Проще всего прочитать текст в String-строку (урок про них). Это максимально не оптимально, но зато довольно просто для восприятия:

void setup() < Serial.begin(9600); Serial.setTimeout(50); >void loop() < if (Serial.available()) < String str = Serial.readString(); Serial.println(str); >>

Рейтинг
( Пока оценок нет )
Загрузка ...
EFT-Soft.ru