Оконное приложение

Содержание

Оконное приложение

Наверное, вы уже поняли, что полноэкранным приложениям в этой книге уделяется особое внимание. Все программы на CD-ROM работают в полноэкранном режиме, и в этой главе до настоящего момента все внимание было сосредоточено исключительно на полноэкранных приложениях.

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

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

Структура приложения

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

Инициализация

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

Сначала указатель на интерфейс DirectDraw ( ddraw1 ) инициализируется функцией DirectDrawCreate() . Указатель ddraw1 , как и в полноэкранной версии, используется только для получения указателя на интерфейс DirectDraw2 , после чего освобождается.

Затем функция OnCreate() вызывает функцию SetCooperativeLevel() . В полноэкранном приложении уровень кооперации определялся тремя флагами: DDSCL_EXCLUSIVE , DDSCL_FULLSCREEN и DDSCL_ALLOWMODEX . В данном случае используется только флаг DDSCL_NORMAL .

Функция DetectDisplayMode() инициализирует некоторые переменные класса DirectDrawWin . Она выглядит так:

Функция DetectDisplayMode() с помощью функции GetDisplayMode() интерфейса DirectDraw получает информацию о текущем видеорежиме Windows. Говоря точнее, разрешение экрана и глубина пикселей текущего видеорежима сохраняются в переменных displayrect и displaydepth .

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

Листинг 3.4. Функция CreateFlippingSurfaces() в оконном приложении

Сначала мы создаем первичную поверхность. В полноэкранном варианте код выглядит по-другому, потому что здесь создается обычная, несоставная первичная поверхность. В структуре DDSURFACEDESC мы описываем первичную поверхность, используя только флаг DDSCAPS_PRIMARYSURFACE . Затем описанная поверхность создается функцией CreateSurface() интерфейса DirectDraw .

Далее функция CreateClipper() интерфейса DirectDraw создает объект отсечения. CreateClipper() получает три аргумента, однако первый и последний из них чаще всего равны нулю. Второй аргумент представляет собой адрес указателя на интерфейс DirectDrawClipper . В нашем случае используется переменная класса DirectDrawWin с именем clipper .

Объект отсечения нужен для ограничения вывода в программе. Поскольку наше приложение работает в окне, которое находится на рабочем столе вместе с другими окнами, при обновлении изображения необходимо учитывать присутствие этих окон. Чтобы объект отсечения автоматически выполнял свою работу, его необходимо присоединить к окну функцией SetHWnd() интерфейса DirectDrawClipper . Функция SetHWnd() получает два аргумента — двойное слово ( DWORD ), которое зарезервировано для будущего использования и пока должно быть равно нулю, и логический номер окна приложения.

Далее объект отсечения присоединяется к первичной поверхности приложения функцией SetClipper() интерфейса DirectDrawSurface . После такого присоединения можно осуществлять блиттинг на первичную поверхность с помощью функции Blt() интерфейса DirectDrawSurface . Использовать функцию BltFast() нельзя, потому что она не поддерживает отсечения.

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

Функция CreateFlippingSurfaces() пытается создать «идеальный» вторичный буфер, для чего используются флаг DDSCAPS_VIDEOMEMORY и функция CreateSurface() . Если вызов заканчивается успешно, флаг videobacksurf получает значение TRUE , а функция завершает работу. В противном случае вторичный буфер не создается, а флагу videobacksurf присваивается значение FALSE .

В таком варианте вторичный буфер создается приложением в системной памяти позднее, в обработчике OnSize() . Функция OnSize() вызывается при изменении размеров окна приложения. Создавая вторичный буфер по размерам клиентской области окна, мы экономим память. Функция OnSize() выглядит так:

Инициализация приложения завершается вызовом функций StorePixelFormatData() и CreateCustomSurfaces() , происходящим в обработчике OnCreate() . Обе функции ведут себя точно так же, как и в полноэкранном приложении.

Графический вывод

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

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

Вторая блит-операция копирует содержимое вторичного буфера на первичную поверхность. На этот раз используется функция Blt() , поскольку к первичной поверхности присоединен объект отсечения. Структуры srect и drect типа RECT определяют области источника и приемника, участвующие в блиттинге. Заметьте, что при вычислении области приемника используются переменные offsetx и offsety , в которых хранятся координаты клиентской области окна. Если убрать эти смещения из структуры drect , программа всегда будет выводить изображение в левом верхнем углу экрана независимо от расположения окна.

Оконное приложение

На этом уроке мы напишем оконное приложение на ассемблере. Я буду писать его на MASM. Это приложение я постарался сделать наиболее минимальным и понятным.

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

Этой строкой мы указываем, какая функция будет обрабатывать сообщения окна. Функция, которая обрабатывает сообщения окна, называется оконной функцией. Оконная функция вызывается всякий раз, когда окну было прислано какое-либо сообщение.

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

Потом мы вызываем RegisterClass, единственным параметром которой является указатель на структуру, которая описывает новый класс окна.

Потом мы создаём окно с помощью функции CreateWindowEx.

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

В оконной функции мы получаем сообщение и обрабатываем его. Если тип сообщения WM_DESTROY, то мы прыгаем на соответствующую метку, после которой вы выходим из нашей программы. Если была нажата клавиша, то мы продолжаем обработку и смотрим, нажата ли клавиша escape, если да, то выходим. Если сообщение, какое либо другое, то вызываем стандартный обработчик сообщений окна. Этот обработчик превращает наше окно в настоящее «живое» окно, которое может двигаться, расширятся и свёртываться. Можно и не вызывать эту функцию, но для того чтобы окно стало живым нам придётся вручную обрабатывать все сообщения окна, а это просто нецелесообразно.

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

Как создать оконное приложение с помощью MinGW

11.10.2012, 01:10

Как создать оконное приложение?
Всем привет . Я програмирую на Dev C++ Хотелось бы узнать как можно создать рабочее окно для.

Как создать оконное приложение?
товарищи! изучал c++ с помощью консольных приложений,программировал в codeblocks. теперь хотелось.

Как создать оконное приложение
Добрый вечер! Хочу понять, как создать оконное приложение для windows. Читал про qt, про vs, где.

