Table des matières:

Gestionnaire de fenêtres intégré : 10 étapes
Gestionnaire de fenêtres intégré : 10 étapes

Vidéo: Gestionnaire de fenêtres intégré : 10 étapes

Vidéo: Gestionnaire de fenêtres intégré : 10 étapes
Vidéo: Tuto Windows 10 - Gérer les fenêtres ouvertes 2024, Juillet
Anonim
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré
Gestionnaire de fenêtres intégré

Ce projet montre comment implémenter un gestionnaire de fenêtres avec des fenêtres superposées mobiles sur un microcontrôleur intégré avec un panneau LCD et un écran tactile. Il existe des progiciels disponibles dans le commerce pour le faire, mais ils coûtent de l'argent et sont de source fermée. Celui-ci, appelé MiniWin, est gratuit et open-source. Il est écrit en C99 entièrement conforme et peut être utilisé dans une application C ou C++. Les objectifs de MiniWin sont d'être facile à utiliser, facile à modifier, extensible, portable sur une large gamme de matériel et pas trop gourmand en ressources.

En plus de fournir le code pour gérer vos fenêtres, MiniWin possède une collection de commandes d'interface utilisateur - boutons, curseurs, barres de progression, arbres, etc. Vous pouvez avoir plusieurs fenêtres de différents types ou plusieurs instances du même type. Les fenêtres peuvent être déplacées, redimensionnées, agrandies, réduites, fermées - toutes les choses habituelles que vous faites avec des fenêtres dans des gestionnaires de fenêtres plus grands. Les polices TrueType avec crénage et anti-aliasing (rend le texte plus lisse) sont également prises en charge pour un rendu de texte attrayant.

Dans chaque fenêtre, vous avez un espace client (votre espace à l'intérieur de la bordure et en dessous de la barre supérieure). Sur celui-ci, vous pouvez ajouter des contrôles pour créer une boîte de dialogue ou vous pouvez utiliser la bibliothèque graphique intégrée pour dessiner ce que vous voulez. Toutes les fonctions de la bibliothèque graphique sont compatibles avec les fenêtres. Vous n'avez pas à vous soucier de l'emplacement de votre fenêtre, de ce qui la chevauche ou si elle est minimisée.

En plus de créer vos propres fenêtres, il existe également des boîtes de dialogue standard incluses qui sont très faciles à instancier - par exemple des boîtes de dialogue de confirmation (juste un bouton OK ou Oui/Non), des réglages de l'heure/de la date, des sélecteurs de fichiers, des sélecteurs de couleurs, etc.

MiniWin utilise un système de file d'attente de messages de conception de gestionnaire de fenêtres standard. Windows peut interagir entre eux et avec le gestionnaire de fenêtres via des messages. Vous n'appelez pas de fonctions pour faire des choses directement, vous ajoutez un message à la file d'attente et le gestionnaire de fenêtres le fera pour vous.

MiniWin a été porté sur des cartes de développement standard avec écrans tactiles des fournisseurs de microcontrôleurs ST, NXP et Renesas. Il existe des pilotes matériels et des exemples de projets pour tous ces périphériques. De plus, MiniWin peut être conçu pour Windows ou Linux afin que vous puissiez simuler votre code d'interface utilisateur avant d'obtenir votre matériel embarqué.

MiniWin a un générateur de code. Vous pouvez spécifier vos fenêtres et vos contrôles dans un fichier JSON lisible par l'homme simple à créer et le générateur de code analyse le fichier et crée le code pour vous (il y a beaucoup d'exemples à suivre). Il crée des applications de simulation complètes Windows ou Linux qui peuvent simplement être construites et votre écran LCD simulé avec vos fenêtres MiniWin fonctionne. Vous pouvez prendre exactement le même code généré et le déposer dans un projet intégré et avoir le même code affichant les mêmes fenêtres et contrôles quelques instants plus tard sur votre matériel intégré.

MiniWin ne nécessite aucun support d'exploitation sur le périphérique intégré. Tout se déroule dans un seul thread. MiniWin peut être intégré à un RTOS exécuté sur un processeur embarqué et il existe des exemples d'intégration de MiniWin à FreeRTOS.

Cette instructable montre comment faire fonctionner MiniWin sur un processeur STM32 M4 à l'aide de la carte de découverte STM32F429 bon marché qui est livrée avec un écran tactile QVGA déjà connecté. Ceux-ci sont facilement disponibles auprès de votre fournisseur de composants électroniques.

MiniWin fonctionne sur des microcontrôleurs de milieu de gamme et supérieurs.

Fournitures

Carte de développement STM32F429I-DISC1 et un câble micro USB

