- Spot est une boîte à outils GUI desktop multiplateforme simple et réactive pour créer des interfaces en Go, qui utilise des widgets natifs quand c’est possible et fournit des API cohérentes selon les plateformes
- Quand l’état de l’application change, il reconstruit un arbre immuable de composants puis le compare à l’état précédent pour déterminer quels contrôles UI doivent être mis à jour
- Les backends actuels sont une implémentation basée sur Cocoa pour macOS et sur FLTK pour les autres plateformes, avec la possibilité d’utiliser FLTK aussi sur macOS
spotest le package cœur indépendant du backend qui fournit le modèle réactif et le rendu, etspot/uiest un ensemble de contrôles GUI multiplateformes prêts à l’emploi- La mise en page automatique, les fenêtres multiples, les boîtes de dialogue modales, les fenêtres redimensionnables, la barre de menus, les widgets personnalisés, l’accès aux widgets natifs, le glisser-déposer et l’internationalisation ne sont pas encore pris en charge
Objectif de Spot et modèle de base
- Spot est une boîte à outils GUI réactive pour Go, conçue pour fournir une API cohérente sur plusieurs plateformes tout en utilisant des widgets natifs là où c’est possible
- Il peut être ajouté au projet comme une simple dépendance, et en n’écrivant que du code Go, on peut produire des binaires GUI natifs autonomes sans outils supplémentaires ni génération de code
- L’exemple suit le flux
ui.Init(),spot.MountFn(...),ui.Run()pour créer une fenêtre et un bouton, et gère l’état du nombre de clics avecspot.UseState[int](<https://github.com/roblillack/ctx, 0>) - Le gestionnaire de clic du bouton appelle
setCounter(counter + 1)et, quand l’état change, le titre du bouton devient au format"Clicked %d times!"
Fonctionnement des mises à jour réactives
- Dans Spot, reactive signifie que l’interface se met à jour automatiquement quand l’état de l’application change
- Lors d’un changement d’état, un arbre immuable de composants est reconstruit puis comparé rapidement à l’état précédent pour déterminer quels contrôles UI doivent être mis à jour
- Sur le web, cette idée est souvent appelée virtual DOM, et Spot est né comme une expérimentation visant à transposer ce concept à l’environnement desktop Go pour créer une bibliothèque GUI proche de React
- Au lieu de mettre l’UI à jour manuellement, le développeur gère la logique applicative et l’état avec des fonctions de rendu sans effet de bord et des hooks comme
UseState
Backends et organisation des packages
- Spot choisit automatiquement au moment de la compilation le backend adapté à la plateforme d’exécution
- Deux backends sont actuellement fournis
- Implémentation basée sur FLTK : utilise go-fltk
- Implémentation basée sur Cocoa : utilise une version modifiée de gocoa
- Sur macOS, Spot utilise le backend Cocoa, et sur les autres plateformes le backend basé sur FLTK
- Il est aussi possible d’utiliser FLTK sur macOS, et l’amélioration du support Windows reste prévue pour plus tard
spotest le package cœur qui fournit le modèle réactif et les fonctions de rendu, et peut être utilisé avec n’importe quel ensemble de contrôles implémentant l’interfacespot.Controlspot/uiest un package de contrôles GUI multiplateformes prêts à l’emploi utilisables avec Spot
Composants, contrôles et hooks
- Comme avec React, il est possible de créer des hooks personnalisés
- Il suffit d’écrire une fonction prenant
*spot.RenderContexten premier argument et d’y appelerspot.UseState,spot.UseEffect, etc. pour l’intégrer au cycle de vie de Spot - Par convention, le nom de la fonction commence par le préfixe
Use…
- Il suffit d’écrire une fonction prenant
- Les composants personnalisés peuvent être créés sous forme de structures implémentant l’interface
spot.Component- Cette interface ne contient qu’une seule méthode :
Render(ctx *spot.RenderContext) spot.Component - Les composants ainsi créés peuvent être utilisés de la même manière que les composants intégrés
- Cette interface ne contient qu’une seule méthode :
- Dans Spot, un component est une unité logique qui contient la logique métier et l’état
- Un composant est composé d’autres composants et finit par être rendu en un ou plusieurs contrôles
- Un control est un composant spécial monté dans l’arbre UI, qui représente un élément visuel à l’écran
- Il repose généralement sur une implémentation native du backend GUI, comme pour les boutons, labels ou champs texte
- Il est aussi possible d’utiliser une bibliothèque de widgets complètement différente de celle fournie
- Il suffit de créer une structure qui implémente l’interface
spot.Componentet gère les widgets natifs
- Il suffit de créer une structure qui implémente l’interface
- L’utilisation de
spot/uiavec un backend autre que Cocoa ou FLTK n’est actuellement pas prise en charge
Terminologie du cycle de vie du rendu
- Make : processus consistant à créer une instance de structure implémentant l’interface
spot.Component, ou à créer une nouvelle instance de composant en appelantspot.Makeavec une fonction de rendu - Render : processus qui applique l’état du composant à ses éléments constitutifs et renvoie d’autres instances de composants
- Build : processus qui rend récursivement les composants pour construire l’arbre de contrôles
- On peut passer une instance de composant à
spot.Build, ou une fonction de rendu àspot.BuildFnpour l’exécuter
- On peut passer une instance de composant à
- Mount : processus qui crée les contrôles UI réels à partir de l’arbre de contrôles virtuel
- On peut appeler
Mountsur un nœud de l’arbre, ou utiliserspot.Mountetspot.MountFn
- On peut appeler
- Update : processus de mise à jour de l’arbre de contrôles monté
- Il s’effectue en appelant
Updatesur un nœud de l’arbre
- Il s’effectue en appelant
Fonctionnalités actuellement absentes
- Spot ne fournit actuellement pas les fonctionnalités suivantes
-
Mise en page automatique
- Fenêtres multiples
- Boîtes de dialogue modales
- Fenêtres redimensionnables
- Barre de menus
- Widgets personnalisés
- Accès aux widgets natifs
- Glisser-déposer
- Internationalisation
-
Contrôles UI pris en charge
- Spot fournit par défaut plusieurs contrôles UI comme des boutons, labels, champs texte, sliders et menus déroulants
- Les statuts de prise en charge sont indiqués ainsi : ❓ non implémenté, 🚧 en cours, ⚠️ partiellement implémenté, ✅ terminé
- Les principaux contrôles terminés sont les suivants
- Button : bouton d’action simple, utilise
Fl_ButtonetNSButton - Checkbox : contrôle permettant de choisir entre deux options, utilise
Fl_Check_ButtonetNSButton - Dropdown : menu déroulant pour choisir un élément parmi plusieurs, utilise
Fl_ChoiceetNSComboBox - Image : contrôle d’affichage d’image bitmap, utilise
Fl_Boxet unNSButtonpersonnalisé - Label : label texte non éditable, utilise
Fl_BoxetNSTextField - ListBox : contrôle de liste à sélection simple ou multiple, utilise
Fl_Select_Browser/Fl_Multi_BrowseretNSTableView - ProgressBar : affiche la progression d’un travail de longue durée, utilise
Fl_ProgressetNSProgressIndicator - Slider : entrée par curseur horizontal, utilise
Fl_SlideretNSSlider - Spinner : saisie numérique avec boutons haut/bas, utilise
Fl_SpinneretNSTextField+NSStepper - TextField : champ de saisie texte sur une ligne, utilise
Fl_InputetNSTextField - TextEditor : édition de texte multiligne, utilise
Fl_Text_EditoretNSTextView - Window : contrôle de fenêtre de niveau supérieur, utilise
Fl_WindowetNSWindow
- Button : bouton d’action simple, utilise
- Certains contrôles sont partiellement implémentés ou non implémentés
- Dial : contrôle circulaire d’état, actuellement en état ⚠️ partiellement implémenté
- ComboBox : menu déroulant combiné à une saisie texte, pas encore commencé
- Comme backend natif Windows potentiel à l’avenir, la bibliothèque de contrôles
https://github.com/rodrigocfd/windigoest mentionnée
1 commentaires
Avis sur Hacker News
Il faut absolument que je regarde ça. Je cherchais un moyen simple de créer des outils de développement internes en Go, en gros des formulaires avec des boutons et des champs texte.
J’ai aussi essayé Gio, mais je l’ai trouvé difficile à comprendre ; pour l’instant j’utilise wails, qui me plaît beaucoup plus. Ce projet a l’air intéressant et mérite qu’on s’y penche.
Je conseille vivement de réduire sérieusement l’ambition derrière « multiplateforme : en s’appuyant sur FLTK[1] et Cocoa[2], Spot fonctionne sur Mac, Linux et BSD, avec une prise en charge native de Windows prévue à l’avenir ».
Gardez les enseignements pour préserver de la flexibilité plus tard, mais il vaut mieux commencer par être bon sur un seul toolkit. Les toolkits GUI, les bindings GUI et les GUI elles-mêmes sont déjà des domaines où l’on peut facilement se noyer dans les détails ; si vous vous imposez en plus de prendre en charge les détails de plusieurs toolkits sous-jacents, vous risquez de finir par n’en maîtriser correctement aucun.
On dit que « les premiers 90 % représentent 90 % du travail, et les 10 % restants représentent encore 90 % », mais pour les GUI, même ça semble optimiste. Les premiers 10 % représentent 90 % du travail, les 10 % suivants coûtent dix fois plus, et les 10 % d’après encore dix fois plus. Tenter le multiplateforme peut vous étrangler.
Je ne m’attends pas à ce que vous soyez d’accord avec ça tout de suite, mais quand vous vous retrouverez plus tard face à trois toolkits imposant trois manières contradictoires de gérer, par exemple, le texte enrichi, j’espère que vous vous autoriserez à ne garder que le toolkit sous-jacent le mieux pris en charge ou le plus populaire, et à abandonner les autres.
Je cherchais quelque chose comme ça en Go depuis un moment. Comme Go a un processus de build simple, je pense qu’il a une vraie chance d’offrir une excellente expérience développeur pour les UI multiplateformes.
D’après mon expérience, la moitié de la douleur du développement multiplateforme vient de la gestion de la complexité du build, et Go l’élimine presque entièrement.
Cela dit, les tailles par défaut des contrôles natifs diffèrent d’une plateforme à l’autre, donc je me demande comment ils vont résoudre le layout multiplateforme. Je n’ai pas vu d’autre toolkit multiplateforme régler ça particulièrement bien. En tout cas, bonne chance.
Je cherchais quelque chose comme ça il y a quelques années. Mais j’avais aussi besoin du support de Windows. J’ai finalement basculé vers C++ pour utiliser wxWidgets, et j’ai pu obtenir un petit binaire autonome.
Pour un toolkit natif, j’ai été impressionné de voir que FLTK prend en charge le zoom global de l’application avec Ctrl-+ et Ctrl+-, comme un navigateur. Et grâce à https://github.com/fltk-rs/fltk-theme?tab=readme-ov-file#wid..., j’ai une meilleure impression de jusqu’où on peut rendre FLTK « natif » visuellement.
Dans le même registre, j’ai récemment découvert GoVCL https://z-kit.cc/en/ et j’aimerais bien l’essayer.
Le « Hello World » Spot autonome fait 2.3MiB sur mon Mac. Ce n’est pas très joli, mais pour moi ça fonctionne suffisamment bien.
Je me demande quels sont les avantages de l’approche par arbre de contrôles virtuel par rapport à la mise à jour directe des contrôles affichés à l’utilisateur.
Il faut écrire du code de callback un peu partout, et chaque callback peut devoir examiner soigneusement l’état actuel de toutes les autres activités avant de mettre à jour des dizaines de widgets.
Avec une approche réactive, on écrit une seule fonction de rendu qui décrit l’interface pour un état donné, et le framework se charge de savoir quand l’appeler et quelles entrées lui fournir. C’est beaucoup plus facile à comprendre et, après avoir utilisé React, il est difficile de revenir en arrière ; c’est ce qui m’a amené à expérimenter pour voir si quelque chose de similaire était possible en Go.
Ça a l’air bien. Je me demande si vous pourriez ajouter les plateformes prises en charge dans le README.
Des informations comme Windows, Linux, macOS, *BSD, Android, iOS, Web ou Tizen seraient assez intéressantes.
Vous pourriez le présenter comme dans la documentation de Flutter : https://docs.flutter.dev/reference/supported-platforms
L’effort est louable, mais du multiplateforme sans support Windows ?
Si seulement j’avais découvert ça il y a trois semaines, ou si ça avait déjà existé à l’époque d’après l’historique des commits. Cela fait longtemps que je dis qu’un React porté en Go ou un framework de type React pour Go offrirait une expérience de développement formidable, et celui-ci semble correspondre exactement.
Je détestais assez React.js jusqu’à ce que React.lua me fasse changer d’avis.
J’ai fini par trouver une manière de faire quelque chose de similaire avec seulement
html/templatede la bibliothèque standard de Go, et j’ai décrit l’implémentation ici : https://www.sheshbabu.com/posts/react-like-composition-using...Le gros problème, quand on sort quelque chose sur desktop, c’est qu’on finit généralement par vouloir aussi une version web. C’est particulièrement vrai si ce n’est pas une application très de niche qui interagit beaucoup avec le système d’exploitation.
Ou bien il faut quelque chose qui cible plusieurs plateformes, y compris le mobile.
J’ai cherché assez longtemps, mais ce qui s’en rapprochait le plus était Qt et React Native, et les deux étaient des options douloureuses pour plusieurs raisons.
FLTK prend en charge Windows. Je me demande si Windows n’est pas encore pris en charge parce qu’il est prévu d’utiliser une autre solution.
Cela dit, mon objectif, même s’il est peu prioritaire, est d’implémenter un backend basé sur Win32, et la première étape est terminée : https://github.com/roblillack/spot/pull/4