Как создать оконное приложение в Visual Studio C++
Доброго времени суток. Нужна помощь. Как создать оконное приложение в Visual Studio (не знаю т.к.

Как написать оконное приложение на С++?
Здравствуйте, возможно уже было но все же. Хочу написать оконное приложение,используя C++.

Программирование для окон

Вам еще не надоело создавать консольные приложения? Я так и знал: Ну что ж, тогда я не зря старался при написании данного материала, который обязан пролить свет на программирование в среде Windows, и научить вас создавать полноценные оконные приложения, в зависть вашему соседу, который еще этого не умеет.

Система, основанная на сообщениях

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

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

Win32 API

Win32 API (Application Programming Interface — интерфейс прикладного программирования) — это набор функций, позволяющих программисту создавать приложения для Windows. Win32 API является основой для каждой Windows-программы.

Программисты, пишущие на С++ уже привыкли, что точкой входа в программу является функция main(). Но в системе Windows это не так. Все Win32-приложения используют в качестве точки входа в программу функцию WinMain. Ее объявление можно найти в заголовочном файле winbase.h:

Давайте рассмотрим все ее аргументы:

  • hInstance — идентификатор экземпляра приложения.
  • hPrevInstance — идентификатор предыдущего экземпляра приложения. В Win32 он всегда равен нулю.
  • lpCmdLine — указатель на командную строку.
  • nShowCmd — флаги для окна.

Как видите — все не так сложно! Вас, наверное, удивили только какие-то непонятные типы данных. Не волнуйтесь — разберемся.

Типы данных в Windows

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

Таблица 1

BOOL, BOOLEAN Булев. Имеет только 2 значения: TRUE или FALSE
CHAR 8-битный символ (ANSI Windows)
WCHAR 16-битный символ (Unicode)
TCHAR CHAR или WCHAR (если используется Unicode)
USHORT, WORD Целое беззнаковое 16-битное число
DWORD, DWORD32, UINT32 Целое беззнаковое 32-битное число
DWORD64, UINT64, ULONGLONG Целое беззнаковое 64-битное число
FLOAT Число с плавающей точкой
SHORT Целое знаковое 16-битное число
INT, INT32, LONG, LONG32 Целое знаковое 32-битное число
INT64, LONG64, LONGLONG Целое знаковое 64-битное число
VOID Пустой тип

Структура Windows-программ

Каждая Windows-программа состоит как минимум из двух основных функций. Это WinMain и функция окна.

Давайте напишем простую программу, создающую пустое окно. Для этого в Visual C++ создайте пустой проект Win32 Application, добавьте новый файл (например, myprog.cpp), и вставьте туда следующий код:

Теперь давайте рассмотрим приведенный код подробнее.

К сожалению, привести здесь описания всех типов данных, структур, функций и т.д., используемых в Win32 API, не представляется возможным, поэтому советую обратиться к официальному источнику, где можно найти всю необходимую информацию о программировании под Windows — Microsoft Developer Network (msdn.microsoft.com).

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

  • style — стиль окна данного класса.
  • lpfnWndProc — указатель на функцию окна, которая вызывается каждый раз при получении окном нового сообщения.
  • cbClsExtra и cbWndExtra — дополнительный размер резервируемой памяти (в байтах) для структур класса и окна.
  • hInstance — идентификатор приложения.
  • hIcon — идентификатор иконки, связанной с классом.
  • hCursor — идентификатор курсора, связанного с классом.
  • hbrBackground — идентификатор кисти, которой будет закрашен фон окна.
  • lpszMenuName — имя меню.
  • lpszClassName — имя создаваемого класса окна.

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

После регистрации класса окна можно приступать к созданию самого окна. Для этого используется функция CreateWindow(), которая возвращает хендл создаваемого окна.

Создав окно, нам необходимо отобразить его на экране. Этим занимается функция ShowWindow(), которая принимает в качестве аргументов идентификатор окна, и флаг, указывающий на способ отображения окна (в данном случае SW_SHOW, определяющий, что окно необходимо показать на экране). Затем, с помощью функции UpdateWindow() мы посылаем нашему окну сообщение WM_PAINT, указывающее на необходимость перерисовать клиентскую область окна.

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

Илон Маск рекомендует:  Посчитать модуль числа в Excel

Функция GetMessage() возвращает ненулевое значение, поэтому цикл не завершается до момента завершения программы. При завершении программы окну посылается сообщение WM_QUIT, которое является единственным сообщением, при получении которого функция GetMessage() возвращает ноль, и цикл обработки сообщений завершается, а код выхода из программы, хранящийся в элементе wParam структуры MSG, возвращается функцией WinMain.

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

  • hWnd — идентификатор окна.
  • msg — код текущего сообщения.
  • wParam и lParam — дополнительная информация о сообщении.

В Windows существует более тысячи стандартных сообщений. Конечно же, программист не должен обрабатывать их все. Для этого существует функция DefWindowProc(), которая обрабатывает переданное ей сообщение по умолчанию. Таким образом, вы должны обрабатывать только те сообщения, обработка по умолчанию которых вас не устраивает. Также, функция DefWindowProc() не обрабатывает сообщение WM_DESTROY, поэтому вы должны предусмотреть его обработку самостоятельно. В приведенном примере, при получении окном сообщения WM_DESTROY, мы, с помощью функции PostQuitMessage(), ставим в очередь сообщение WM_QUIT, чтобы завершить работу программы.

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

Вот оно, чудо

Теперь, разобравшись с кодом программы, откомпилируйте созданный проект и запустите приложение. Вы увидите пустое окно, с которым уже можно выполнять стандартные действия — перемещать, изменять размеры, сворачивать/разворачивать, и даже закрыть! : Все это достигается одним единственным стилем окна WS_OVERLAPPEDWINDOW, определенным при создании окна функцией CreateWindow().

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

Ресурсы программы

Практически в каждой Windows-программе можно увидеть различные элементы управления, меню, и другие ресурсы программы. Создать в окне какой либо элемент управления, например, кнопку, можно двумя способами. Первый, это создать новое окно используя функцию CreateWindow() с предопределенным в системе оконным классом «button». Второй способ, это использовать файлы ресурсов, в которых содержится описания всех ресурсов программы, будь то меню, элементы управления, иконки и даже диалоговые окна. Каждый элемент управления имеет свой уникальный идентификатор (хендл) определяемый программистом. Когда пользователь совершает какие либо действия над элементом управления, сообщение об этом поступают окну, и после этого выполняются соответствующие действия. К примеру, при нажатии на кнопку окно получает сообщение WM_COMMAND, которое в параметре wParam содержит идентификатор кнопки.

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

Как написать оконное приложение? [закрыт]

Хочу писать в Visual Studio хотя можно и в чём-нибудь другом, язык С++.

Посоветуйте книги, статьи. Слышал в VS есть Windows Forms, только методом тыка не получилось разобраться.

Поступили предложения использовать Windows Forms, WPF, MFC и Qt. Так, а что лучше?

Закрыт по причине того, что не по теме участниками Nick Volynkin ♦ , Aries, Visman, tutankhamun, ermak0ff 21 сен ’15 в 7:50 .

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

  • «Вопросы-опросники запрещены на Stack Overflow на русском. Для получения ответа, перефразируйте ваш вопрос так, чтобы на него можно было дать однозначно правильный ответ.» – Aries, tutankhamun, ermak0ff

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

4 ответа 4

Первым шагом стоит скачать и установить на свою машину Visual C++ Express (если она еще не установлена). Вторым шагом зайти на страницу MSDN Создание приложений Win32 (C++) и выполнить по пунктам все, что там написано. Третьим шагом заглянуть в раздел Интерактивный учебник по Visual C++: там есть, что почитать. Возможно, и книги не понадобятся. :)

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