Téléchargement gratuit de STM32CubeIDE.

Étape 1: Obtenir le code

Obtenir le code
Obtenir le code

Tout d'abord, vous devez installer STM32CubeIDE. Vous l'obtenez sur le site Web de ST. Vous devez vous inscrire et il faut un certain temps pour le télécharger et l'installer. Tout est gratuit.

Pendant l'installation, téléchargez la source MiniWin et décompressez-la. C'est gros, mais vous n'en utiliserez qu'une petite partie. Cliquez ici sur le bouton vert « Cloner ou télécharger »…

github.com/miniwinwm/miniwinwm

puis choisissez Télécharger Zip. Décompressez le contenu.

Étape 2: Construire un exemple de projet

Construire un exemple de projet
Construire un exemple de projet
Construire un exemple de projet
Construire un exemple de projet

Tout d'abord, construisons l'un des exemples de projets. Un bon s'appelle MiniWinSimple. Démarrez STM32CubeIDE puis procédez comme suit:

  1. Choisissez Fichier|Importer…
  2. Ouvrez Général et choisissez Projet existant dans l'espace de travail. Prochain.
  3. Cliquez sur Parcourir et accédez à l'endroit où vous avez décompressé MiniWin. Ensuite, allez dans le dossier STM32CubeIDE\MiniWinSimple\STM32F429. Cliquez sur Sélectionner un dossier.
  4. Dans Projet: cochez MiniWinSimple_STM32F429 puis cliquez sur Terminer.
  5. Le projet MiniWinSimple_STM32F429 apparaîtra dans votre Explorateur de projets. Sélectionnez-le puis construisez-le avec Project|Build Project.
  6. Branchez maintenant votre câble USB à la carte et à votre ordinateur et exécutez-le en utilisant Exécuter|Déboguer et une fois téléchargé, choisissez Exécuter|Reprendre. Vous obtiendrez un affichage d'étalonnage d'écran la première fois, alors touchez le centre des 3 croix sur l'écran LCD. Vous pouvez maintenant interagir avec la fenêtre sur l'écran.

Pour déplacer une fenêtre, faites-la glisser par sa barre de titre. Pour redimensionner une fenêtre, utilisez l'icône en forme de triangle blanc à gauche de la barre de titre. Les fenêtres MiniWin ne peuvent pas être redimensionnées en faisant glisser les bordures car les écrans sur lesquels MiniWin est utilisé sont trop petits. Pour réduire, agrandir ou fermer une fenêtre, utilisez les icônes à l'extrémité droite de la barre de titre (la fermeture peut être désactivée). Lorsqu'une fenêtre est réduite, vous ne pouvez pas déplacer les icônes réduites. Ils s'accumulent du bas à gauche vers la droite.

Étape 3: Exécuter le générateur de code

Exécution du générateur de code
Exécution du générateur de code

Nous allons maintenant modifier l'exemple de projet en générant nos propres fenêtres et en y déposant le nouveau code. Pour ce faire, nous allons exécuter le générateur de code.

  1. Ouvrez une invite de commande et accédez au dossier dans lequel vous avez décompressé MiniWin, puis au dossier Tools\CodeGen.
  2. L'exécutable pour Windows CodeGen.exe est déjà disponible. Pour Linux, vous devez le construire en tapant make. (Vous pouvez également le construire à partir des sources pour Windows si vous craignez d'exécuter un exécutable téléchargé mais que vous avez besoin du compilateur et de l'environnement de développement installés. Consultez la documentation MiniWin dans le dossier docs pour plus de détails).
  3. Dans ce dossier se trouvent quelques exemples de fichiers JSON. Nous utiliserons example_empty.json. Vous devez d'abord le modifier pour le configurer pour Windows ou Linux. Ouvrez-le dans un éditeur et en haut où vous trouverez "TargetType", modifiez la valeur "Linux" ou "Windows" en fonction de ce sur quoi vous exécutez le générateur de code.
  4. Tapez maintenant codegen example_empty.json dans l'invite de commande.
  5. Accédez à votre projet dans STM32CubeIDE et ouvrez le dossier MiniWinSimple_Common. Supprimez tous les fichiers qui s'y trouvent.
  6. Nous avons laissé le "TargetName" dans le fichier JSON par défaut sur "MiniWinGen" donc c'est le nom de notre dossier de code généré. Allez dans le dossier où vous avez décompressé MiniWin, puis dans le dossier MiniWinGen_Common. Maintenant, sélectionnez tous ces fichiers et glissez-déposez ensuite dans STM32CubeIDE dans le dossier MiniWinSimple_Common de votre projet.
  7. Maintenant, reconstruisez et réexécutez le projet dans STM32CubeIDE et votre nouvelle fenêtre de conception apparaîtra. Le bouton dans la fenêtre a disparu car example_empty.json n'en définit aucun.

