NodeGui — это библиотека с открытым исходным кодом для создания кроссплатформенных собственных настольных приложений с помощью Node.js. Приложения NodeGui могут работать в macOS, Windows и Linux. Приложения, созданные с помощью NodeGui, написаны с использованием JavaScript, оформлены с помощью CSS и отображаются как собственные виджеты рабочего стола с использованием платформы Qt.
Вот некоторые особенности NodeGui:
нативные виджеты со встроенной поддержкой темного режима
низкое потребление процессора и памяти
стилизация с помощью CSS, включая полную поддержку макета Flexbox
полная поддержка Node.js API и доступ ко всем совместимым с Node.js модулям npm
отличная поддержка отладки с использованием Chrome DevTools
первоклассная поддержка TypeScript
NodeGui работает на платформе Qt, что делает его процессор и память более эффективными по сравнению с другими решениями на основе Chromium, такими как Electron. Это означает, что приложения, написанные с использованием NodeGui, не открывают экземпляр браузера и не отображают в нем пользовательский интерфейс. Вместо этого все виджеты отображаются изначально.
В этом руководстве показано, как установить NodeGui и использовать его для создания поисковика мемов, который находится в системном трее и взаимодействует с GIPHY API.
Полный исходный код этого руководства доступен на GitHub.
Установка и базовая настройка
В этом руководстве предполагается, что у вас установлен Node.js версии 12 или выше. Вы можете убедиться, что и Node, и npm доступны, запустив:
# This command should print the version of Node.js
node -v
# This command should print the version of npm
npm -v
Если вам нужна помощь на этом этапе, ознакомьтесь с нашим руководством по установке Node.
Установите CMake и инструменты компиляции
NodeGui требует инструментов компиляции CMake и C++ для создания собственного слоя C++ проекта. Убедитесь, что вы установили CMake ≥ 3.1 вместе с компилятором C++, который поддерживает C++11 и выше. Подробные инструкции немного отличаются в зависимости от вашей операционной системы.
macOS
Рекомендуется устанавливать CMake с помощью Homebrew. Запустите следующие команды в терминале после установки Homebrew:
brew install cmake
brew install make
Вы можете подтвердить установку, выполнив:
# This command should print the version of CMake which should be higher than 3.1
cmake —version
make —version
Наконец, вам понадобится GCC/Clang для компиляции кода C++. Убедитесь, что у вас установлен GCC, используя эту команду:
gcc —version
Если у вас не установлен GCC, обязательно установите Инструменты командной строки для Xcode или Инструменты разработчика XCode со страницы разработчика Apple.
Окна
Вы можете установить CMake в Windows, загрузив последнюю версию со страницы загрузки CMake.
Настоятельно рекомендуется использовать Powershell в качестве предпочтительного терминала в Windows.
Вы можете подтвердить установку CMake, запустив:
# This command should print the version of CMake which should be higher than 3.1
cmake —version
Наконец, вам нужен компилятор C++. Одна из возможностей — установить Visual Studio 2017 или более позднюю версию. В процессе установки рекомендуется выбрать настольную разработку с рабочей нагрузкой C++.
линукс
В этом руководстве мы сосредоточимся на Ubuntu 18.04. Рекомендуется устанавливать CMake с помощью менеджера пакетов. Выполните следующие команды в терминале:
sudo
sudo
Вы можете подтвердить установку, выполнив:
# This command should print the version of CMake which should be higher than 3.1
cmake —version
make —version
Наконец, вам нужен GCC для компиляции кода C++. Убедитесь, что у вас установлен GCC, с помощью команды:
# gcc version should be ≥ v7
gcc —version
Привет, мир
Чтобы начать работу с нашим
Примечание. Для запуска этого требуется Git и npm.
Откройте терминал и запустите:
git clone https://github.com/nodegui/nodegui-starter memeapp
cd memeapp
npm install
npm start
Если все пойдет хорошо, вы должны увидеть на экране работающее приложение Hello World NodeGui.
Привет, мир, пример NodeGui
По умолчанию проект
Удалите index.tsфайл в srcпапке.
Создайте новый файл index.jsв srcкаталоге со следующим содержимым:
источник/index.js
const { QMainWindow, QLabel } = require ('@nodegui/nodegui’) ;
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const label = new QLabel () ;
label.setText ('Hello World’) ;
win.setCentralWidget (label) ;
win.show () ;
global.win = win;
Что касается разработки, приложение NodeGui по сути является приложением Node.js. Все API и функции, имеющиеся в NodeGui, доступны через @nodegui/nodeguiмодуль, который может потребоваться, как и любой другой модуль Node.js. Кроме того, у вас есть доступ ко всем
В приведенном выше примере мы импортировали QMainWindow и QLabel для создания собственного окна, отображающего текст «Hello World».
Теперь снова запустите приложение:
npm start
Привет, мир
Теперь, когда у нас есть готовые базовые настройки, давайте начнем создавать наш поисковик мемов 🥳.
Примечание. Если
Отображение анимированного GIF
Поскольку мемы, как правило, представляют собой анимированные
Для этого мы будем использовать QMovie вместе с QLabel. QMovie — это не виджет, а контейнер, который может воспроизводить простые анимации. Мы будем использовать его в сочетании с QLabel.
Пример использования QMovie выглядит так:
const movie = new QMovie () ;
movie.setFileName ('/absolute/path/to/animated.gif’) ;
movie.start () ;
const animatedLabel = new QLabel () ;
animatedLabel.setMovie (movie) ;
Поскольку мы хотим загрузить изображение с
Итак, приступим к установке axios:
npm i axios
Теперь давайте создадим функцию, которая будет принимать
async function getMovie (url) {
const { data } = await axios.get (url, { responseType: 'arraybuffer’ }) ;
const movie = new QMovie () ;
movie.loadFromData (data) ;
movie.start () ;
return movie;
}
Функция getMovieпринимает
Вы можете думать о QMovieнем как о классе, который обрабатывает внутреннюю логику воспроизведения
Поскольку getMovieвозвращает обещание, нам нужно внести некоторые изменения в код. После небольшого рефакторинга получаем следующее.
источник/index.js
const { QMainWindow, QMovie, QLabel } = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
async function getMovie (url) {
const { data } = await axios.get (url, { responseType: 'arraybuffer’ }) ;
const movie = new QMovie () ;
movie.loadFromData (data) ;
movie.start () ;
return movie;
}
const main = async () => {
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const label = new QLabel () ;
const gifMovie = await getMovie (
'https: //upload.wikimedia.org/wikipedia/commons/e/e3/Animhorse.gif’
) ;
label.setMovie (gifMovie) ;
win.setCentralWidget (label) ;
win.show () ;
global.win = win;
};
main ().catch (console.error) ;
Функция main— это наша точка входа. Здесь мы создаем окно и метку. Затем мы создаем экземпляр QMovieс помощью нашей getMovieфункции и, наконец, устанавливаем QMovieзначение QLabel.
Запустите приложение, npm startи вы должны увидеть
Пример базовой анимации, показывающей скачущую лошадь
Получение
У Giphy.com есть общедоступный API, который каждый может использовать для создания отличных приложений, использующих анимированные
Мы будем использовать функцию конечной точки поиска для реализации нашего поиска мемов.
Давайте начнем с написания searchGifsфункции, которая будет принимать searchTermsпараметр в качестве входных данных и запрашивать
const GIPHY_API_KEY = 'Your API key here’;
async function searchGifs (searchTerm) {
const url = 'https: //api.giphy.com/v1/gifs/search’;
const res = await axios.get (url, {
params: {
api_key: GIPHY_API_KEY,
limit: 25,
q: searchTerm,
lang: 'en’,
offset: 0,
rating: '
}
}) ;
return res.data.data;
}
Результат функции после выполнения будет выглядеть примерно так:
[
{
«type»: «gif»,
«id»: «dzaUX7CAG0Ihi»,
«url»: «https: //giphy.com/gifs/
«images»: {
«fixed_width_small»: {
«height»: «54»,
«size»: «53544»,
«url»: «https: //media3.giphy.com/media/dzaUX7CAG0Ihi/100w.gif? cid=725ec7e0c00032f700929ce9f09f3f5fe5356af8c874ab12&rid=100w.gif»,
«width»: «100»
},
«downsized_large»: {
«height»: «220»,
«size»: «807719»,
«url»: «https: //media3.giphy.com/media/dzaUX7CAG0Ihi/giphy.gif? cid=725ec7e0c00032f700929ce9f09f3f5fe5356af8c874ab12&rid=giphy.gif»,
«width»: «410»
},
...
},
«slug»: «
...
«import_datetime»: «
«trending_datetime»: «
},
{
type: «gif»,
...
},
...
]
В результате получается массив объектов, содержащих информацию о каждом GIF. Нас особенно интересует returnValue[i].images.fixed_width_small.urlдля каждого изображения, которое содержит
Отображение списка
Чтобы отобразить список
создать контейнер QWidget
создать QMovieвиджет для каждого GIF
создать QLabelиз каждого QMovieэкземпляра
прикрепите каждый QLabelкак дочерний элемент QWidgetконтейнера
вернуть QWidgetконтейнер
Код выглядит следующим образом:
async function getGifViews (listOfGifs) {
const container = new QWidget () ;
container.setLayout (new FlexLayout ());
const promises = listOfGifs.map (async gif => {
const { url, width } = gif.images.fixed_width_small;
const movie = await getMovie (url) ;
const gifView = new QLabel () ;
gifView.setMovie (movie) ;
gifView.setInlineStyle (`width: ${width}`) ;
container.layout.addWidget (gifView) ;
}) ;
await Promise.all (promises) ;
container.setInlineStyle (`
width: 330px;
height: 300px;
`) ;
return container;
}
Давайте немного разберем это.
Затем, чтобы назначить дочерние виджеты элементу QWidget, нам нужно задать ему макет. Макет определяет, как дочерние виджеты должны располагаться внутри родителя. Здесь мы выбираем FlexLayout.
Затем мы используем нашу getMovieфункцию для создания QMovieэкземпляра для каждого
Поскольку все это происходит асинхронно, мы ждем, пока все разрешится с помощью Promise.all, прежде чем устанавливать некоторые стили контейнера и возвращать виджет контейнера.
Прикрепление списка к виджету нашего окна
Теперь давайте изменим нашу mainфункцию, чтобы увидеть список подготовленных нами виджетов.
источник/index.js
const { FlexLayout, QLabel, QMainWindow, QMovie, QWidget } = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
const GIPHY_API_KEY = 'Your API key here’;
async function getMovie (url) {... }
async function searchGifs (searchTerm) {... }
async function getGifViews (listOfGifs) {... }
const main = async () => {
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const center = new QWidget () ;
center.setLayout (new FlexLayout ());
// We get the list of gifs here
const listOfGifs = await searchGifs ('hello’) ;
// We create the container with GIF view widgets
const container = await getGifViews (listOfGifs) ;
// We finally attach the container to the widget
center.layout.addWidget (container) ;
win.setCentralWidget (center) ;
win.show () ;
global.win = win;
};
main ().catch (console.error) ;
Если вы запустите проект после внесения этих изменений, вы должны увидеть:
Список приветственных
Большой! Теперь давайте добавим поле ввода поиска вместе с кнопкой, чтобы пользователи могли искать
Добавление ввода поиска и кнопки
Начнем с создания createSearchContainerфункции, которая будет принимать функцию обратного вызова в качестве параметра. Это будет вызываться при нажатии кнопки поиска.
Вот что должна делать функция:
создайте QWidgetконтейнер, в который мы добавим поле ввода поиска и кнопку в качестве дочерних элементов
создать макет и прикрепить его к контейнеру
создайте поисковый ввод и кнопку, затем прикрепите их кFlexLayout
прикрепите прослушиватель событий к кнопке, которая при нажатии будет вызывать onSearchфункцию обратного вызова, передавая ей любой текст, присутствующий в поле ввода текста
вернуть QWidgetконтейнер
Код выглядит следующим образом:
function createSearchContainer (onSearch) {
const searchContainer = new QWidget () ;
searchContainer.setObjectName ('searchContainer’) ;
searchContainer.setLayout (new FlexLayout ());
const searchInput = new QLineEdit () ;
searchInput.setObjectName ('searchInput’) ;
const searchButton = new QPushButton () ;
searchButton.setObjectName ('searchButton’) ;
searchButton.setText (' 🔎 ') ;
searchButton.addEventListener ('clicked’, () => {
onSearch (searchInput.text ());
}) ;
searchContainer.layout.addWidget (searchInput) ;
searchContainer.layout.addWidget (searchButton) ;
searchContainer.setStyleSheet (`
#searchContainer {
padding: 10px;
}
#searchInput {
flex: 1;
height: 40px;
}
#searchButton {
width: 50px;
height: 35px;
}
`) ;
return searchContainer;
}
Надеюсь, у вас есть четкое представление о том, что здесь происходит, но обратите внимание на одну новую вещь — метод setStyleSheet. Вы можете думать об этом как о способе применить блочный CSS за один раз. Это очень похоже на глобальные таблицы стилей в Интернете, но с той разницей, что в NodeGui/Qt таблица стилей может быть присоединена к любому блоку, а не только глобально.
Чтобы стилизовать виджет с помощью таблицы стилей, нам нужно добавить objectNameк виджету, который мы будем использовать для ссылки на него в таблице стилей. Это в значительной степени идентично тому, что происходит idв
Теперь давайте добавим это searchContainerв главное окно.
источник/index.js
const {
FlexLayout,
QLabel,
QLineEdit,
QMainWindow,
QMovie,
QPushButton,
QWidget,
} = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
const GIPHY_API_KEY = 'Your API key here’;
async function getMovie (url) {... }
async function searchGifs (searchTerm) {... }
async function getGifViews (listOfGifs) {... }
function createSearchContainer (onSearch) {... }
const main = async () => {
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const center = new QWidget () ;
center.setLayout (new FlexLayout ());
// Here we create the search container
const searchContainer = createSearchContainer (searchText => {
console.log ('searchText: ', searchText) ;
}) ;
// Here we add it to the center widget before we add the list of GIFs.
center.layout.addWidget (searchContainer) ;
const listOfGifs = await searchGifs ('hello’) ;
const container = await getGifViews (listOfGifs) ;
center.layout.addWidget (container) ;
win.setCentralWidget (center) ;
win.show () ;
global.win = win;
};
main ().catch (console.error) ;
Теперь, когда вы запускаете приложение и вводите
Список
Подключение поиска к просмотру GIF
Чтобы загружать новые
Внутри обратного вызова, который запускается при нажатии кнопки поиска, возьмите текст поиска и используйте searchGifsфункцию, чтобы получить новый список
Создайте новый контейнер для этих
Удалите существующий контейнер из окна.
Добавьте новый контейнер в окно.
Если немного перетасовать, то получим:
const main = async () => {
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const center = new QWidget () ;
center.setLayout (new FlexLayout ());
let container = new QWidget () ;
const searchContainer = createSearchContainer (async searchText => {
try {
// Create a new GIF container with new GIFs
const listOfGifs = await searchGifs (searchText) ;
const newGifContainer = await getGifViews (listOfGifs) ;
// Remove existing container from the window
center.layout.removeWidget (container) ;
container.close () ;
// Add the new GIF container to the window
center.layout.addWidget (newGifContainer) ;
container = newGifContainer;
} catch (err) {
console.error ('Something happened!', err) ;
}
}) ;
center.layout.addWidget (searchContainer) ;
win.setCentralWidget (center) ;
win.show () ;
global.win = win;
};
Запустим еще раз и увидим волшебство 🧙♂️.
Подключенный виджет поиска GIF
Как видите, когда вы вводите
Использование QScrollAreaдля прокрутки списка
Пока все движется в правильном направлении, вы, наверное, заметили, что список
Мы начнем с удаления heightсвойства в getGifViewsфункции:
async function getGifViews (listOfGifs) {
...
container.setInlineStyle (`
width: 330px;
— height: 300px;
`) ;
return container;
}
Затем нам нужно измениться src/index.js, чтобы выглядеть так:
const {
FlexLayout,
QLabel,
QLineEdit,
QMainWindow,
QMovie,
QPushButton,
QScrollArea,
QWidget,
} = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
const GIPHY_API_KEY = 'Your API key here’;
async function getMovie (url) {... }
async function searchGifs (searchTerm) {... }
async function getGifViews (listOfGifs) {... }
function createSearchContainer (onSearch) {... }
const main = async () => {
const win = new QMainWindow () ;
win.setWindowTitle ('Meme Search’) ;
const center = new QWidget () ;
center.setLayout (new FlexLayout ());
const scrollArea = new QScrollArea () ;
scrollArea.setWidgetResizable (false) ;
scrollArea.setInlineStyle ('flex: 1; width: 350px; height: 400px;') ;
const searchContainer = createSearchContainer (async searchText => {
try {
const listOfGifs = await searchGifs (searchText) ;
const newGifContainer = await getGifViews (listOfGifs) ;
// Remove existing container from the scrollArea
const oldContainer = scrollArea.takeWidget () ;
if (oldContainer) oldContainer.close () ;
// Add the new GIF container to the scrollArea
scrollArea.setWidget (newGifContainer) ;
} catch (err) {
console.error ('Something happened!', err) ;
}
}) ;
center.layout.addWidget (searchContainer) ;
center.layout.addWidget (scrollArea) ;
win.setCentralWidget (center) ;
win.show () ;
global.win = win;
};
main ().catch (console.error) ;
Здесь нет ничего слишком захватывающего. Мы создаем новый элемент QScrollArea, который добавляем в макет под полем поиска. Мы также используем метод takeWidgetQScrollArea для удаления любого существующего контейнера из области прокрутки перед добавлением новых результатов поиска.
Если вы запустите поисковик мемов, теперь у вас должны быть прокручиваемые
Прокручиваемый поиск
Добавление прослушивателей кликов для копирования
Теперь, когда мы можем видеть все
Затем пользователь может просто перейти к тому месту, где он хочет использовать GIF, и вставить его с помощью Ctrl/ Cmd+ V.
Для этого мы должны:
прикрепите прослушиватель событий мыши к каждому GIF
внутри обратного вызова прослушивателя событий используйте класс QClipboard, чтобы скопировать
показать пользователю модальное сообщение о том, что
Слушатель событий может быть прикреплен внутри getGifViewsфункции:
async function getGifViews (listOfGifs) {
...
const promises = listOfGifs.map (async gif => {
...
gifView.addEventListener (WidgetEventTypes.MouseButtonRelease, () => {
const clipboard = QApplication.clipboard () ;
clipboard.setText (url, QClipboardMode.Clipboard) ;
showModal (
'Copied to clipboard!',
`You can press Cmd/Ctrl + V to paste the GIF url: ${url}`
) ;
}) ;
container.layout.addWidget (gifView) ;
}) ;
...
return container;
}
Здесь QApplication.clipboard возвращает объект для взаимодействия с буфером обмена. Мы можем использовать setTextметод этого объекта, чтобы изменить фактическое содержимое буфера обмена.
Мы также используем showModalфункцию. Давайте определим, что дальше:
function showModal (title, details) {
const modal = new QMessageBox () ;
modal.setText (title) ;
modal.setDetailedText (details) ;
const okButton = new QPushButton () ;
okButton.setText ('OK’) ;
modal.addButton (okButton, ButtonRole.AcceptRole) ;
modal.exec () ;
}
Виджет QMessageBox похож на окно предупреждения в
Наконец, нам нужно импортировать все эти новые виджеты вверху src/index.js:
const {
ButtonRole,
FlexLayout,
QApplication,
QClipboardMode,
QLabel,
QLineEdit,
QMainWindow,
QMessageBox,
QMovie,
QPushButton,
QScrollArea,
QWidget,
WidgetEventTypes,
} = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
const GIPHY_API_KEY = 'Your API key here’;
async function searchGifs (searchTerm) {... };
async function getGifViews (listOfGifs) {... };
async function getMovie (url) {... };
function createSearchContainer (onSearch) {... };
function showModal (title, details) {... };
const main = async () => {... };
main ().catch (console.error) ;
Если вы запустите поисковик мемов, теперь у вас должна быть возможность копировать/вставлять
Скопировать URL GIF в буфер обмена GIF
Добавление значка в системный трей
Мы хотим, чтобы наше приложение было скрыто в системном трее, когда оно не используется. Для этого мы создадим значок на панели задач, который будет иметь пункт меню, который при щелчке будет переключать видимость работающего виджета.
Необходимые шаги:
Создайте QSystemTrayIcon со значком.
Создайте меню для значка на панели задач, используя QMenu. Установите экземпляр меню в качестве контекстного меню панели задач.
Создавайте пункты меню с помощью виджетов QAction и настройте прослушиватели событий для прослушивания их triggerсобытий.
По триггеру скрыть или показать окно.
Давайте начнем с запроса необходимых модулей, а затем внесем небольшое изменение в mainфункцию, чтобы указать ей использовать нашу иконку:
const {
ButtonRole,
FlexLayout,
QApplication,
QClipboardMode,
QIcon,
QLabel,
QLineEdit,
QMainWindow,
QMenu,
QMessageBox,
QMovie,
QAction,
QPushButton,
QScrollArea,
QSystemTrayIcon,
QWidget,
WidgetEventTypes,
} = require ('@nodegui/nodegui’) ;
const axios = require ('axios’).default;
const path = require ('path’) ;
const iconImg = require ('.../assets/systray.png’).default;
const GIPHY_API_KEY = 'Your API key here’;
const main = async () => {
...
win.show () ;
systemTrayIcon (win) ;
global.win = win;
};
Как видите, нам нужна иконка из assetsпапки. Если вы следуете инструкциям, вы можете скачать файл значка отсюда.
Теперь идет функция для создания значка в системном трее:
function systemTrayIcon (win) {
const icon = new QIcon (path.resolve (__dirname, iconImg));
const tray = new QSystemTrayIcon () ;
tray.setIcon (icon) ;
tray.show () ;
// Menu that should pop up when clicking on systray icon.
const menu = new QMenu () ;
tray.setContextMenu (menu) ;
//Each item in the menu is called an action
const visibleAction = new QAction () ;
menu.addAction (visibleAction) ;
visibleAction.setText ('Show/Hide’) ;
visibleAction.addEventListener ('triggered’, () => {
if (win.isVisible ()) {
win.hide () ;
} else {
win.show () ;
}
}) ;
global.tray = tray;
}
Здесь мы создаем значок, используя класс NodeGui QIcon. Затем мы используем QSystemTrayIconкласс для создания значка на панели задач для нашего приложения.
Наконец, нам нужно настроить параметры нашего
const path = require ('path’) ;
module.exports = {
...
node: {
— __dirname: true,
— __filename: true
+ __dirname: false,
+ __filename: false
},
...
}
Окончательный результат:
Окончательный виджет поиска
Некоторые последние настройки
Обработка ошибок
Прежде чем мы перейдем к упаковке, давайте воспользуемся нашей showModalфункцией и добавим диалоговое окно обработки ошибок:
const main = async () => {
...
const searchContainer = createSearchContainer (async searchText => {
try {
...
} catch (err) {
...
showModal ('Something went wrong!', JSON.stringify (err));
}
}) ;
...
};
Это предупредит пользователя, если, например,
Разрешить пользователю вводить ключ API
Пока мы говорим о ключах API, давайте добавим диалоговое окно, позволяющее пользователю вводить свой ключ API. Это означает, что его не нужно жестко запрограммировать в программе:
const {
...
QDialog,
...
} = require ('@nodegui/nodegui’) ;
...
let GIPHY_API_KEY = '';
async function searchGifs (searchTerm) {... }
async function getGifViews (listOfGifs) {... }
async function getMovie (url) {... }
function createSearchContainer (onSearch) {... }
function showModal (title, details) {... }
function systemTrayIcon (win) {... }
function showAPIKeyDialog () {
const dialog = new QDialog () ;
dialog.setLayout (new FlexLayout ());
const label = new QLabel () ;
label.setText ('Enter your Giphy API Key’) ;
const input = new QLineEdit () ;
const okButton = new QPushButton () ;
okButton.setText ('OK’) ;
okButton.addEventListener ('clicked’, () => {
GIPHY_API_KEY = input.text () ;
dialog.close () ;
}) ;
dialog.layout.addWidget (label) ;
dialog.layout.addWidget (input) ;
dialog.layout.addWidget (okButton) ;
dialog.setInlineStyle (`
padding: 10;
height: 150px;
`) ;
dialog.exec () ;
}
const main = async () => {
...
showAPIKeyDialog () ;
global.win = win;
};
main ().catch (console.error) ;
Как видите, мы используем QDialogвиджет, чтобы запрашивать у пользователя ввод данных, а затем сохраняем все, что он предоставляет, в GIPHY_API_KEYпеременной. Если вы хотите улучшить свои навыки работы с NodeGui после прочтения этого руководства, вы можете улучшить его — например, сохранив ключ к файловой системе или проверив его и предоставив отзыв пользователю.
Примечание. Не забывайте, что полный исходный код доступен здесь: https://github.com/sitepoint-editors/memesearchapp-nodegui-tutorial.
Упаковка приложения для
После того, как мы успешно создали приложение, нам нужно создать дистрибутивы для macOS, Windows и Linux, которые конечные пользователи смогут загрузить и использовать.
Процесс создания дистрибутивов обычно различен для каждой операционной системы, поэтому, чтобы облегчить боль, мы будем использовать инструмент упаковки NodeGui под названием @nodegui/packer.
использование
npm install —
Затем используйте упаковщик для создания шаблона развертывания:
npx
Шаблон, по сути, является проектом для конкретной ОС, который содержит код для успешной упаковки всего кода, ресурсов и зависимостей приложения NodeGui. Обратите внимание, что вам нужно запустить это в Windows, macOS и Linux отдельно, чтобы создать три разных шаблона. Этот шаблон позволяет точно настроить окончательные параметры развертывания для каждой ОС. Вы можете настроить такие вещи, как информация о компании, значки и другие метаданные, в соответствии с вашими потребностями.
Для Linux шаблон выглядит так:
.
└── deploy
├── config.json
└── linux
└── MemeApp
├── default.desktop
├── default.png
└── qode.json
Обратите внимание, что вам нужно запустить команду инициализации только один раз. Затем вы вносите изменения в шаблон и фиксируете его в репозитории проекта.
Следующим шагом является фактическая сборка и упаковка проекта в дистрибутив.
Удалите buildкаталог, если он существует:
rm -rf. /deploy/build
Затем создайте приложение с помощью
npm run build
Наконец, запустите команду pack упаковщика, передав ей distпапку в качестве аргумента:
npx
Это приведет к следующему:
В macOS упаковщик выведет dmgфайл.
В Linux упаковщик выводит файл AppImage, который
В Windows упаковщик выводит папку, содержащую исполняемый файл и все dll.
После успешного выполнения команды она должна распечатать выходной каталог, который обычно находится внутри deploy/
.
└── deploy
├── config.json
└── linux
├── build
│ └── MemeApp
│ ├──
│ ├── AppRun → qode
│ ├── default.desktop
│ ├── default.png
│ ├── dist
│ │ ├── f59514675cec2e70ce8598286c94dc22.png
│ │ ├── index.js
│ │ └── nodegui_
│ ├── doc
│ │ └──...
│ ├── lib
│ │ └──...
│ ├── plugins
│ │ └──...
│ ├── qode
│ ├── qode.json
│ └── qt.conf
└── MemeApp
├── default.desktop
├── default.png
└── qode.json
Дистрибутив Linux — deploy/linux/build/MemeApp/
Вывод
В этом руководстве мы успешно создали приложение для поиска мемов в реальном мире, используя NodeGui примерно из 200 строк кода. Мы изучили некоторые основные понятия и возможности библиотеки. Мы также смогли упаковать готовое приложение в дистрибутив, которым можно поделиться с конечными пользователями.
Я считаю, что NodeGui открывает двери для создания множества действительно эффективных нативных приложений с помощью Node.js.
NodeGui также поддерживает библиотеки и фреймворки, такие как React (официальный), Angular (сообщество) и вскоре Vue.js (сообщество). Пожалуйста, ознакомьтесь с ними и поставьте им звезду на GitHub, если они вас интересуют.
NodeGui — это библиотека с открытым исходным кодом, которая значительно выиграет от добавления кода. Он имеет относительно простую для понимания кодовую базу и очень гостеприимное сообщество. Я призываю всех помочь.
Наконец, благодаря множеству встроенных виджетов и стилям с помощью CSS, я считаю, что приложения NodeGui так же легко разрабатывать, как