Почитайте «Visual C++ и MFC» Мешков А., Тихомиров Ю.

Несмотря на то что давно издана, на мой взгляд самая доходчивая книга про использование MFC. А Windows Forms не получиться использовать на C++ (как уже написал в одном из комментариев). Поскольку Windows Forms доступен только на платформе .NET и язык должен быть соответствующим, например C++/CLI.

Привет :) Не слушай usrex-а :))))

ООП на Java примерах (OOP in Java examples)

У Вас уже должны быть установлены среда разработки приложений NetBeans и JDK (Java Development Kit).

Запустите NetBeans. В меню выберите File/NewProject/Java/ и введите pro1 в ответ на запрос имени проекта, а затем нажмите Finish. При этом будет создан файл Pro1.java с классом Pro1 и пустым методом main() в нем.

Добавим следующий код в этот метод:

Для запуска программы выберем в меню Run /Run Project. В нижней панели отобразится результат работы программы:

Простейшее оконное приложение

Построим изучение основ языка Java на аналогиях, сравнивая его с языком C++. В начале рассмотрим программы, подобные простейшим MFC приложениям.

Начнем с простого, создадим программу, которая показывает пустое окно.

Исходный код программы:

Последовательность выполнения (обозначена 1-4) практически та же, что и для простейшего оконного MFC приложения. При разработке Java приложения программист использует базовые классы, строит производные от них классы. Проект программы может содержать несколько классов. Один из классов проекта содержит функцию main, которая есть точкой входа в программу. Имя класса должно совпадать с именем файла, в котором класс описан.

Java – полностью объектно-ориентированный язык, даже в большей степени, чем C++. Функции и переменные, не привязанные к контексту какого-либо объекта, больше не присутствуют в системе. Примером есть функция main и объект приложения app, которые в Java приложении отнесены к создаваемому классу приложения. В MFC приложении отсутствует функция main (WinMain спрятана в MFC каркасе) и объект приложения создается как глобальная переменная.

Полностью исключена препроцессорная обработка. Операция включения в программу файлов-заголовков с описаниями классов (include) заменена на операцию import, которая читает подготовленные бинарные файлы с описанием классов. Для поддержки пользовательских интерфейсов язык Java содержит библиотеки AWT и Swing, позволяющие создавать и поддерживать окна, использовать элементы управления (кнопки, меню, полосы прокрутки и др.), применять инструменты для создания графических приложений.

В Java отсутствуют указатели, хотя все переменные объектного типа являются ссылками. Создаются такие переменные динамически – через оператор New. При этом исчезла необходимость явно управлять памятью вызовами функции free или оператором delete, поскольку в систему встроен автоматический «сборщик мусора». Он освобождает память, на которую больше нет ссылок.

Оконное приложение с обработкой событий

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

Вначале создадим метку (countLabel) а также две командные кнопки (addCrow и removeCrow) и разместим компоненты в окне:

Посмотрите, как выполнялась аналогичная задача в MFC приложении. Существенное отличие лишь в том, как созданные в окне компоненты удаляются. В MFC приложении они удаляются в деструкторе оператором delete. В Java приложении память, на которую больше нет ссылок, освобождается автоматически «сборщиком мусора».

Добавление событий

Пришло время добавить немного интерактивности. Нам нужно сделать 3 вещи:

  1. Научить кнопку addCrow добавлять 1 к переменной voron.
  2. Научить кнопку removeCrow вычитать 1 из переменной voron.
  3. Научить кнопку countLabel обновлять свое значение в зависимости от содержимого переменной voron.

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

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

В Java для определения события используются три действующих лица – объект-источник события, объект-слушатель события и объект-событие.

Мы создаем сначала кнопку (объект-источник). При вызове метода addActionListener создается объект класса ActionListener (слушатель). При вызове обработчика события (метод actionPerformed) создается объект класса ActionEvent (событие), в котором объединены параметры события.

Объекты – источники событий должны быть объектами класса, который имеет методы для регистрации слушателя addXXXListener и отключения слушателя removeXXXListener. Здесь под XXX подразумевается некоторое имя события. Например, ActionListener или AWTEventListener, и т.д.

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

Создание картинки в окне

Для создания картинки необходимо в класс окна добавить панель – элемент класса, производный от класса Jpanel. Объектами на панели могут быть подгружаемые картинки, либо рисунки, выполненные инструментами Java 2D API.

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

Анимация изображения

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

Исходный код программы приводится ниже. Файл рисунка «star.png» размещается в директории, где находятся файлы классов проекта.

В классе Board используется интерфейс ActionListener, реализованный в подключаемом библиотечном классе javax.swing.Timer. С помощью интерфейса к объекту класса Board (источнику события) подключается объект «таймер» (слушатель события). Функция actionPerformed (обработчик события) вызывается через каждые 25 мс. Промежуток времени устанавливается при создании объекта timer.

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