Étape 4: Ajout d'une fenêtre

Ajout d'une fenêtre
Ajout d'une fenêtre

Nous allons maintenant ajouter une deuxième fenêtre au fichier de configuration JSON et régénérer le code.

1. Ouvrez example_empty.json dans un éditeur de texte.

2. Sous la section "Windows", il y a un tableau de définitions de fenêtres qui n'a actuellement qu'une seule fenêtre. Copiez tout ça…

{

"Name": "W1", "Title": "Window 1", "X": 10, "Y": 15, "Width": 200, "Height": 180, "Border": true, "TitleBar": true, "Visible": true, "Minimised": false }

et collez-le à nouveau avec une virgule séparant les 2 définitions.

3. Remplacez "W1" par "W2" et "Fenêtre 1" par "Fenêtre 2". Remplacez "X", "Y", "Largeur" et "Hauteur" par des valeurs différentes en gardant à l'esprit que la résolution de l'écran est de 240 de large sur 320 de haut.

4. Enregistrez le fichier et exécutez à nouveau le générateur de code.

5. Copiez les fichiers comme à l'étape précédente, reconstruisez et réexécutez. Vous aurez maintenant 2 fenêtres sur votre écran.

Étape 5: Ajout d'un contrôle

Ajout d'un contrôle
Ajout d'un contrôle

Nous allons maintenant ajouter quelques contrôles à votre nouvelle fenêtre. Modifiez le même fichier qu'à l'étape précédente.

1. Dans la spécification de la fenêtre W1, ajoutez une virgule après le dernier paramètre ("Réduit": false) puis ajoutez ce texte

"MenuBar": vrai, "MenuBarEnabled": true, "MenuItems": ["Fred", "Bert", "Pete", "Alf", "Ian"], "Buttons": [{ "Name": "B1", "Label": "Button1", "X": 10, "Y": 10, "Enabled": true, "Visible": true }]

Cette section ajoute une barre de menu avec 5 éléments et l'active (les barres de menu peuvent être globalement désactivées, essayez-le). Il ajoute également un bouton qui est activé et visible (ils peuvent être créés invisibles puis rendus visibles dans le code plus tard).

2. Régénérez le code, copiez-le, reconstruisez, réexécutez tout comme avant.

Étape 6: faire en sorte que les commandes fassent quelque chose

Faire en sorte que les commandes fassent quelque chose
Faire en sorte que les commandes fassent quelque chose

Nous avons maintenant l'interface utilisateur de base dont nous avons besoin pour lui faire faire quelque chose. Pour cet exemple, nous afficherons une boîte de dialogue de sélection de couleurs lorsque le bouton de la fenêtre 1 est enfoncé.

Allez dans votre projet dans STM32CubeIDE et ouvrez le dossier MiniWinSimple_Common puis ouvrez le fichier W1.c (le nom de ce fichier correspond au champ "Nom" de la fenêtre dans le fichier JSON lors de la génération du code).

Dans ce fichier, vous trouverez la fonction window_W1_message_function(). Cela ressemble à ceci:

void window_W1_message_function(const mw_message_t *message){ MW_ASSERT(message != (void*)0, "Paramètre de pointeur nul"); /* La ligne suivante arrête les avertissements du compilateur car la variable est actuellement inutilisée */ (void)window_W1_data; switch (message->message_id) { case MW_WINDOW_CREATED_MESSAGE: /* Ajoutez n'importe quel code d'initialisation de fenêtre ici */ break; case MW_MENU_BAR_ITEM_PRESSED_MESSAGE: /* Ajouter le code de gestion du menu de la fenêtre ici */ break; case MW_BUTTON_PRESSED_MESSAGE: if (message->sender_handle == button_B1_handle) { /* Ajoutez votre code de gestionnaire pour ce contrôle ici */ } break; par défaut: /* Gardez MISRA satisfait */ break; } }

Ceci est appelé par le gestionnaire de fenêtres pour cette fenêtre chaque fois que le gestionnaire de fenêtres a besoin d'informer la fenêtre que quelque chose s'est passé. Dans ce cas, nous souhaitons savoir que le seul bouton de la fenêtre a été enfoncé. Dans l'instruction switch pour les types de messages, vous verrez un cas pour MW_BUTTON_PRESSED_MESSAGE. Ce code s'exécute lorsque le bouton a été enfoncé. Il n'y a qu'un seul bouton dans cette fenêtre, mais il pourrait y en avoir plus, donc une vérification est faite de quel bouton il s'agit. Dans ce cas, il ne peut s'agir que du bouton B1 (le nom correspond à nouveau au nom du bouton dans le fichier JSON).

Donc, après cette étiquette de cas, ajoutez le code pour faire apparaître une boîte de dialogue de sélection de couleur, qui est la suivante:

mw_create_window_dialog_colour_chooser (10, 10, "Couleur", MW_HAL_LCD_RED, false, message->recipient_handle);

Les paramètres sont les suivants:

  • 10, 10 est l'emplacement sur l'écran de la boîte de dialogue
  • "Couleur" est le titre de la boîte de dialogue
  • MW_HAL_LCD_RED est la couleur par défaut avec laquelle la boîte de dialogue commencera
  • false signifie ne pas afficher une grande taille (essayez de le définir sur true et voyez la différence)
  • message->recipient handle est à qui appartient cette boîte de dialogue, dans ce cas c'est cette fenêtre. Le handle d'une fenêtre se trouve dans le paramètre de message de la fonction. Il s'agit de la fenêtre à laquelle la réponse de dialogue sera envoyée.

Pour connaître la valeur de la couleur choisie par l'utilisateur, le gestionnaire de fenêtres enverra à notre fenêtre un message avec la couleur choisie lorsque l'utilisateur appuie sur le bouton OK dans la boîte de dialogue. Par conséquent, nous devons également intercepter ce message avec un autre cas dans l'instruction switch qui ressemble à ceci:

cas MW_DIALOG_COLOUR_CHOOSER_OK_MESSAGE:

{ mw_hal_lcd_colour_t selected_colour = message->message_data; (void)chosen_colour; } Pause;

Nous ne faisons rien pour le moment avec la couleur choisie, il suffit donc de la convertir en void pour éviter un avertissement du compilateur. Le code final de cette fonction ressemble maintenant à ceci:

void window_W1_message_function(const mw_message_t *message)

{ MW_ASSERT(message != (void*)0, "Paramètre de pointeur nul"); /* La ligne suivante arrête les avertissements du compilateur car la variable est actuellement inutilisée */ (void)window_W1_data; switch (message->message_id) { case MW_WINDOW_CREATED_MESSAGE: /* Ajoutez n'importe quel code d'initialisation de fenêtre ici */ break; case MW_MENU_BAR_ITEM_PRESSED_MESSAGE: /* Ajouter le code de gestion du menu de la fenêtre ici */ break; case MW_BUTTON_PRESSED_MESSAGE: if (message->sender_handle == button_B1_handle) { /* Ajoutez votre code de gestionnaire pour ce contrôle ici */ mw_create_window_dialog_colour_chooser(10, 10, "Color", MW_HAL_LCD_RED, false, message->recipient_handle); } Pause; cas MW_DIALOG_COLOUR_CHOOSER_OK_MESSAGE: { mw_hal_lcd_colour_t selected_colour = message->message_data; (void)chosen_colour; } Pause; par défaut: /* Gardez MISRA satisfait */ break; } }

L'exécution du code est illustrée dans l'image ci-dessus. Vous remarquerez peut-être que lorsqu'une boîte de dialogue s'affiche, vous devez y répondre et la fermer avant de faire quoi que ce soit d'autre. C'est ce qu'on appelle le comportement modal. Les boîtes de dialogue dans MiniWin sont toujours globalement modales et vous ne pouvez en avoir qu'une seule à la fois. Il y a plus d'explications ici…

en.wikipedia.org/wiki/Modal_window

Étape 7: Dessiner dans la fenêtre

Dessiner dans la fenêtre
Dessiner dans la fenêtre

Jusqu'à présent, nous n'avons utilisé que des contrôles, et ils se dessinent d'eux-mêmes. Il est temps de faire un dessin personnalisé sur notre fenêtre. La partie sur laquelle vous pouvez dessiner se trouve à l'intérieur des bordures (s'il y en a, elles sont facultatives), à l'intérieur des barres de défilement (si définies, également facultatives) et en dessous de la barre de titre (s'il y en a une, elle est également facultative). C'est ce qu'on appelle la zone client dans la terminologie des fenêtres.

Il existe une bibliothèque de commandes graphiques dans MiniWin que vous pouvez utiliser. Ils sont tous conscients de la fenêtre. Cela signifie que vous n'avez pas à vous soucier de savoir si la fenêtre est visible, partiellement masquée par d'autres fenêtres, allumée, partiellement éteinte ou complètement hors de l'écran, ou si la coordonnée de l'endroit où vous dessinez se trouve sur la zone cliente ou au-delà.. Tout est pris en charge pour vous. Vous ne pouvez pas dessiner en dehors de votre espace client.

Dessiner sur des zones clientes dans la terminologie Windows s'appelle peindre et chaque fenêtre a une fonction de peinture où vous faites votre dessin. Vous n'appelez pas votre fonction de peinture, le gestionnaire de fenêtres le fait pour vous en cas de besoin. Il est nécessaire lorsqu'une fenêtre est déplacée ou qu'une autre fenêtre au-dessus a sa position ou sa visibilité modifiée. Si vous avez besoin de repeindre votre fenêtre parce que certaines des données dont dépend le contenu de la fenêtre ont changé (c'est-à-dire que vous savez qu'une repeinture est requise plutôt que le gestionnaire de fenêtres ne le sache), alors vous dites au gestionnaire de fenêtres qu'une repeinture est nécessaire et il appelle votre fonction de peinture. Vous ne l'appelez pas vous-même. (Tout cela est démontré dans la section suivante).

Tout d'abord, vous devez trouver votre fonction de peinture. Le générateur de code le crée pour vous et il se trouve juste au-dessus de la fonction de gestionnaire de messages modifiée dans la section précédente. Accédez à votre projet et ouvrez à nouveau le fichier W1.c.

Dans ce fichier, vous trouverez la fonction window_W1_paint_function(). Cela ressemble à ceci:

void window_W1_paint_function (mw_handle_t window_handle, const mw_gl_draw_info_t *draw_info)

{ MW_ASSERT(draw_info != (void*)0, "Paramètre de pointeur nul"); /* Remplir la zone client de la fenêtre avec du blanc uni */ mw_gl_set_fill(MW_GL_FILL); mw_gl_set_solid_fill_colour(MW_HAL_LCD_WHITE); mw_gl_set_border(MW_GL_BORDER_OFF); mw_gl_clear_pattern(); mw_gl_rectangle(draw_info, 0, 0, mw_get_window_client_rect(window_handle).width, mw_get_window_client_rect(window_handle).height); /* Ajoutez votre code de peinture de fenêtre ici */ }

Il s'agit du code brut tel que généré et tout ce qu'il fait est de remplir la zone client de blanc uni. Dessinons un cercle rempli de jaune sur la zone client. Nous devons d'abord comprendre le concept d'un contexte graphique (une autre chose Windows). Nous définissons les paramètres de dessin dans le contexte graphique, puis appelons une routine de dessin de cercle générique. Les choses que nous devons définir dans cet exemple sont si le cercle a une bordure, le style de la ligne de bordure, la couleur de la bordure, si le cercle est rempli, la couleur de remplissage et le motif de remplissage. Vous pouvez voir le code ci-dessus qui fait quelque chose de similaire pour remplir la zone client avec un rectangle blanc plein sans bordure. Les valeurs dans le contexte graphique ne sont pas mémorisées entre chaque appel de la fonction de peinture, vous devez donc configurer les valeurs à chaque fois (elles sont cependant mémorisées avec la fonction de peinture).

Dans le code ci-dessus, vous pouvez voir que le remplissage est activé et que le motif de remplissage est désactivé, nous n'avons donc pas besoin de les définir à nouveau. Nous devons définir la bordure, le style de la bordure sur un solide, la couleur du premier plan de la bordure sur le noir et la couleur de remplissage sur le jaune comme ceci:

mw_gl_set_fg_colour(MW_HAL_LCD_BLACK);

mw_gl_set_solid_fill_colour(MW_HAL_LCD_YELLOW); mw_gl_set_line(MW_GL_SOLID_LINE); mw_gl_set_border(MW_GL_BORDER_ON); mw_gl_circle(draw_info, window_simple_data.circle_x, window_simple_data.circle_y, 25);

Ajoutez ce code au commentaire de cette fonction où il est dit d'ajouter votre code. Ensuite, nous devons dessiner un cercle qui se fait comme ceci:

mw_gl_circle(draw_info, 30, 30, 15);

Cela dessine un cercle aux coordonnées 30, 30 avec un rayon de 15. Reconstruisez le code et réexécutez-le et vous verrez un cercle dans la fenêtre comme indiqué ci-dessus. Vous remarquerez que le cercle et le bouton se chevauchent mais que le bouton est au-dessus. C'est par conception. Les contrôles sont toujours au-dessus de tout ce que vous dessinez sur la zone client.

Étape 8: Données de fenêtre

Données de fenêtre
Données de fenêtre

Jusqu'à présent, nous avons implémenté notre propre code dans la fonction message de Window 1 (pour gérer les messages entrants) et sa fonction paint (pour dessiner sur la zone client de la fenêtre). Il est maintenant temps de lier les deux. Permet de remplir le cercle dessiné dans la fonction de peinture avec la couleur que l'utilisateur choisit par le sélecteur de couleur lorsque le bouton a été enfoncé. Rappelez-vous que nous n'appelons pas la fonction de peinture, le gestionnaire de fenêtres le fait, donc notre fonction de message (qui connaît la couleur choisie) ne peut pas appeler la fonction de peinture directement elle-même. Au lieu de cela, nous devons mettre en cache les données et informer le gestionnaire de fenêtres qu'une nouvelle peinture est requise. Le gestionnaire de fenêtres appellera alors la fonction paint qui pourra utiliser les données mises en cache.

En haut de W1.c, vous verrez une structure de données vide et un objet de ce type déclaré par le générateur de code comme ceci:

struct typedef

{ /* Ajoutez vos données membres ici */ char dummy; /* Certains compilateurs se plaignent des structs vides; supprimez ceci lorsque vous ajoutez vos membres */ } window_W1_data_t; statique window_W1_data_t window_W1_data;

C'est là que nous mettons nos données en cache afin qu'elles soient conservées entre les appels et qu'elles soient connues sous le nom de données de fenêtre. Il suffit de stocker la couleur choisie ici, comme ceci:

struct typedef

{ /* Ajoutez vos données membres ici */ mw_hal_lcd_colour_t selected_colour; } window_W1_data_t; statique window_W1_data_t window_W1_data = { MW_HAL_LCD_YELLOW };

Nous allons lui donner une couleur de départ jaune. Maintenant, dans la fonction de message, nous allons légèrement modifier le code pour enregistrer la couleur choisie ici comme ceci:

cas MW_DIALOG_COLOUR_CHOOSER_OK_MESSAGE:

{ window_W1_data.chosen_colour = message->message_data; } Pause;

Ensuite, nous allons modifier la fonction de peinture pour utiliser cette valeur lorsqu'elle trace le cercle comme ceci:

mw_gl_set_solid_fill_colour(window_W1_data.chosen_colour);

Nous avons maintenant modifié les données dont dépend le contenu de la fenêtre, nous devons donc informer le gestionnaire de fenêtres que la fenêtre doit être repeinte. Nous le faisons dans la fonction message lorsque le message de dialogue OK est reçu, comme ceci:

mw_paint_window_client(message->recipient_handle);

Cela n'entraîne pas la peinture directe de la fenêtre. C'est une fonction utilitaire qui envoie un message au gestionnaire de fenêtres indiquant qu'une fenêtre doit être repeinte (si vous y entrez, vous pouvez voir comment cela se produit). La fenêtre qui doit être repeinte dans ce cas est elle-même et le descripteur de la fenêtre se trouve dans le paramètre de message de la fonction de gestionnaire de messages.

L'ensemble du fichier ressemble maintenant à ceci si vous ne savez pas où vont certains des extraits de code ci-dessus:

#comprendre

#include "miniwin.h" #include "miniwin_user.h" #include "W1.h" typedef struct { /* Ajoutez vos données membres ici */ mw_hal_lcd_colour_t selected_colour; } window_W1_data_t; statique window_W1_data_t window_W1_data = { MW_HAL_LCD_YELLOW }; void window_W1_paint_function(mw_handle_t window_handle, const mw_gl_draw_info_t *draw_info) { MW_ASSERT(draw_info != (void*)0, "Paramètre de pointeur nul"); /* Remplir la zone client de la fenêtre avec du blanc uni */ mw_gl_set_fill(MW_GL_FILL); mw_gl_set_solid_fill_colour(MW_HAL_LCD_WHITE); mw_gl_set_border(MW_GL_BORDER_OFF); mw_gl_clear_pattern(); mw_gl_rectangle(draw_info, 0, 0, mw_get_window_client_rect(window_handle).width, mw_get_window_client_rect(window_handle).height); /* Ajoutez votre code de peinture de fenêtre ici */ mw_gl_set_fg_colour(MW_HAL_LCD_BLACK); mw_gl_set_solid_fill_colour(window_W1_data.chosen_colour); mw_gl_set_line(MW_GL_SOLID_LINE); mw_gl_set_border(MW_GL_BORDER_ON); mw_gl_circle(draw_info, 30, 30, 15); } void window_W1_message_function(const mw_message_t *message) { MW_ASSERT(message != (void*)0, "Paramètre de pointeur nul"); /* La ligne suivante arrête les avertissements du compilateur car la variable est actuellement inutilisée */ (void)window_W1_data; switch (message->message_id) { case MW_WINDOW_CREATED_MESSAGE: /* Ajoutez n'importe quel code d'initialisation de fenêtre ici */ break; case MW_MENU_BAR_ITEM_PRESSED_MESSAGE: /* Ajouter le code de gestion du menu de la fenêtre ici */ break; case MW_BUTTON_PRESSED_MESSAGE: if (message->sender_handle == button_B1_handle) { /* Ajoutez votre code de gestionnaire pour ce contrôle ici */ mw_create_window_dialog_colour_chooser(10, 10, "Color", MW_HAL_LCD_RED, false, message->recipient_handle); } Pause; cas MW_DIALOG_COLOUR_CHOOSER_OK_MESSAGE: { window_W1_data.chosen_colour = message->message_data; mw_paint_window_client(message->recipient_handle); } Pause; par défaut: /* Gardez MISRA satisfait */ break; } }

Construisez et exécutez à nouveau et vous devriez pouvoir définir la couleur de remplissage du cercle.

Cet exemple de données de fenêtre utilise des données stockées dans une structure de données statique en haut du fichier source. C'est bien si vous n'avez qu'une seule instance de la fenêtre, comme nous le faisons dans cet exemple, mais si vous avez plusieurs instances, elles partageront toutes la même structure de données. Il est possible d'avoir des données par instance afin que plusieurs instances du même type de fenêtre aient leurs propres données. Ceci est expliqué dans la documentation MiniWin qui se trouve dans le répertoire docs. L'exemple de fichier l'utilise pour afficher plusieurs images dans le même type de fenêtre (comme on le voit dans l'image principale tout en haut de cette instructable).

Étape 9: Un peu de plaisir final avec les polices

Un peu de plaisir final avec les polices
Un peu de plaisir final avec les polices

MiniWin prend en charge le rendu des polices TrueType. S'il y a une chose qui rend votre interface utilisateur belle, ce sont les polices attrayantes. Cette dernière étape montre comment rendre une police TrueType dans une fenêtre MiniWin.

Il existe deux manières de rendre les polices TrueType. L'une consiste à les dessiner directement sur votre espace client comme cela a été fait pour le cercle précédemment, l'autre consiste à ajouter un champ de zone de texte dans votre fenêtre. Nous faisons ce dernier car c'est plus facile.

Nous allons maintenant ajouter un contrôle de zone de texte dans notre fichier de configuration JSON. Ajoutez-le dans la définition de Window 2 pour qu'il ressemble à ceci:

comme ça:

{

"Name": "W2", "Title": "Window 2", "X": 50, "Y": 65, "Width": 100, "Height": 80, "Border": true, "TitleBar": true, "Visible": true, "Minimised": false, "TextBoxes": [{ "Name": "TB1", "X": 0, "Y": 0, "Width": 115, "Height": 50, "Justification": "Centre", "BackgroundColour": "MW_HAL_LCD_YELLOW", "ForegroundColour": "MW_HAL_LCD_BLACK", "Font": "mf_rlefont_BLKCHCRY16", "Enabled": true, "Visible": true }] }

Un petit mot sur les polices TrueType dans MiniWin. Les polices sont fournies dans des fichiers.ttf. Dans les gestionnaires de fenêtres sur des ordinateurs plus gros, ceux-ci sont rendus sur votre écran lorsqu'ils sont nécessaires. Cela prend beaucoup de puissance de traitement et de mémoire et ne convient pas aux petits appareils. Dans MiniWin, ils sont pré-traités en bitmaps et liés au moment de la compilation à une taille et un style de police fixes (gras, italique, etc.), c'est-à-dire que vous devez décider quelles polices, quelle taille et quel style vous allez utiliser au moment de la compilation. Cela a été fait pour vous pour deux exemples de polices dans le fichier zip MiniWin que vous avez téléchargé. Si vous souhaitez utiliser d'autres polices avec d'autres tailles et styles, consultez la documentation MiniWin dans le dossier docs. Il existe des outils dans MiniWin pour Windows et Linux pour le pré-traitement des fichiers.ttf en fichiers de code source que vous pouvez déposer dans votre projet.

Et un deuxième mot rapide - la plupart des polices sont protégées par le droit d'auteur, y compris celles que vous trouverez dans Microsoft Windows. Utilisez-les à volonté pour un usage personnel, mais tout ce que vous publiez, vous devez vous assurer que la licence avec laquelle les polices sont publiées le permet, comme c'est le cas pour les 2 polices incluses dans MiniWin, mais pas les polices de Microsoft !

Retour au code ! Générez, déposez des fichiers, construisez et réexécutez comme avant et vous verrez que la fenêtre 2 a maintenant du texte par défaut sur un fond jaune dans une police farfelue. Modifions le texte en éditant le fichier source W2.c de Window 2.

Nous devons communiquer avec la zone de texte que nous venons de créer et la façon dont vous le faites, comme toute communication dans MiniWin, consiste à lui envoyer un message. Nous voulons définir le texte dans le contrôle lorsque la fenêtre est créée mais avant qu'elle ne soit affichée, nous ajoutons donc du code dans le gestionnaire de messages dans le cas MW_WINDOW_CREATED_MESSAGE. Ceci est reçu par le code de la fenêtre juste avant l'affichage de la fenêtre et est destiné à des initialisations comme celle-ci. Le générateur de code a créé un espace réservé qui ressemble à ceci dans la fonction du gestionnaire de messages:

cas MW_WINDOW_CREATED_MESSAGE:

/* Ajoutez n'importe quel code d'initialisation de fenêtre ici */ break;

Ici, nous allons envoyer un message au contrôle de zone de texte pour lui indiquer le texte que nous voulons qu'il affiche en utilisant la fonction mw_post_message comme ceci:

cas MW_WINDOW_CREATED_MESSAGE:

/* Ajoutez n'importe quel code d'initialisation de fenêtre ici */ mw_post_message(MW_TEXT_BOX_SET_TEXT_MESSAGE, message->recipient_handle, text_box_TB1_handle, 0UL, "C'était une nuit sombre et orageuse…", MW_CONTROL_MESSAGE); Pause;

Ce sont les paramètres:

  • MW_TEXT_BOX_SET_TEXT_MESSAGE - C'est le type de message que nous envoyons au contrôle. Ils sont répertoriés dans miniwin.h et documentés dans la documentation.
  • message->recipient_handle - C'est de qui provient le message - cette fenêtre - dont le descripteur se trouve dans le paramètre de message transmis à la fonction du gestionnaire de messages.
  • text_box_TB1_handle - À qui nous envoyons le message - le handle du contrôle de zone de texte. Ceux-ci sont répertoriés dans le fichier généré miniwin_user.h.
  • 0UL - Valeur de données, rien dans ce cas.
  • "C'était une nuit sombre et orageuse…" - Valeur du pointeur - le nouveau texte.
  • MW_CONTROL_MESSAGE - Type de destinataire qui est un contrôle.

C'est ça. Reconstruisez et réexécutez comme d'habitude et vous obtiendrez la zone de texte comme dans l'image ci-dessus.

La publication de messages est fondamentale pour MiniWin (comme pour tous les gestionnaires de fenêtres). Pour plus d'exemples, regardez les exemples de projets dans le fichier zip et pour une explication complète, lisez la section sur les messages MiniWin dans la documentation.

Étape 10: Aller plus loin

Image
Image

C'est tout pour cette introduction de base à MiniWin. MiniWin peut faire beaucoup plus que ce qui a été démontré ici. Par exemple, l'écran du tableau utilisé dans cette instructable est petit et les commandes sont petites et doivent être utilisées avec un planteur. Cependant, d'autres exemples et matériels utilisent des commandes plus grandes (il existe 2 tailles) sur des écrans plus grands et ceux-ci peuvent être actionnés avec le doigt.

Il existe de nombreux autres types de contrôle que ceux présentés ici. Pour plus de contrôles, consultez les différents exemples de fichiers JSON dans le dossier du générateur de code. Tous les types de contrôle sont couverts dans ces exemples.

Windows a beaucoup d'options. La bordure, la barre de titre et les icônes sont tous configurables. Vous pouvez avoir des barres de défilement et des zones clientes de fenêtre de défilement, plusieurs instances du même type de fenêtre et les fenêtres peuvent être nues (uniquement une zone client, pas de bordure ni de barre de titre) ce qui signifie qu'elles sont fixées au moment de la compilation en place sur l'affichage (voir l'image dans cette section avec des icônes de grande taille - ce sont en fait 6 fenêtres nues).

MiniWin n'utilise pas de mémoire dynamique. Cela le rend adapté aux petits appareils contraints et est une exigence pour certains projets intégrés. MiniWin et le code qu'il génère sont également entièrement conformes à MISRA 2012 au niveau « requis ».

Pour plus d'informations, consultez le dossier docs pour la documentation ainsi que les autres exemples d'applications dans le fichier zip. Il y a des exemples ici montrant comment utiliser toutes les fonctionnalités de MiniWin et comment intégrer MiniWin avec FatFS et FreeRTOS.

Conseillé: