Бортовой журнал Ктулху

Как перестать бояться и начать писать приложения для десктопа. Простой графический клиент web API на C++ и GTK+

После многих лет программирования на РНР захотелось попробовать силы в принципиально другом направлении - в десктопной разработке на C++. Здесь сразу пропускаю вопросы типа "почему (не Python, Java, Go, etc)", просто, захотелось.

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

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

Для изучения чего-то желательно не просто сферический проект в вакууме, а нечто более или менее полезное в работе.

Так как я часто разрабатываю различные API, решил сделать клиента для отправки POST запросов. Для начала достаточно, тем более что это первый опыт разработки на C++.

Дополнительно, получу минимальный опыт в разработке интерфейсов.

Да, я написал еще один велосипед (:

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

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

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

А я посмотрел. Хром потребляет 28 мегабайт, отображая страницу, на которой меньше килобайта текста. Если на странице будет какой-либо функционал, та же форма отправки запросов, смело можно умножать на 10.

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

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

В подтверждение этому, приведу пример, когда я устанавливал на Windows 10 программу для тестирования медиков "Элекс", которая была написана пару десятков лет назад, там даже в системных требованиях указан 486 процессор.

Много ли сайтов открывается да в том же 6-м Internet Explorer?

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

Все, выдыхай, бобёр.

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

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

Я далеко не сразу пришел к этому непростому решению, пробовал писать на Java, даже кое-что работало, но хотелось выйти их лишних слоёв абстракции.

И это (пока что) просто извращенное хобби.

2021 03 15 21 32 03 1

Окно программы на текущий момент.

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

На данный момент программа умеет отправить POST запрос и получить JSON ответ. Как я написал выше, сотый раз говорю: не люблю повторяться часто  занимаюсь разработкой да и просто какой-то работой с web API, и, внезапно, могу использовать в работе свои программы :).

Дальше напишу о разработке.

Когда-то, где-то...

Интерфейс написан на GTK3, использованы стандартные элементы, такие как textview, entry. Почему именно GTK а не QT - что первое попалось в гугле, что получилось без приключений установить, то и взял, ну, и было желание написать нативное для GNOME.

Все очень просто, программа школьного уровня.

Весь код включать в статью не буду, его можно посмотреть на github

Интерфейс реализован следующим способом:

Widgets *widg = g_slice_new ( Widgets ); // набор виджетов для окна: textarea, text input
widg->textview = gtk_text_view_new(); // окно запроса
widg->textviewresp = gtk_text_view_new(); // окно ответа
gtk_text_view_set_editable(GTK_TEXT_VIEW(widg->textview), true); // редактируемое окно запроса
widg->entry = gtk_entry_new(); // поле ввода url
ok_button = gtk_button_new_with_label("Отправить запрос");

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

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

Ответ в виде json выводится в правое текстовое поле.

Как выглядит вызов Curl:

CURL *curl = curl_easy_init();
CURLcode res;
string responseBuffer;
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json"); // Currenlty we support JSON ONLY, required header
headers = curl_slist_append(headers, "Content-Type: application/json"); // Currenlty we support JSON ONLY, required header
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl,CURLOPT_POST,1);
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, txt);
/* send all data to this function */
curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L); //remove this to disable verbose output
curl_easy_setopt (curl, CURLOPT_CONNECTTIMEOUT, 5);
curl_easy_setopt (curl, CURLOPT_TIMEOUT, 5);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
http_code = 0;
res = curl_easy_perform(curl);
 if(res != CURLE_OK)
 {
 responseBuffer = fprintf(stderr, "curl_easy_perform() failed: %s\n",
 curl_easy_strerror(res));
 } else {
 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
 }
responseBuffer.replace(0,1,"{\n");
 findAndReplaceAll(responseBuffer, ",", ",\n");
gtk_text_view_set_editable(GTK_TEXT_VIEW(widg->textviewresp), true);
 buff = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widg->textviewresp));
 const gchar *rsp = responseBuffer.data();
 gtk_text_buffer_set_text (buff, rsp, -1);
 }
curl_easy_cleanup(curl);

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