Дополнительно к рассмотренной реализации класса Board ниже приводятся две альтернативные версии.

Board.java (2-я версия)

Board.java (3-я версия)

Анимация объектов с помощью потока (Thread) — самый точный способ анимации. Он реализуется через интерфейс Runnable. В предыдущих примерах мы выполнили задачу через определенные промежутки времени. В этом примере анимация будет проходить внутри потока.

Метод addNotify () вызывается после того, как панель была добавлена в JFrame компонент — add(new Board()). Этот метод часто используется для различных задач инициализации.

Метод run () вызывается только один раз — после создания объекта animator, при его запуске: animator.start(). Из этого метода в бесконечном цикле while вызываются методы cycle () и repaint (). Время выполнения этих методов может быть различным в каждом из while циклов. А мы хотим, чтобы анимация проходила на постоянной скорости. Поэтому вычисляем разницу timeDiff системного времени до и после запуска обоих методов. Эту разницу вычитаем из константы DELAY (50 мс), корректируя тем самым необходимую задержку (sleep) выполнения потока.

Ошибки, возникшие в программе во время её работы обрабатываются через исключения. Обработка исключений произведена в программе с помощью операторов try…catch.

Игровое приложение ”Snake”

Snake (Змея) – одна из старейших классических видеоигр. В этой игре голова змеи перемещается с помощью клавиш управления курсором, хвост следует за ней.

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

Исходный код программы приводится ниже. Файлы рисунка «1.png» и «2.png» размещается в директории, где находятся файлы классов проекта. Анимация реализуется через рассмотренный выше способ использования таймера (см. Анимация изображения).

Контрольные задания

Ознакомиться с программой “Snake” и последовательно модифицировать ее:

  1. Автоматизировать работу программы, т.е. обеспечить движение змейки к яблоку, без вмешательства пользователя.
  2. Обеспечить передвижение яблока (жертвы) в точку (random — выбор).
  3. Обеспечить с помощью клавиш управления курсором передвижение яблока. При этом игра приобретает новый статус, где жертва (например, мышка) убегает от охотника.
  4. Обеспечить управление передвижением жертвы с помощью мышки.

Сетевые приложения

Краткий обзор сетевых приложений

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

В приложениях используется клиент-серверная парадигма, которую примерно можно определить следующим образом:

  1. Одна из программ, называемая сервером, ожидает, пока программа-клиент подключится к ней.
  2. Клиент подключается.
  3. Сервер и клиент обмениваются информацией.
  4. Связь между клиентом и сервером закрывается.

Каждое из приложений демонстрирует решение определенной задачи:

– Приложение “A Date Server and Client” обеспечивает простую одностороннюю связь. Сервер отправляет данные только одному подключенному клиенту.

– Приложение “A capitalize server and client” демонстрирует двустороннюю связь сервера с множеством подключенных к нему клиентов.

– Игра для двух игроков “Крестики-нолики” показывает работу сервера, который должен следить за состоянием игры и информировать клиентов, чтобы каждый мог обновить свои данные в соответствии с изменениями у другого клиента. Т.е., сервер выступает в качестве посредника при общении 2-х клиентов между собой.

Приложение “Date Server and Client” с одним клиентом

Приложение состоит из 2-х программ, одна выполняется на стороне сервера, другая – на стороне клиента. При последовательном запуске программ в окне консоли появляется сообщение об активизации сервера и клиента.

Перед очередным запуском программ не забывайте закрывать программы, которые остались открытыми ( running… ) от предыдущих запусков (см. нижнюю строку окна «Output»).

При запуске программы-клиента также появляется окно “Input”. После ввода в текстовое окно IP-адреса сервера (localhost) появляется окно “Message” с данными от сервера (текущая дата и время).

Исходный код программы-сервера (файл DateServer.java):

Программа-сервер постоянно находится в состоянии ожидания, она прослушивает (listen) сеть, ожидая запросов от клиентов. Программа содержит класс DateServer с единственным методом main. Причем, этот метод объявляется так, что он может выбросить исключение (throws IOException).

В программе создаются сокеты. Сокет представляет собой программную конструкцию (объект), которая определяет конечную точку соединения. Вначале создается объект класса ServerSocket, затем — в бесконечном цикле ожидания while (true) объект класса Socket. Главное отличие ServerSocket от Socket, что объект первого класса (listener) заставляет программу ждать подключений. При подключении метод listener.accept() создает объект socket.

Затем создается объект out класса PrintWriter для вывода текста в поток. В параметрах конструктора указывается направление потока socket.getOutputStream() (выходной поток сокета) и задается автоматический сброс буфера (параметр autoFlush = true). Метод out.println (“текст”) обеспечивает запись текста в поток.

В бесконечном цикле while (true) можно передавать данные множеству подключаемых клиентов, если закомментировать break. Однако, при этом не предусмотрено закрытие объекта listener, оно возможно лишь через диспетчер задач (вызывается клавишами ctrl-alt-delete).

Исходный код программы-клиента (файл DateClient.java):

Вначале запускается dialog box с предложением ввести IP address сервера, затем клиент присоединяется к серверу (создается сокет s) и тот передает ему дату и время, которые отображаются в диалоговом окне.

Для получения данных от сервера открывается входной поток s.getInputStream(). А далее цепочка читателей: InputStreamReader читает байты из потока и преобразует их в символы; BufferedReader объединяет символы в строку. Строка отображается в диалоговом окне.

Приложение “Capitalization Server and Client” с несколькими клиентами

Это приложение, как и предыдущее, состоит из 2-х программ, одна выполняется на стороне сервера, другая – на стороне клиента. При последовательном запуске программ в окне консоли появляется сообщение об активизации сервера и клиента.

При запуске программы-клиента появляются окно “Capitalize Client” и окно “Welcome to the Capitalization Program” с текстовым окном для ввода IP-адреса сервера. После ввода IP-адреса сервера в окне “Capitalize Client” клиенту предлагается ввести строку . После ввода текста и нажатия клавиши Enter сервер получает строку, преобразует маленькие буквы в большие и возвращает обновленную строку клиенту.

Илон Маск рекомендует:  Оживляем заголовок страницы с помощью JavaScript

Сервер позволяет подключаться нескольким клиентам.

Когда один из клиентов посылает строку, содержащую точку «.», программа прекращает цикл и закрывается.

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

Программа-сервер (файл CapitalizeServer.java):

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

В классе Capitalizer (производном от Thread) с интерфейсом Runnable определены все методы, необходимые для создания потоков. В рамках класса необходимо определить метод run. Он получает управление при запуске потока методом start.

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

Программа-клиент (файл CapitalizeClient.java):

Игра для двух игроков “Крестики-нолики”

Приложение “Tic Tac Toe game” (игра “Крестики-нолики”) состоит из 2-х программ, одна выполняется на стороне сервера, другая – на стороне клиента. При последовательном запуске программ в окне консоли появляются сообщения об активизации сервера и клиента.

При запуске программы-клиента также появляется окно “Player X”, при повторном ее запуске – окно “ Player O”. Дальнейшее развитие и окончание игры видно из рисунка.

Исходный код программы-сервера и программы-клиента приводится ниже. Рисунки и размещается в директории, где находятся файлы классов проекта программы-клиента.

Программа-сервер (файл TicTacToeServer.java):

В функции main программы-сервера (файл TicTacToeServer.java) создается объект listener и запускается бесконечный цикл.

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

Далее в цикле объект listener прослушивает и подключает 2-х игроков-клиентов. Каждый из игроков (player) передается на обслуживание побочных потоков, а в конструкторе создаются сокет, потоки ввода-вывода и клиентам передаются приветствие и метка (mark) – X или O. Метка служит для идентификации клиента.

Далее потоки переходят в состояние “ Running” запуском (через start) метода run(), который определен в классе Player. В методе run() клиенту с меткой X передается сообщение начать игру («MESSAGE Your move»).

Затем организован собственный бесконечный цикл внутри потока. Здесь происходит обработка данных. От клиента (текущего игрока) поступает номер указанного мышкой квадратика, он сохраняется в переменной location. Методы класса Game по значению этой переменной и наполненности игровой доски определяют текущее состояние игры. Наполненность доски фиксируется в массиве board ссылками на игроков, которые заполнили соответствующие квадраты. Заполняется доска в методе legalMove. В соответствии с текущим состоянием игры передаются сообщения клиентам.

Метод legalMove определен с ключевым словом synchronized. Такой метод запрещает нескольким потокам одновременный доступ к нему. Прежде, чем начать выполнять его, поток пытается заблокировать объект, у которого вызывается метод. При завершении исполнения (как успешном, так и в случае ошибок) производится операция unlock, чтобы освободить объект для других потоков.

Метод legalMove вызывается в потоке игрока, который пытается сделать ход и проверяет, или ход является правильным. То есть, игрок выполняющий ход, должен быть текущим игроком и квадрат, в котором он пытается сделать ход, не должен быть уже занятым. Если ход правильный, состояние игры обновляется (квадрат заполнен, следующий игрок становится текущим, и он уведомляется о своем ходе).

Программа-клиент (файл TicTacToeClient.java):

В функции main программы-клиента запускается бесконечный цикл. В нем создается объект client класса TicTacToeClient. При этом конструктор устанавливает связь с сервером, создает сокет, потоки ввода-вывода, панель с массивом квадратных ячеек board[i]. Объекту каждой ячейки добавляется событие mousePressed, при котором через поток вывода серверу передается номер выбранной ячейки.

При вызове метода client.play() от сервера поступает сообщение о начале игры и метка (X или O), присвоенная игроку. Затем создается внутренний бесконечный цикл. Здесь происходит обработка сообщений сервера, полученных в ответ на выполненный ход (указание мышкой квадратика).

Контрольное задание

На основе игрового приложения ”Snake” создать клиент-серверное приложение для 2-х игроков, где первый управляет движением змейки, а второй – движением жертвы. Победителем считается первый игрок, если он настигает жертву за отведенное время игры (определяется таймером), в противном случае побеждает второй игрок.

С программным кодом выполнения этого задания можете ознакомиться по ссылке (Snake_net). Разработал приложение студент специальности «Компьютерные науки и информационные технологии» Лаврентий Антон.

visual C++, создание диалоговых окон.

Рассмотрим сегодня такой тип приложений приложения win32 на диалоговых окнах, visual C++, создание диалоговых окон. Приложения для windows делятся на три вида: 1. консольные — это самый простой тип приложений, 2.win32 приложения на диалоговых окнах — это самый простой тип win32 приложений и 3.просто приложения win32 это такие, где создаются дочерние окна, множество окон. Третий тип приложений считается самым сложным типом, консольные самый простой тип. Консольные приложения мы умеем создавать, а от увы win32 приложения нет.

Зачем нужно visual C++, создание диалоговых окон

Как правило все коммерческие программы содержать сильный GUI, который довольно тяжело создавать, можно например посмотреть такие программы как microsoft word или exel да и много других. Там программируются множество дочерних окон, создается множество элементов управления там сотни окон, я хз. как такие приложения создавать, они так сложновато устроены. Мы рассмотрим и будем создавать приложения которые будут состоять всего навсего из одного окошка с набором элементов. Сам я недавно с ними познакомился. Будем создавать диалоговые окна.

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

Нажимаем Ок, затем появится окошко жмем кнопку Далее и мы попадаем в окошко в котором ставим галочку на «пустой проект»

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

Создание файла main.cpp

Дальше создадим файл main.cpp со следующим кодом:

Короче вызывается просто функция DialogBox() которой передается в качестве параметра собственная процедура DlgProc() в которой мы обрабатываем 3 вида событий: WM_INITDIALOG, WM_COMMAND, WM_CLOSE. Ну в первый WM_INITDIALOG мы попадаем сразу при создании программы когда производится инициализация окна, в третий WM_CLOSE попадаем когда закрываем окно (нажимем крестик), ну и во втором параметре WM_COMMAND мы уже обрабатываем собственные события. Как видно наша процедура возвращает либо FALSE либо TRUE, если мы возвращаем FALSE, то у нас вызывается процедура которая вырисовывает окно, если мы вернем TRUE, то это означает что функция стандартная для прорисовки окна не вызовется. Это так небольшой ликбез по теории

visual C++, создание диалоговых окон, создание самого окна в редакторе

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

выбираем и мы попадаем в окно «Добавление ресурса»

Выбираем Dialog и нажимаем создать

Все диалог создан, в «Панель элементов» мы видим какие элементы мы можем добавлять, а в «Свойства» мы можем изменять свойства каждого элемента. Дальше компилируем проект, нажимаем Ctrl+F5 и у нас создается окошко с кнопкой ок и отмена

По нажатию на кнопку Ок у нас вызывается окошко

А по нажатии на кнопку отмена вызывается другое информационное окошко

Что происходит

Это все происходит потому что наша функция DialogBox() при завершении функцией EndDialog(hwnd,1); возвращает второй ее параметр поэтому в WinMain() у нас ret принимает либо 1 либо 0 смотря как была завершена функция DialogBox(), это нужно для того что б в приложениях в которых много окон, что б можно было определять какая кнопка была нажата, Ок или Отмена, это мы будем просто понимать, если Ок, то нужно применить изменения, а если Отмена то ничего не делать. Так как у нас одно оконное приложение, то нам это не нужно разбирать visual C++, создание диалоговых окон.

Это короче основа visual C++, создание диалоговых окон, от как из всего выше видно что наше приложение на диалоговых окнах очень просто создается, мы дальше разберем код как можно ввести текст через editbox и вывести на экран, а так же разберем список. Неахота сильно описывать, я просто покажу скрин проги и ниже код ее, ну а дальше опишу немножко как она работает, и так приступим, начнем со Edit Control и Button

Edit Control и Button

И так это просто поле для ввода текста и кнопка. И так создаем в визуальном редакторе для нашего прооекта visual C++, создание диалоговых окон следующий каркас:

Ну и код для работы с каркасом:

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

Ну а для того что б данные вывести в поле мы используем функцию

Тут ничего не могу сказать, сам не сильно знаю, нужно читать дополнительную литературу или МСДН, но лучше конечно Питзольда.

Дальше рассмотрим программу для работы с List Box

List Box.

Это элемент список, вы должны снова создать каркас программы.

Ну и код к этому диалоговому окну:

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

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

Рассмотрим используемые функции, тут немного функций использовано. При выделении элемента из списка у нас отправляется в наше приложение команда и мы ее можем выловить в case IDC_LIST1: , там создается оператор switch (HIWORD(wParam)) и мы ловим параметр case LBN_SELCHANGE: он будет передан при выделении списка. Мы в общем создали обработчик этого события, для того что бы определить какой элемент был выделен, получить его порядковый номер мы используем функцию

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

для удаления элемента используем функцию

для добавление элемента в список юзаем функцию

Создание диалоговых окон — ИТОГИ

Что еще сказать? Наша процедура для обработки событий состоит из трех частей. В первой части инициализируется наше приложение. Там мы инициализировали наш список тремя значениями. Пожалуй это и все. Я сам с этими функциями и возможностями недавно познакомился. Для меня это все новенькое, но уже с данными знаниями мы можем создавать какие нить приложения.

Это вообще то мелочь что мы изучили, если посмотреть визуальный редактор, то там очень много элементов и каждый элемент имеет различные свойства. То что мы рассмотрели сейчас это мелочь «ПУЗАТАЯ». Будем дальше конечно пополнять свой запас знаний, но с этими знаниями мы уже можем создавать более менее нормальные приложения. Ну от например у меня дальше по учебнику идет приложение простая база данных, от я думаю что ж сделать создать ее свою все полностью или использовать тот код что в приложении. Там библиотека dll используется. Я беспокоюсь что ее на моем компе нету. Наверно попытаюсь все таки запустить то приложение что в книге, а затем уже свое приложение создам, где я все напишу на С++ без использования либы БД.

Мне несложно записать в текстовый файл данные, а затем их оттуда извлечь, это так сказать приложение база данных телефонных номеров. Нам уже эти знания по ВИНАПИ дают возможность создавать такие приложения плюс мы будем конечно пополнять свой запас знаний по созданию ГУИ. После этой простой БД мы создадим так же простой текстовый редактор, который будет сохранять файл, открывать файл, создавать файл и все это легко делается на ВИНАПИ. Ладно приступим, хватит писать пора дело делать �� . ГУИ наконец то, аж не верится, что я дошол до его изучения.

Visual C++, создание диалоговых окон это легко для новичков с моим мега про гайдом, сможет это сделать любой школьник ��

Разработка оконных приложений C#

Под оконным приложением понимается приложение в Windows. Для разработки таких приложений в Visual Studio необходимо при создании нового проекта указать тип проекта Windows Application. В результате чего будет создан проект, представленный на рисунке 1.

Рисунок 1 – Оконное приложение

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

Для размещения элементов программно предназначена панель Toolbox, которую можно вызвать, нажав кнопку Toolbox, расположенную на части панели Standard, которая представлена на рисунке 2.

В результате чего появиться панель Toolbox, представленная на рисунке 3.

Первое оконное приложение на Qt

Первая часть статьи. Базовый обзор возможностей Qt и запуск первой Windows программы.

Приветствую тебя дорогой читатель. В этой статье мы поговорим о том как в QT можно создать первое оконное приложение используя только команды и главный файл main.cpp. Данная статья будет разделена на 2 части. В первой части мы с вами создадим само приложение и запустим его на компиляцию при помощи компилятора MinGW с очень короткими комментариями по коду, а во второй части мы разберем весь код до последней детали чтобы у вас сформировалось полное базовое понимание о том как все это работает. Итак пожалуй начнем. Первое что нам необходимо сделать это запустить QT Creator и создать проект. Я думаю нет необходимости объяснять как запустить QT Creator, так что мы начнем сразу с создания проекта.

Видео урок по данной статье

После того как QT запустился нажмите на кнопку новый проект как показано на скриншоте ниже.

Создание нового проекта в Qt

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

Выбор типа приложения

После того как вы нажали кнопку выбрать… У вас откроется следующее окно выбора дополнительных параметров, где вам будет предложено выбрать имя вашего проекта и где он будет храниться. ВАЖНО: Не допускайте русских символов в пути где у вас будет храниться ваш проект, Qt не дружит с русскими символами. Эта мера необходима чтобы в дальнейшем избежать ошибок при сборке проекта. Ниже приведен пример как правильно создать имя и путь к проекту Qt.

Выбор пути где будет храниться ваш проект

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

Далее Qt нам предлагает выбрать комплект при помощи которого мы будем разрабатывать наш проект, я выбрал комплект Desktop Qt 5.8.0 с компилятором от MinGW 32 bit. Вы можете оставить значение по умолчанию или сделать свой выбор комплекта или даже комплектов для разработки вашей программы.

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

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

В данном окне оставляем все по умолчанию

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

Илон Маск рекомендует:  Что такое код mysql_field_seek

Итог созданного проекта в Qt

После того как наш конструктор приложений завершился пришло самое время настроить наш проект так чтобы у нас была возможность выполнить простейшую программу для вывода текста на экран и проверки правильности работы нашего фреймворка. Для начала нам необходимо удалить из нашего проекта все файлы кроме файла main.cpp — вот в этом файле мы и будем в дальнейшем прописывать код для запуска окна с выводом текста в оконном режиме. Вам необходимо оставить все так же как показано на скриншоте ниже после удаления лишних файлов из проекта.

Скриншот до удаления файлов из проекта:

Чуть ниже вы можете увидеть скриншот созданного проекта конструктором Qt без изменений.

До удаления лишних файлов из проекта

Скриншот после удаления файлов из проекта:

После удаления лишних файлов из проекта

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

Удаляем весь лишний код из программы

Разработка простейшего кода для оконного приложения:

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

на Русском языке без проблем с кодировкой. Данная проблема уже была предусмотрена в Qt и решена внутренними инструментами.

Для начала добавим следующий код в наш файл main.cpp

Перепешите весь код с данного скриншота в вашу среду Qt в файл main.cpp как показано на скриншоте

Запустите ваш код при помощи зеленого треугольника слева или сочетанием горячих клавиш Ctrl+R. В итоге у вас должно получиться окно с текстом Привет мир.

Программа в запущенном состоянии

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

Вторая часть статьи. Подробный разбор кода:

До текущего момента мы с вами разобрались как можно создать простейшую программу которая только в окне выводит текст не разбираясь в подробностях кода. Теперь пришло самое время разобраться с теми командами которые мы использовали в нашей программе. Первое что мы с вами сделали, это подключили библиотеку QtWidgets — Данная библиотека включает в себя около 300 различных библиотек направленных на создания оконных приложений. Еще QtWidgets можно назвать складом строительных материалов для различных оконных приложений. Можно было конечно подключить отдельно библиотеки такие как QLabel для создания окон Windows и QApplication для обработки строк с различными аргументами. Но у нас стал бы код чуть длиннее и чуть труднее читаем. А теперь представьте если бы вы создавали программу в которой куча разных функций. И вы бы подключали к каждой функции свою библиотеку. Спустя какое то время вы бы с трудом смогли вспомнить для чего подключено такое большое количество библиотек. Вот как раз в таких случаях и выручают большие библиотеки которые содержат в себе уже весь необходимый строительный материал для создания к примеру оконных программ как QtWidgets.
Вот собственно говоря весь код нашей программы, чуть выше мы с вами уже разобрали библиотеку QtWidgets

Теперь давайте разберем наш пример. Сначала создается объект класса QApplication, который осуществляет контроль и управление приложением. Для его создания в конструктор этого класса необходимо передать два аргумента. Первый argc аргумент представляет собой информацию о количестве аргументов в командной строке, из которой происходит обращение к программе, а второй argv — это указатель на массив символьных строк, содержащих аргументы, по одному в строке. Любая использующая Qt программа с графическим интерфейсом должна создавать только один объект этого класса, и он должен быть создан до использования операций, связанных с пользовательским интерфейсом.

Затем создается объект класса QLabel. После создания элементы управления Qt по умолчанию невидимы, и для их отображения необходимо вызвать метод show(). Объект класса QLabel является основным управляющим элементом приложения, что позволяет завершить работу приложения при закрытии окна элемента. Если вдруг окажется, что в созданном приложении имеется сразу несколько независимых друг от друга элементов управления, то при закрытии окна последнего такого элемента управления завершится и само приложение. Это правильно, иначе приложение осталось бы в памяти компьютера и расходовало бы его ресурсы.
Наконец, в последней строке программы приложение запускается вызовом
QApplication::ехес(). С его запуском приводится в действие цикл обработки событий, определенный в классе QCoreApplication, являющемся базовым для QGuiApplication, от которого унаследован класс QApplication. Этот цикл передает получаемые от системы события на обработку соответствующим объектам. Он продолжается до тех пор, пока либо не будет вызван статический метод QCoreApplication::exit (), либо не закроется окно последнего элемента управления. По завершению работы приложения метод QApplication::ехес() возвращает значение целого типа, содержащее код, информирующий о его завершении. После того как вы создали весь код и запустили программу – у вас должен получиться следующий результат.

Программа в запущенном состоянии

Теперь пришло самое время разобраться как работают теги из HTML(язык гипертекстовой разметки) и CSS(каскадные таблицы стилей).

Когда вы создаете объект и передаете конструктору информацию в двойных кавычках, то конструктор автоматически создает окно при помощи QLabel и создает там текстовое поле в котором собственно и будет выводиться ваш текст. Благодаря новым возможностям от Qt есть возможность использовать различные теги от HTML и CSS. Такая возможность позволяет оформлять различные элементы программы в различных стилях что очень сильно помогает в разработке дизайна программ. Главное не забывать о том что в HTML и CSS используются такие спец. Символы как точка с запятой и двойные кавычки в для написания нескольких свойств в CSS для текста или какого то объекта. В Qt придется забыть о данных знаках при написания кода оформления в двойных кавычках так как это может вызвать ошибку при компиляции. А вот что касается простеньких свойств в HTML и CSS которые имеют не более 1 параметра, то здесь работает все корректно. Ниже привел пример оформления, с кодом вы можете ознакомится на скриншоте.

Программа в запущенном состоянии с примененными стилями из HTML и CSS

Чуть выше на скриншоте вы можете увидеть как буквально в 1 строку кода мы оформили текст в разной цветовой гамме, так же задали размер заголовка текста и добавили пару переносов строки. А теперь судите сами на сколько упрощает жизнь при оформлении программы при использовании языка гипертекстовой разметки и каскадных таблиц стилей.

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

Так же большая просьба написать в комментариях, насколько бы вам было интересно начать параллельное изучение HTML и CSS для Qt.

Программирование для окон

Вам еще не надоело создавать консольные приложения? Я так и знал: Ну что ж, тогда я не зря старался при написании данного материала, который обязан пролить свет на программирование в среде Windows, и научить вас создавать полноценные оконные приложения, в зависть вашему соседу, который еще этого не умеет.

Система, основанная на сообщениях

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

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

Win32 API

Win32 API (Application Programming Interface — интерфейс прикладного программирования) — это набор функций, позволяющих программисту создавать приложения для Windows. Win32 API является основой для каждой Windows-программы.

Программисты, пишущие на С++ уже привыкли, что точкой входа в программу является функция main(). Но в системе Windows это не так. Все Win32-приложения используют в качестве точки входа в программу функцию WinMain. Ее объявление можно найти в заголовочном файле winbase.h:

Давайте рассмотрим все ее аргументы:

  • hInstance — идентификатор экземпляра приложения.
  • hPrevInstance — идентификатор предыдущего экземпляра приложения. В Win32 он всегда равен нулю.
  • lpCmdLine — указатель на командную строку.
  • nShowCmd — флаги для окна.

Как видите — все не так сложно! Вас, наверное, удивили только какие-то непонятные типы данных. Не волнуйтесь — разберемся.

Типы данных в Windows

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

Таблица 1

BOOL, BOOLEAN Булев. Имеет только 2 значения: TRUE или FALSE
CHAR 8-битный символ (ANSI Windows)
WCHAR 16-битный символ (Unicode)
TCHAR CHAR или WCHAR (если используется Unicode)
USHORT, WORD Целое беззнаковое 16-битное число
DWORD, DWORD32, UINT32 Целое беззнаковое 32-битное число
DWORD64, UINT64, ULONGLONG Целое беззнаковое 64-битное число
FLOAT Число с плавающей точкой
SHORT Целое знаковое 16-битное число
INT, INT32, LONG, LONG32 Целое знаковое 32-битное число
INT64, LONG64, LONGLONG Целое знаковое 64-битное число
VOID Пустой тип

Структура Windows-программ

Каждая Windows-программа состоит как минимум из двух основных функций. Это WinMain и функция окна.

Давайте напишем простую программу, создающую пустое окно. Для этого в Visual C++ создайте пустой проект Win32 Application, добавьте новый файл (например, myprog.cpp), и вставьте туда следующий код:

Теперь давайте рассмотрим приведенный код подробнее.

К сожалению, привести здесь описания всех типов данных, структур, функций и т.д., используемых в Win32 API, не представляется возможным, поэтому советую обратиться к официальному источнику, где можно найти всю необходимую информацию о программировании под Windows — Microsoft Developer Network (msdn.microsoft.com).

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

  • style — стиль окна данного класса.
  • lpfnWndProc — указатель на функцию окна, которая вызывается каждый раз при получении окном нового сообщения.
  • cbClsExtra и cbWndExtra — дополнительный размер резервируемой памяти (в байтах) для структур класса и окна.
  • hInstance — идентификатор приложения.
  • hIcon — идентификатор иконки, связанной с классом.
  • hCursor — идентификатор курсора, связанного с классом.
  • hbrBackground — идентификатор кисти, которой будет закрашен фон окна.
  • lpszMenuName — имя меню.
  • lpszClassName — имя создаваемого класса окна.

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

После регистрации класса окна можно приступать к созданию самого окна. Для этого используется функция CreateWindow(), которая возвращает хендл создаваемого окна.

Создав окно, нам необходимо отобразить его на экране. Этим занимается функция ShowWindow(), которая принимает в качестве аргументов идентификатор окна, и флаг, указывающий на способ отображения окна (в данном случае SW_SHOW, определяющий, что окно необходимо показать на экране). Затем, с помощью функции UpdateWindow() мы посылаем нашему окну сообщение WM_PAINT, указывающее на необходимость перерисовать клиентскую область окна.

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

Функция GetMessage() возвращает ненулевое значение, поэтому цикл не завершается до момента завершения программы. При завершении программы окну посылается сообщение WM_QUIT, которое является единственным сообщением, при получении которого функция GetMessage() возвращает ноль, и цикл обработки сообщений завершается, а код выхода из программы, хранящийся в элементе wParam структуры MSG, возвращается функцией WinMain.

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

  • hWnd — идентификатор окна.
  • msg — код текущего сообщения.
  • wParam и lParam — дополнительная информация о сообщении.

В Windows существует более тысячи стандартных сообщений. Конечно же, программист не должен обрабатывать их все. Для этого существует функция DefWindowProc(), которая обрабатывает переданное ей сообщение по умолчанию. Таким образом, вы должны обрабатывать только те сообщения, обработка по умолчанию которых вас не устраивает. Также, функция DefWindowProc() не обрабатывает сообщение WM_DESTROY, поэтому вы должны предусмотреть его обработку самостоятельно. В приведенном примере, при получении окном сообщения WM_DESTROY, мы, с помощью функции PostQuitMessage(), ставим в очередь сообщение WM_QUIT, чтобы завершить работу программы.

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

Вот оно, чудо

Теперь, разобравшись с кодом программы, откомпилируйте созданный проект и запустите приложение. Вы увидите пустое окно, с которым уже можно выполнять стандартные действия — перемещать, изменять размеры, сворачивать/разворачивать, и даже закрыть! : Все это достигается одним единственным стилем окна WS_OVERLAPPEDWINDOW, определенным при создании окна функцией CreateWindow().

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

Ресурсы программы

Практически в каждой Windows-программе можно увидеть различные элементы управления, меню, и другие ресурсы программы. Создать в окне какой либо элемент управления, например, кнопку, можно двумя способами. Первый, это создать новое окно используя функцию CreateWindow() с предопределенным в системе оконным классом «button». Второй способ, это использовать файлы ресурсов, в которых содержится описания всех ресурсов программы, будь то меню, элементы управления, иконки и даже диалоговые окна. Каждый элемент управления имеет свой уникальный идентификатор (хендл) определяемый программистом. Когда пользователь совершает какие либо действия над элементом управления, сообщение об этом поступают окну, и после этого выполняются соответствующие действия. К примеру, при нажатии на кнопку окно получает сообщение WM_COMMAND, которое в параметре wParam содержит идентификатор кнопки.

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

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL