1. Si vous venez d'arriver sur le forum et que vous êtes un peu perdus, cliquez ici !
    Rejeter la notice

Autres [À l'arrêt] [VB/C# .NET] Créer un launcher compatible 1.8.x

Discussion dans 'Tutoriels' créé par Hawezo, 10 Fev 2016.

  1. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Bonjour bonsoir, mesdames et messieurs, grands, moyens, petits, beaux, moins beaux, pas beaux, gentils, méchants, faux-méchants comme Kylo Ren, cette introduction commence à devenir beaucoup trop longue et lourde. (cmb)

    Vous êtes sur mon tutoriel pour apprendre à développer un lanceur pour Minecraft pour ses dernières versions (1.7 et supérieur, je pense), presque à partir de zéro.

    Je dis presque, car je ne vais pas expliquer toutes les notions, raisons pour laquelle je vous conseille d'aller voir le tutoriel dont je vais parler plus bas.
    Je vous souhaite une bonne lecture :)

    [​IMG]
    I. Introduction
    II. Les bases

    a. Mise au point
    b. Les outils nécessaires
    III. Création du projet
    a. Réglages du projet
    b. Derniers réglages avant de commencer
    IV. Optionnel - déboguer plus facilement
    a. Préparation de la classe
    b. Premier débogage
    V. La classe LauncherVariables
    VI. Les graphismes

    a. Les choses à éviter
    b. L'image de fond
    c. Les polices d'écriture personnalisées

    1. Téléchargements
    2. Utilisation
    d. Bouton de fermeture et de réduction personnalisés
    1. Transitions Dot Net
    2. Les évènements de la souris
    3. Résultat
    VII. Optionnel - l'organisation
    a. Les régions
    b. Les commentaires

    VIII. Finitions de la Control Box
    a. Fermeture et réduction
    b. Animations

    IX. Les graphismes (deuxième partie)
    a. Le titre et le logo de la fenêtre
    b. Optionnel - le label personnalisé
    c. Des contours
    d. Déplacement de la fenêtre

    X. L'authentification
    a. Préparation
    1. Les zones de texte
    2. Le bouton de connexion
    b. Utilisation de MojangAPI
    c. AuthManager et threads

    [​IMG]



    I. Introduction

    Il existe déjà plusieurs tutoriels disponibles sur Internet, et même sur le forum.
    Cependant, au vu des tutoriels proposés, je tenais à partager mon expérience de développement, et donc, ma manière de faire.
    Je vais donc tenter de vous apprendre à créer un lanceur (entendez « Lanceur ») pour Minecraft, compatible avec les dernières versions de ce dernier.



    [​IMG]


    II. Les bases

    a. Mise au point avant de démarrer


    J’estime ici que vous savez déjà ce qu’est un langage de programmation. Si non, je vous invite à jeter un œil sur l’article dédié de Wikipédia. Cependant, si vous ne savez même pas ce qu'est un langage de programmation, vous aurez probablement du mal à suivre ce tutoriel dans son intégralité.

    Pour ceux qui n’ont jamais développé ou qui ne connaissent pas Visual Basic .NET, C# .NET, ou plus globalement Visual Studio, je vous invite à lire les premiers chapitres du tutoriel VB .NET sur OpenClassrooms, histoire que vous ne soyez pas trop vite dépassés.
    Vous pouvez aussi lire le tutoriel en entier, cela ne peut pas vous faire de mal.

    Je vais cependant vous aider dans l’installation des outils nécessaires, car le tutoriel d’OpenClassrooms commence à se faire un petit peu vieux. :3


    b. Les outils nécessaires

    Pour commencer le développement de notre lanceur, nous avons besoin d’un IDE. En l’occurrence, nous aurons besoin de Visual Studio Express, la version gratuite de l’environnement de développement de Microsoft.

    Je vous invite à le télécharger sur le site dédié : https://www.visualstudio.com/fr-fr/downloads/download-visual-studio-vs.aspx

    ÉDITION - Dracoctix a mentionné, dans les commentaires, une version plus complète de Visual Studio. Elle est gratuite et plus fonctionnelle, vous pouvez la télécharger et l'utiliser à la place de Visual Studio Express. Cliquez ici.

    [​IMG]
    Figure 1 - Téléchargement de Visual Studio Express 2015 pour Windows Desktop

    Descendez plus bas sur la page, sous la section « Téléchargements Visual Studio », puis cliquez sur « Visual Studio 2015 » dans le menu latéral, et enfin, sur « Express 2015 pour Desktop ».

    Sélectionnez votre langue, puis cliquez sur le bouton de téléchargement.
    Suivez les étapes, téléchargez l’exécutable, installez Visual Studio, puis ouvrez-le.



    [​IMG]


    III. Création du projet

    a. Réglages du projet

    J’ai créé un projet WinForms nommé Lanceur Minecraft.

    À noter › Si vous ne savez pas comment créer un projet, je vous invite à lire le tutoriel référencé dans l'introduction. Prenez garde à créer un projet WinForms et non WPF, ce n'est pas la même chose :)

    Je vous invite à ouvrir les propriétés du projet en double-cliquant sur My Project dans l’explorateur de solutions.

    Modifiez le contenu de la zone de texte sous Espace de noms racine, de manière à ce que le contenu soit aussi court et clair que possible.
    Dans mon cas, c’était « Lanceur_Minecraft » et je l’ai modifié en « Launcher ».

    J’ai appelé mon projet « Lanceur Minecraft » car je n'ai pas de vrai nom pour celui-ci.
    Cependant, si votre lanceur a un nom, vous pouvez l’utiliser pour l’espace de noms racine.
    En guise d'exemple, j’ai dû créer un lanceur qui devait s’appeler « Mineteam ». J’ai donc utilisé le nom « Mineteam » pour l’espace de noms racine.

    Attention › Gardez en tête que tous vos noms de variables et de classes devraient être en anglais. Il est très peu recommandé de les écrire en français, malgré le mauvais exemple du tutoriel d’OpenClassrooms.

    Choisissez ensuite la version du Framework sur laquelle vous comptez développer. Dans mon cas, je vais développer sous la 4.5.
    Cette dernière est native sur Windows à partir de Windows 8 ; mais prenez en compte que les utilisateurs de votre lanceur doivent impérativement avoir au minimum la version que vous choisirez pour pouvoir ouvrir le lanceur. Si vous comptez distribuer votre lanceur à des gens sous Windows Vista (vous ne devriez pas), vous devriez choisir une version inférieure.

    Cochez maintenant la case Application à instance unique, et choisissez À la fermeture du dernier formulaire comme mode d’arrêt.

    Enfin, cliquez sur Informations de l’assembly. Une boîte de dialogue apparaît : vous pouvez la remplir avec les informations que vous souhaitez.

    [​IMG]
    Figure 2 - Informations de l'assembly de mon lanceur

    Validez en cliquant sur OK, puis sauvegardez le projet (Ctrl+S).


    b. Derniers réglages

    Il est toujours bien de renommer ses contrôles et formulaires afin d’avoir une meilleure organisation. Je vous invite donc à renommer votre formulaire Form1 en Main.
    Pour le renommer, cliquez sur Form1.vb dans l’Explorateur de solutions et appuyez sur F2.

    Si une boîte de dialogue s’affiche, cliquez sur Oui : elle va renommer toutes les références à votre fenêtre comme nous le voulons.
    Si elle ne s’affiche pas, c’est que vous avez déjà changé le nom de votre formulaire dans ses propriétés.

    À noter › En anglais, « Main » veut dire « principal ». C’est une habitude et une convention chez les développeurs que les classes principales se nomment Main.

    Je vous invite maintenant à vous rendre dans les propriétés de votre Main.
    Voici les propriétés que nous allons changer maintenant, dans l’ordre (par catégories) :

    • FormBorderStyle à FixedSingle – cela va empêcher notre utilisateur de modifier la taille de la fenêtre.

    • Text à Lanceur Minecraft – ou ce que vous voulez : c’est le titre qui va s’afficher en tant que titre du formulaire. Je vous invite cependant à mettre quelque chose de sobre et clair, il est toujours désagréable de lire « Minecraft Launcher v3.2.08 by Xxx_MrAlbertoDu64_xxX » en nom de fenêtre. J’exagère un peu, mais en lisant ma signature vous verrez que je n’ai aucune pitié pour les kikoos. :fouet:

    • Size à 1000 ; 600 – ce sera la taille de la fenêtre. Vous pouvez mettre ce que vous souhaitez, je serai moi-même peut-être amené à la modifier par la suite.

    • StartPosition à CenterScreen – ça va être la position de départ de la fenêtre sur notre écran.

    • MiximizeBox à False – cela désactive le bouton Agrandir de la fenêtre.

    • MinimizeBox à False – pareil, avec le bouton Réduire.

    Nous serons peut-être à nouveau amenés à modifier ces propriétés, mais, pour le moment, nous avons modifié les bases.

    [​IMG]
    Figure 3 - État du projet après les modifications



    [​IMG]



    IV. Optionnel - déboguer plus facilement


    a. Préparation de la classe

    Ceux qui ont déjà programmé le savent, déboguer un programme (trouver les erreurs dans le code qui causent un disfonctionnement, autrement dit, les bugs) peut s’avérer quelquefois plutôt difficile.

    Dans l’optique d’anticiper d’éventuels problèmes, nous allons écrire une classe partagée (qui n’aura donc pas besoin d’être instanciée) qui nous permettra de loguer des informations au fur et à mesure que le programme se déroule.

    Créez donc un nouveau dossier en effectuant un clic droit sur le nom de votre projet dans l’Explorateur de solutions, puis en sélectionnant Ajouter > Nouveau dossier. Nommez-le « Core ».

    Une fois cela fait, créez une classe à l’intérieur de ce dossier que vous nommerez « Logger ».

    [​IMG]
    Figure 4 - Contenu de la classe automatiquement créée

    Nous allons donc créer plusieurs fonctions que je ne vais pas expliquer, qui vont permettre d’écrire quelque chose dans un fichier sous la forme [Heure] [Niveau d’alerte] <message>.

    Vous pouvez copier-coller le code ci-dessous dans votre classe, je vais juste expliquer quelques petites choses.


    Code (vbnet):
    Imports System.Text

    Public Class Logger

        Private Shared _LogWriter As IO.StreamWriter
        Private Shared _LogFile As String
        Private Shared _DefaultColor As ConsoleColor = ConsoleColor.White
        Public Enum Levels
            Normal = 1
            Debug = 2
            [Warning] = 3
            [Error] = 4
        End Enum

        ' -------------------------------------------------------------------------------
        ' -------- [ PUBLIC ] -----------------------------------------------------------
        ' -------------------------------------------------------------------------------

        ''' <summary>
        ''' Writes a new line
        ''' </summary>
        <DebuggerHidden()>
        Public Shared Sub NewLine()
            Console.WriteLine()
        End Sub

        ''' <summary>
        ''' Writes a normal text in the console, in green.
        ''' </summary>
        ''' <param name="Text">The text.</param>
        <DebuggerHidden()>
        Public Shared Sub Normal(ByVal Text As String)
            Logger.WriteLine(Levels.Normal, Text)
        End Sub

        ''' <summary>
        ''' Writes a debug text in the console, in gray.
        ''' </summary>
        ''' <param name="Text">The text.</param>
        Public Shared Sub Debug(ByVal Text As String)
            Logger.WriteLine(Levels.Debug, Text)
        End Sub

        ''' <summary>
        ''' Writes a warning text in the console, in yellow.
        ''' </summary>
        ''' <param name="Text">The text.</param>
        <DebuggerHidden()>
        Public Shared Sub Warning(ByVal Text As String)
            Logger.WriteLine(Levels.Warning, Text)
        End Sub

        ''' <summary>
        ''' Writes an error text in the console, in dark red.
        ''' </summary>
        ''' <param name="Text">The text.</param>
        <DebuggerHidden()>
        Public Shared Sub [Error](ByVal Text As String)
            Logger.WriteLine(Levels.Error, Text)
        End Sub

        ''' <summary>
        ''' Writes an exception text in the console, in dark red.
        ''' </summary>
        ''' <param name="Exception">The exception to log.</param>
        <DebuggerHidden()>
        Public Shared Sub Exception(ByVal Exception As Exception)
            Logger.NewLine()
            Logger.Error(Logger.GetSeparator(Levels.Error))
            Logger.Error(Exception.Message)
            Logger.Error(Exception.StackTrace)
            Logger.Error(Exception.StackTrace)
            Logger.Error(Logger.GetSeparator(Levels.Error))
            Logger.NewLine()
        End Sub



        ' -------------------------------------------------------------------------------
        ' -------- [ PRIVATE ] ----------------------------------------------------------
        ' -------------------------------------------------------------------------------

        Private Shared Function GetSeparator(Optional ByVal Level As Levels = Levels.Normal)
            Dim Header As String = ""
            For i = Header.Length To Console.WindowWidth - Level.ToString.Length - Date.Now.ToString("HH:mm:ss").Length - 8
                Header &= "-"
            Next
            Return Header
        End Function

        ''' <summary>
        ''' Writes a line in the logger with the specified color.
        ''' </summary>
        ''' <param name="Level">The line's level.</param>
        ''' <param name="Text">The text.</param>
        Private Shared Sub WriteLine(ByVal Level As Levels, ByVal Text As String)
            Dim Timestamp As String = Date.Now.ToString("HH:mm:ss")
            ' If Not (Level = Levels.Debug And LauncherVariables.DEBUG = False) Then Console.WriteLine("[{0}] [{1}] {2}", Timestamp, Level.ToString, Text)
            Logger.WriteInFile(String.Format("[{0}] [{1}] {2}", Timestamp, Level.ToString, Text))
        End Sub

        ''' <summary>
        ''' Logs the logs in a file.
        ''' </summary>
        Private Shared Sub WriteInFile(ByVal Text As String)
            If IsNothing(Logger._LogWriter) Then
                If Not IO.Directory.Exists("logs/") Then IO.Directory.CreateDirectory("logs/")
                Logger._LogFile = "logs/" & Date.Now.ToString("MM-dd-yyyy-HH-mm") & "-logs.txt"
                Logger._LogWriter = New IO.StreamWriter(Logger._LogFile, True, Encoding.UTF8)
            End If

            Try
                Logger._LogWriter.WriteLine(Text)
                Logger._LogWriter.Flush()
            Catch ex As Exception
                MsgBox(ex.ToString)
            End Try
        End Sub





        ' -------------------------------------------------------------------------------
        ' -------- [ LOGGER ] -----------------------------------------------------------
        ' -------------------------------------------------------------------------------

        ''' <summary>
        ''' Finalizes the logger and close it properly.
        ''' </summary>
        <DebuggerHidden()>
        Public Shared Shadows Sub Finalize()
            Logger._LogWriter.Close()
            Logger._LogWriter.Dispose()
        End Sub

    End Class


    La ligne Public Enum Levels ainsi que le contenu de son bloc sont une énumération : cela permet de récupérer des valeurs à l’aide d’un nom. C’est un peu comme des variables, sauf que les valeurs ne changent pas et les noms sont regroupés sous un autre nom.

    À noter › Certains noms sont entre crochets. Ce sont des mots clés réservés à notre IDE pour pouvoir identifier certains types, variables globales, etc… les mettre entre crochet permet de malgré tout utiliser le nom voulu.

    Ici, on peut accéder à la valeur de Debug en écrivant Logger.Levels.Debug. Cela permet généralement la facilitation des conditions.

    Dans notre cas, nous n’en avons pas vraiment besoin puisque j’ai choisi de créer une fonction pour chaque niveau d’alerte. Nous pourrons donc écrire du debug en appelant Logger.Debug("Test"), au lieu de Logger.WriteLine(Levels.Debug, "Test").

    Attention › J’ai mis la fonction WriteLine en Private, cela change son niveau d’accès : vous n’aurez pas accès à la fonction en dehors de la classe. C’est un concept de Programmation Orientée Objet (POO), vous pouvez en apprendre plus sur le tutoriel que je vous ai donné au début du tutoriel.

    [​IMG]
    Figure 5 - Contenu de la classe Logger

    Attention › Si vous êtes attentifs, vous avez remarqué qu’une classe LauncherVariables a été créée. Je vous expliquerai ce qu’il en est plus tard.


    b. Premier débogage

    Je vous invite à vous rendre sur votre Main et à double-cliquer sur la fenêtre.
    Cela va vous créer un Évènement dans le fichier correspondant à la classe Main.

    Écrivez « Logger.Debug("Test") » dans cet évènement, puis lancez le programme avec la touche F5.

    [​IMG]
    Figure 6 - Première ligne dans notre premier évènement

    Sous vos yeux ébahis (ou peut-être pas), une fenêtre blanche s’affiche. Vous pouvez fermer le programme.

    Pour les plus à l’ouest d’entre vous, vous vous demandez pourquoi je vous ai fait ouvrir la fenêtre, et/ou pourquoi ne s’est-il rien passé alors que nous avons écrit une ligne de code.

    Pour ceux qui suivent et qui ont analysé le code de la classe Logger, vous avez déjà ouvert le répertoire de votre solution à la recherche du fichier log.
    Comment ça non ? :grrr:

    Effectuez un clic droit sur le nom de votre projet dans l’Explorateur de solutions et cliquez sur Ouvrir dans l’Explorateur de fichiers. Rendez-vous dans bin > Debug > logs. Là, étincelant, votre tout premier log. Vous pouvez l’ouvrir.

    [​IMG]
    Figure 7 - Tout premier log


    Si vous avez suivi, vous savez qu’à chaque action un peu importante dans votre programme, vous appellerez la fonction Debug de votre Logger afin d’écrire dans ce fichier des informations de debug.



    [​IMG]


    V. La classe LauncherVariables

    Nous allons vite passer dessus, c’est simplement une classe partagée (comme la classe Logger) qui va contenir des variables globales au lanceur.

    Par exemple, la mienne contient la ligne Public Const DEBUG As Boolean = True qui permet de savoir si l’on veut déboguer ou non.

    Je vous invite donc à créer cette classe et à y mettre cette ligne.

    [​IMG]
    Figure 8 - La classe LauncherVariables

    Attention › Cette classe et son contenu seront amenés à changer avec le futur système de paramètres.



    [​IMG]


    VI. Les graphismes

    Histoire de ne pas trop vous faire languir, nous allons passer à l’aspect graphique du lanceur.
    Cependant, malgré les graphismes que je vais adopter, vous pouvez très bien créer les vôtres, et totalement innover. Je ne suis pas excellent en graphismes, je vais donc faire le minimum nécessaire.

    Vous avez sans doute déjà vu pas mal de lanceurs, certains jolis, certains moches. Pratiquement aucun n’adopte une charte graphique, et tous - ou presque - ont vu leur design créés à coup de « tiens c’est pas mal, je vais laisser ça comme ça ».

    Eh bien, contre toute attente... je vais faire pareil. :3
    Je ne vais pas me plier aux règles d’une charte graphique comme le Flat UI ou le Material UI de Google car ce serait trop long, mais sachez que vous, qui lisez ce tutoriel, et qui créez un lanceur pour votre serveur, devriez respecter une de ces chartes pour que votre lanceur soit uniforme et agréable à l’œil.
    Cependant, vous pouvez aussi me recopier. Vous avez le droit. :p


    a. Les choses à éviter
    • Les textes en gras
      Quelque chose d’extrêmement désagréable à voir sur un formulaire quelconque, que ce soit un lanceur Minecraft ou autre, est un texte en gras mal géré. Si vous comptez mettre quelque chose en évidence, utilisez des polices comme Roboto Medium, mais ne mettez pas du gras, car les polices rendent souvent très mal sur un formulaire.
    • Les couleurs flashy
      Vous vous en doutez certainement, mais mettre du vert fluo en image de fond sur votre lanceur n’est pas une bonne idée.
    • Les fautes d’orthographe
      Une faute de frappe c’est vite arrivé, mais si vous n’êtes pas capables d’aligner 10 mots sans faire une faute d’orthographe, utilisez un p*tain de correcteur orthographique. Rien de plus désagréable que de lire un texte rempli de fautes, et je ne suis pas le seul de cet avis. De plus, un rendu sans faute rendra votre lanceur plus professionnel.
    • Les mauvais alignements
      Quand vous alignez des contrôles (que nous verrons plus tard) tels que des étiquettes (labels), boutons, ou autres éléments graphiques, veillez à ce qu’ils soient alignés (vous pouvez vous aider des valeurs numériques des propriétés Size et Location, de la propriété Dock, et de la barre d'outils Disposition)
    • Évitez les ombres et le biseautage
      Hormis sur les cadres (panels), les ombres sont à proscrire. De même, le biseautage dans un nom de serveur écrit à la va-vite sur une version tout à fait légale de Photoshop.
    b. L’image de fond

    J’ai l’intention d’utiliser, pour mes graphismes, une image de fond. Mais sachez qu’une image de fond possède un gros désavantage : elle rendra votre lanceur plus lourd.
    Que ce soit au téléchargement ou à l’exécution, une image rendra plus lourd votre lanceur. Si vous n’avez pas un ordinateur très puissant (comme moi), vous pourriez voir des défauts d’affiche lors de l’affichage, de la fermeture ou du déplacement de votre fenêtre.
    Pour éviter cela un maximum, prenez une image compressée (pas trop quand même) et qui fait la taille exacte de votre lanceur : ni trop grande, ni trop petite.

    Voici l’image de fond que j’ai choisie :

    [​IMG]
    Vous pouvez la télécharger en effectuant un clic droit, puis "Enregistrer sous"

    C’est une image que j’ai trouvée sur Google. Je l’ai réduite à une taille de 1000 * 600 pixels et floutée à 15%.
    Vous êtes évidemment libre de choisir votre propre image, comme par exemple, une capture d’écran de votre serveur (un endroit intéressant, pas l’herbe, hm ?). Je vous conseille également le flou.

    Rendez-vous donc dans les propriétés de votre Main et cliquez sur BackgroundImage. Sélectionnez le bouton radio du bas, et cliquez sur Importer. Choisissez votre image, puis validez.
    Enfin, mettez la valeur Zoom à BackgroundImageLayout, cela aura pour effet de cadrer l’image dans votre fenêtre (notez que vous n’avez pas besoin de faire ça si vous avez suivi mes conseils).
    Si ça ne va pas avec votre image, essayez Stretch étirer »), ou si vous avez choisi un modèle (pattern) tel que l’image d’un cube de terre, choisissez Tile tuile », soit « répétition »).

    Pour un meilleur rendu, j’ai choisi de finalement retirer les bordures de la fenêtre. Pour cela, mettez la valeur « None » à FormBorderStyle, et n’oubliez pas de remettre la taille de la fenêtre à 1000 * 600, car elle a été modifiée.

    Enfin, mettez un Panel (qui se trouve dans la boite à outils, si vous ne la trouvez pas, ouvrez-la en appuyant sur Ctrl+W, puis X, ou en allant dans Affichage > Boîte à outils) dans votre formulaire.

    Accédez aux propriétés du Panel et changez ces valeurs :
    • Name à PNL_TOP – Il est toujours aussi important de modifier les noms des contrôles.
    • Dock à Top – Ainsi, le Panel sera lié au haut de notre fenêtre.
    • Size à 1000 ; 38 – De toute façon, vous ne pouvez pas modifier le 1000. Le 38 correspond à la hauteur du Panel.
    • BackColor à 153 ; 0 ; 0 ; 0 – Cela correspond à un fond noir avec une opacité de 60% (60 / 100 * 255).


    c. Les polices d’écriture personnalisées

    1. Téléchargements

    Afin de parvenir à une meilleure personnalisation, vous allez être amenés à utiliser vos propres polices.
    Je vous conseille donc de télécharger celles-ci :
    • Material Icons - c'est une police d'écriture créée et fournie par Google qui contient un symbole à chaque caractère. Elle est extrêmement utile (et jolie), je vais beaucoup l'utiliser dans ce projet.
    • Roboto - c'est aussi une police d'écriture de Google, et elle rend elle aussi très bien. Je vous la conseille également.
    À noter › Pour télécharger Roboto, cliquez sur la flèche en haut à droite du compteur, et cliquez sur Zip File.

    [​IMG]
    Figure 9 - téléchargement de la police Roboto


    2. Utilisation

    Afin de les utiliser, vous allez devoir commencer par les importer dans votre projet.
    Pour cela, allez dans les propriétés du projet (My Project) et cliquez sur l’onglet Ressources. Faites un glisser-déposer des polices précédemment téléchargées dans la zone blanche.

    [​IMG]
    Figure 10 - Importation de la police d'écriture Material Icons Regular

    Cela fait, créez une classe dans le dossier Core, que vous nommerez FontManager.

    Collez-y ce code, que vous n’avez pas besoin de comprendre. Sachez juste qu’il permet de récupérer un objet de type Font grâce à un tableau de Byte.


    Code (vbnet):
    Imports System.Drawing.Text
    Imports System.Runtime.InteropServices

    Public Class FontManager

        Private Shared _FontCollection As PrivateFontCollection

        ''' <summary>
        ''' Get an instance of a given font.
        ''' </summary>
        ''' <param name="Font">The font to use, for example, in the resources.</param>
        ''' <param name="Size">The size of the font, in pixels. 12 by default.</param>
        ''' <param name="Style">The style of the font, regular by default.</param>
        Public Shared Function GetFont(ByRef Font() As Byte, Optional ByVal Size As Single = 12, Optional ByVal Style As FontStyle = FontStyle.Regular) As Font
            If FontManager._FontCollection Is Nothing Then LoadFont(Font)
            Return New Font(FontManager._FontCollection.Families(0), Size, Style)

        End Function

        ''' <summary>
        ''' Load a font in the FontCollection
        ''' </summary>
        Private Shared Sub LoadFont(ByRef Font() As Byte)
            Try
                FontManager._FontCollection = New PrivateFontCollection ' On initialise la collection
                Dim FontPointer As IntPtr = Marshal.AllocCoTaskMem(Font.Length) ' On crée un pointeur vers une partie de la mémoire

                Marshal.Copy(Font, 0, FontPointer, Font.Length) ' On copie la police dans la mémoire
                FontManager._FontCollection.AddMemoryFont(FontPointer, Font.Length) ' On ajoute la police se trouvant dans la mémoire dans la collection
                Marshal.FreeCoTaskMem(FontPointer) ' On libère la mémoire précédemment utilisée

            Catch ex As Exception
                Logger.Exception(ex) ' Nous loggons notre exception
            End Try
        End Sub

    End Class


    À noter › Si vous souhaitez malgré tout comprendre le code, il est en partie commenté.

    Créez maintenant une étiquette (Label) que vous placerez dans le PNL_TOP. Changez les propriétés suivantes :

    • BackColor à Transparent (ou 0 ;0 ;0 ;0) – de manière à rendre son fond transparent
    • Cursor à Hand – afin que notre souris se transforme en main
    • ForeColor à #ecf0f1 – une nuance du blanc
    • TextAlign à MiddleCenter
    • Name à LBL_CLOSE – afin de l’identifier dans le code
    • Dock à Right – c’est important, cela sert à coller l’étiquette à droite du Panel.
    • Size à 38 ; 38 – pour que cela forme un carré de côté 38 px.

    Votre bouton Fermer est presque prêt. Rendez-vous dans l’éditeur de code, et dans l’évènement Main. S’il y a toujours la ligne de debug, vous pouvez l’enlever. Ajoutez-y ces lignes :

    Code (vbnet):
    Me.LBL_CLOSE.Font = FontManager.GetFont(My.Resources.MaterialIcons_Regular, 15)
    Me.LBL_CLOSE.Text = ChrW(&HE5CD)
    La première permet de charger la police grâce au FontManager. Le 15 est la taille de la police. La seconde permet d’écrire le caractère unicode correspondant à la croix dans la tableau des caractères de la police (donc E5CD).

    À noter › Le préfixe &H permet de rentrer un nombre de base 16, c’est-à-dire un nombre hexadécimal. En C#, on pourrait directement écrire « \ue5cd » dans une chaîne de caractère ; en VB, on utilise la fonction ChrW pour récupérer ce caractère.

    À noter › Vous pouvez vous rendre sur la page GitHub de la police d’écriture pour avoir plus de logos. Vous pouvez également installer la police sur votre PC et ouvrir charmap.exe (Windows+R, charmap, puis touche Entrée) pour les voir. Le code correspondant est affiché en bas.

    [​IMG]
    Figure 11 - La fenêtre Exécuter et la fenêtre Charmap

    Vous pouvez maintenant ouvrir le programme avec F5. Surprise ! Une jolie croix apparaît en haut à droite. Mais elle n’est pas encore fonctionnelle.


    d. Bouton de fermeture et de réduction personnalisés

    1. Transitions Dot Net
    Nous allons devoir utiliser ce qu’on appelle une bibliothèque. Sortez donc de chez vous, rendez-vous dans la bibliothèque la plus proche et kidnappez la bibliothécaire.

    Une bibliothèque est en fait une liste de fonctions déjà écrites par quelqu’un d’autre, qui nous mâche bien le travail, parce qu’on est des flemmards.

    Téléchargez donc la bibliothèque « Transition Dot Net » à cette adresse, et extrayez-la vers un dossier sur votre disque dur.

    Rendez-vous dans les propriétés de votre projet, onglet Références, cliquez sur Ajouter, Parcourir, trouvez le fichier Transitions.dll là où vous l’avez extrait, puis validez en cliquant sur OK.

    Félicitations, vous venez d’importer votre première bibliothèque ! :)

    Cette dernière va en fait nous servir à effectuer des transitions (oui c’est moi, Captain Obvious) afin de rendre notre bouton plus joli.


    2. Les évènements de la souris

    Je vous invite maintenant à cliquer sur l’icône en forme d’éclair en haut des propriétés de l’étiquette et à double-cliquer sur la zone de texte à droite de MouseEnter, en bas.

    [​IMG]
    Figure 12 - onglet des évènements de l'étiquette

    Cela nous amène dans l’éditeur de code, dans la méthode correspondant à l’évènement appelé lorsque l’on survole l’étiquette avec la souris.

    Mettez-y le code suivant :
    Code (vbnet):

    Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#e57373"), New TransitionType_Linear(250))
    Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(100, 0, 0, 0), New TransitionType_Linear(250))
     
    Ouvrez maintenant l’évènement MouseLeave et insérez-y ce code :
    Code (vbnet):

    Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), New TransitionType_Linear(250))
    Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(0, 0, 0, 0), New TransitionType_Linear(250))
     
    Attention › N'oubliez pas d'importer Transitions dans votre classe. Sans l'import, il va y avoir des erreurs : placez Imports Transitions en début de fichier.

    Analysons ces lignes.
    La première permet d’effectuer une transition linéaire d’une durée de 250 millisecondes de la valeur actuelle de la propriété ForeColor à une nouvelle valeur, soit la couleur « #e57373 » qui correspond à une nuance de rouge des codes couleurs de Google.

    À noter › Je vais souvent réutiliser ces codes, vous devriez vous aussi garder cette page à portée de main, et même, en favoris.

    La seconde permet d’effectuer la même transition, mais de la couleur de fond, et change simplement l’opacité en l’augmentant à 39%.

    Les lignes de l’évènement MouseLeave font la même chose en sens inverse.

    Ouvrez maintenant votre lanceur avec F5, et passez votre souris sur votre bouton de fermeture. N’est-ce pas magnifique ?

    Je vous laisse maintenant copier ce bouton pour créer un bouton de réduction. Pour cela, vous devez savoir :
    • Le nom du bouton : LBL_REDUCE
    • Couleur du fondu : #4fc3f7
    • Valeur unicode du bouton : e5cf ou e15b

    Les évènements sont donc les mêmes que pour l’étiquette de fermeture avec certaines valeurs changées. Je vous laisse vous débrouiller. :3


    3. Résultats

    C’est bon ? Vous avez finit ? Allez, je vous file le code.

    Code (vbnet):

    Imports Transitions

    Public Class Main

      Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      Me.PNL_TOP.Font = FontManager.GetFont(My.Resources.MaterialIcons_Regular, 15)
      Me.LBL_CLOSE.Font = PNL_TOP.Font
      Me.LBL_CLOSE.Text = ChrW(&HE5CD)
      Me.LBL_REDUCE.Font = PNL_TOP.Font
      Me.LBL_REDUCE.Text = ChrW(&HE5CF)
      End Sub


      Private Sub LBL_CLOSE_MouseEnter(sender As Object, e As EventArgs) Handles LBL_CLOSE.MouseEnter
      Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#e57373"), New TransitionType_Linear(250))
      Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(100, 0, 0, 0), New TransitionType_Linear(250))
      End Sub

      Private Sub LBL_CLOSE_MouseLeave(sender As Object, e As EventArgs) Handles LBL_CLOSE.MouseLeave
      Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), New TransitionType_Linear(250))
      Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(0, 0, 0, 0), New TransitionType_Linear(250))
      End Sub


      Private Sub LBL_REDUCE_MouseEnter(sender As Object, e As EventArgs) Handles LBL_REDUCE.MouseEnter
      Transition.run(LBL_REDUCE, "ForeColor", ColorTranslator.FromHtml("#4fc3f7"), New TransitionType_Linear(250))
      Transition.run(LBL_REDUCE, "BackColor", Color.FromArgb(100, 0, 0, 0), New TransitionType_Linear(250))
      End Sub

      Private Sub LBL_REDUCE_MouseLeave(sender As Object, e As EventArgs) Handles LBL_REDUCE.MouseLeave
      Transition.run(LBL_REDUCE, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), New TransitionType_Linear(250))
      Transition.run(LBL_REDUCE, "BackColor", Color.FromArgb(0, 0, 0, 0), New TransitionType_Linear(250))
      End Sub


    End Class
     
    Je ne sais pas vous, mais je trouve ce code assez désorganisé. Nous voulons écrire un code propre, donc nous allons voir comment nous organiser parmi les classes et les méthodes.



    [​IMG]



    VII. Optionnel - l'organisation

    Plus tôt dans ce tutoriel, je vous ai demandé de créer un dossier nommé « Core » dans l’arborescence des fichiers du projet.

    Cela permet, au fur et à mesure que le nombre de fichiers dans le projet grandit, de rester organiser. En effet, plus le code va grandir, plus vous ajouterez de fichiers, de classes, etc. D’où le principe de les regrouper par catégorie.

    Ici, le dossier Core contient tout ce qui est lié au fonctionnement interne du lanceur. Core veut dire « noyau », je ne sais pas si c’est la meilleure manière de nommer le dossier, mais elle reste assez parlante.

    Par exemple, si le nombre de classe servant à gérer certains aspects du lanceur (managers), comme le FontManager, voient le jour dans ce projet, je vais certainement toutes les mettre dans un dossier Managers.

    De même que nous trions l’arborescence d’un projet, les lignes de code à l’intérieur des fichiers de ce dernier doivent elle aussi être organisées.


    a. Les régions

    Le charabia que j’ai écrit plus haut étant un bel exemple de ce qu’il ne faut pas faire, je vous conseille donc de ranger ces lignes de code par catégories grâce au mot-clé #Region (avec le #).

    Par exemple :
    Code (vbnet):
    #Region ’’Events’’
        Private Sub Main_Load()
        #Region “ControlBox”
            Private Sub LBL_CLOSE_MouseEnter()
            Private Sub LBL_CLOSE_MouseLeave ()
        #End Region
    #End Region
     
    C’est ainsi que nous allons nous organiser.


    b. Les commentaires

    Il faut aussi veiller à commenter certaines fonctions.
    Que ce soit par esthétique du code ou par prévention de relecture, il faut s’habituer à commenter nos lignes de code. Particulièrement les fonctions : mettez trois apostrophes sur la ligne au-dessus d’une méthode et vous pourrez écrire à quoi elle sert.
    Ce sera notamment utile lors du survol à la souris d’un appel à sa fonction pour voir ce que vous avez écrit, donc son fonctionnement, et à l’écriture de ses arguments pour voir le type et le but de ces arguments.

    [​IMG]
    Figure 13 - Le commentaire prend trois lignes et est entre balises

    Je vous invite donc à copier-coller le code ci-dessous (ou à le réorganiser vous-même) afin d’organiser notre charabia.

    Code (vbnet):
    Imports Transitions
    Imports Launcher.LauncherMethods

    Public Class Main

    #Region " Évenements "

      ' -------------------------------------------------------------------------------------
      ' ----- [ FORMULAIRE ] ----------------------------------------------------------------
      ' -------------------------------------------------------------------------------------


      ''' <summary>
      ''' Se déclenche lorsque la fenêtre s'ouvre.
      ''' </summary>
      Private Sub Main_Load(sender As Object, e As EventArgs) Handles MyBase.Load
      Me.PNL_TOP.Font = FontManager.GetFont(My.Resources.MaterialIcons_Regular, 15)
      Me.LBL_CLOSE.Font = PNL_TOP.Font
      Me.LBL_CLOSE.Text = ChrW(&HE5CD)
      Me.LBL_REDUCE.Font = PNL_TOP.Font
      Me.LBL_REDUCE.Text = ChrW(&HE5CF)
      End Sub




      ' -------------------------------------------------------------------------------------
      ' ----- [ CONTROL BOX ] ---------------------------------------------------------------
      ' -------------------------------------------------------------------------------------


      ''' <summary>
      ''' Se déclenche lorsque la souris entre sur le bouton de fermeture.
      ''' </summary>
      Private Sub LBL_CLOSE_MouseEnter(sender As Object, e As EventArgs) Handles LBL_CLOSE.MouseEnter
      Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#e57373"), New TransitionType_Linear(250))
      Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(100, 0, 0, 0), New TransitionType_Linear(250))
      End Sub
      Private Sub LBL_CLOSE_MouseLeave(sender As Object, e As EventArgs) Handles LBL_CLOSE.MouseLeave
      Transition.run(LBL_CLOSE, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), New TransitionType_Linear(250))
      Transition.run(LBL_CLOSE, "BackColor", Color.FromArgb(0, 0, 0, 0), New TransitionType_Linear(250))
      End Sub

      ''' <summary>
      ''' Se déclenche lorsque la souris entre sur le bouton de réduction.
      ''' </summary>
      Private Sub LBL_REDUCE_MouseEnter(sender As Object, e As EventArgs) Handles LBL_REDUCE.MouseEnter
      Transition.run(LBL_REDUCE, "ForeColor", ColorTranslator.FromHtml("#4fc3f7"), New TransitionType_Linear(250))
      Transition.run(LBL_REDUCE, "BackColor", Color.FromArgb(100, 0, 0, 0), New TransitionType_Linear(250))
      End Sub
      Private Sub LBL_REDUCE_MouseLeave(sender As Object, e As EventArgs) Handles LBL_REDUCE.MouseLeave
      Transition.run(LBL_REDUCE, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), New TransitionType_Linear(250))
      Transition.run(LBL_REDUCE, "BackColor", Color.FromArgb(0, 0, 0, 0), New TransitionType_Linear(250))
      End Sub

    #End Region

    End Class
     
    À noter › Vous avez sans doute remarqué l’espèce de grand commentaire sur trois lignes. Je n’aime pas les régions imbriquées, j’ai donc choisi ce commentaire pour séparer mes évènements dans la région correspondante.



    [​IMG]


    VII. Finitions de la Control Box

    a. Fermeture et réduction

    Notre Control Box est certes, jolie, mais pour le moment non-fonctionnelle : nous allons remédier à cela. Ouvrez l’évènement MouseClick des deux étiquettes en double-cliquant dessus.

    Dans l’évènement du bouton de fermeture, insérez ce code : Me.Close. Il permet de fermer la fenêtre.

    Dans l’évènement du bouton de réduction, insérez celui-ci : Me.WindowState = FormWindowState.Minimized. Il permet de réduire notre fenêtre.


    b. Animations

    Tout cela est bien joli, mais justement, pas assez (oui, c’est moi qui ai dit que je ne m’attarderai pas sur les graphismes… chut.).

    Nous allons animer la fermeture de notre fenêtre par un joli fondu. Ouvrez l’évènement FormClosing de votre Main.

    [​IMG]
    Figure 14 - Ouverture de l'évènement FormClosing

    Malheureusement, il n’est pas possible de modifier l’opacité de la fenêtre à l’aide de la bibliothèque Transtion Dot Net. Nous allons donc devoir passer par un autre moyen.

    Créez un dossier « Miscellaneous » et déplacez-y la classe LauncherVariables. Créez maintenant une classe LauncherMethods. Nous allons mettre dedans cette classe des méthodes globales, utiles un peu partout.

    Vous pouvez y coller ce code :
    Code (vbnet):

    Public Class LauncherMethods

    #Region " Fondu "

        Public Enum FadeAction
            Show
            Hide
        End Enum
        Public Enum FadeTime
            Slow = 500
            Medium = 250
            Fast = 185
        End Enum

        ''' <summary>
        ''' Permet d'afficher ou de cacher une fenêtre en fondu.
        ''' </summary>
        Public Shared Sub FadeWindow(Target As Form, ByVal Action As FadeAction, Optional ByVal FadeTime As FadeTime = 500, Optional ByVal OPMAX As Integer = 100)
            Try
                Select Case Action
                    Case FadeAction.Show
                        Target.Opacity = 0
                        Target.Show()
                        Dim Inc As Integer
                        Dim checkT As Integer = My.Computer.Clock.TickCount
                        Do While Inc < FadeTime
                            Inc = My.Computer.Clock.TickCount - checkT
                            Target.Opacity = Inc / FadeTime
                            If Target.Opacity >= OPMAX Then Exit Sub
                            Application.DoEvents()
                        Loop
                    Case FadeAction.Hide
                        If Target.Opacity = 0 Then Exit Sub
                        Dim Inc As Integer
                        Dim checkT As Integer = My.Computer.Clock.TickCount
                        Do While Inc < FadeTime
                            Inc = My.Computer.Clock.TickCount - checkT
                            Target.Opacity = 1 - 1 / (FadeTime / Inc)
                            Application.DoEvents()
                        Loop
                End Select

            Catch ex As Exception
                Logger.Exception(ex)
            End Try
        End Sub

    #End Region

    End Class
     
    Vous pouvez maintenant mettre, à l’intérieur de l’évènement FormClosing, cet appel : LauncherMethods.FadeWindow(Me, FadeAction.Hide, FadeTime.Fast).

    Attention › N’oubliez pas d’importer LauncherMethods en début de fichier !

    Si vous démarrez votre lanceur et que vous le fermez à l’aide du bouton, il devrait disparaître en un léger fondu.

    À noter › Les clignotements (flickers en anglais) qui apparaissent sont dûs aux WinForms, plus particulièrement à l’image de fond. Il n’est malheureusement pas possible de les faire disparaître totalement. Vous pouvez vous renseigner sur WPF qui est fait pour ça, mais je vais continuer ce tutoriel en WinForms.

    Le mieux que l’on puisse faire pour faire disparaître ces clignotements est de rajouter cette ligne dans l’évènement Load du Main : Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True). Mais au fur et à mesure que le lanceur s’alourdira, les clignotements peuvent revenir.

    Maintenant, vous pouvez ajouter ce même appel dans l’évènement Load afin d’ouvrir le lanceur en fondu. N’oubliez pas de remplacer FadeAction.Hide par FadeAction.Show, sinon, ce ne sera pas joli. ;)



    [​IMG]



    IV. Les graphismes (deuxième partie)

    Nous allons continuer la création des graphismes du lanceur. Tout d’abord, commencez par réorganiser le code : nous avons trop de lignes dans l’évènement Load, nous allons donc créer une fonction d’initialisation.

    Commencez par créer une nouvelle région « Méthodes » au-dessus de la région « Évènements ». Cela fait, créez une partie « Formulaire » à l’aide de commentaires, puis créez une fonction « Initialize » avec les lignes de l’évènement Load, mais commentées. Le tout dans un bloc Try/Catch.

    Voici le code :

    Code (vbnet):

    #Region " Méthodes "

      ' -------------------------------------------------------------------------------------
      ' ----- [ FORMULAIRE ] ----------------------------------------------------------------
      ' -------------------------------------------------------------------------------------

      Private Sub Initialize()

       Try
          ' Prévention des scintillements
         Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.UserPaint Or ControlStyles.DoubleBuffer, True)

        ' Affichage en fondu
        LauncherMethods.FadeWindow(Me, FadeAction.Show, FadeTime.Fast)

        ' Modification de la control box
        Me.PNL_TOP.Font = FontManager.GetFont(My.Resources.MaterialIcons_Regular, 15)
        Me.LBL_CLOSE.Font = PNL_TOP.Font
        Me.LBL_CLOSE.Text = ChrW(&HE5CD)
        Me.LBL_REDUCE.Font = PNL_TOP.Font
        Me.LBL_REDUCE.Text = ChrW(&HE5CF)
      Catch ex As Exception
        Logger.Exception(ex)
      End Try

    End Sub

    #End Region
     
    Bien. Une bonne chose de faite. Pour être sûrs d’être au même niveau, voici le code complet actuel.


    a. Le titre et le logo de la fenêtre

    Nous avons créé la Control Box, mais puisque nous avons enlevé la barre par défaut, le titre a lui aussi disparu. Le logo aussi. Je vous propose d’aller choisir un logo pour votre lanceur. Il y a plusieurs options :

    1. Vous avez déjà un logo
    Vous pouvez le convertir si ce n’est déjà fait sur le site ConvertIco.

    Attention › Un logo de taille 32*32 pixels est très fortement conseillé, si vous réduisez votre logo de 1000*1000 à 32*32, il va être pixelisé et ne rendra pas bien.
    Évitez aussi les ombres, le biseautage, tout ce qui peut faire du relief. Préférez un logo plat.

    2. Vous n’avez pas de logo
    Vous pouvez aller en trouver un sur IconFinder ou prendre un logo Material si vraiment vous n’avez pas d’inspiration. Vous pouvez aussi reprendre le logo de base de Minecraft.

    Pour ma part, j’ai pris un logo sur IconFinder, que j’ai converti en icône sur ConvertIco, et j’ai ajouté des marges au fichier original sur Paint .NET. J’suis un mec polyvalent, moi. :p

    [​IMG]
    Figure 15 - Le logo que j'ai choisi pour mon lanceur

    Importez votre logo en .PNG dans les ressources de votre lanceur, et créez une PictureBox à l’intérieur du PNL_TOP, de la même manière que vos étiquettes de Control Box, mais à gauche :

    • BackColor à Transparent
    • BackgroundImage à votre image dans les ressources
    • BackgroundImageLayout à Zoom
    • Name à PBX_LOGO – ceci est important
    • Dock à Left
    • Size à 38; 38

    Vous avez maintenant un joli logo. Mettez aussi l'image en .ICO dans la propriété Icon de votre Main.
    On va maintenant ajouter une étiquette qui sera le titre :
    • BackColor : Transparent
    • ForeColor : #bdc3c7
    • Ne mettez rien dans Text
    • TextAlign : MiddleLeft
    • Name : LBL_TITLE
    • AutoSize : False
    • Dock : Left
    • Size : 300; 38

    À noter › Mettre une aussi grande largeur est simplement une mesure de précaution. Vous pouvez bien évidemment la réduire.

    Rendez-vous dans la fonction Initialize et ajoutez cette ligne : Me.LBL_TITLE.Text = Me.Text.
    Lancez en appuyant sur F5, et… c’est l’échec ! Si vous avez bien suivi ces étapes, vous ne voyez que la première lettre de votre titre.

    Pour faire face à ce problème, nous allons modifier le code avec lequel nous récupérons les polices d’écriture.
    Ajoutez trois fonctions publiques et partagées, avec comme argument optionnel la taille de la police et comme valeur de retour chaque police d’écriture, dans LauncherVariables : une pour les icônes, les deux autres pour les Roboto que nous allons importer.

    Importez les polices Roboto Regular et Roboto Medium, téléchargées précédemment, dans votre projet.
    Vous pouvez maintenant modifier votre fonction Initialize telle que suit :

    Code (vbnet):

    Private Sub Initialize()

      Try
        ' Prévention des scintillements
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint OrControlStyles.UserPaint OrControlStyles.DoubleBuffer, True)

        ' Modification de la control box
        Me.LBL_CLOSE.Font = LauncherVariables.MATERIAL_ICONS
        Me.LBL_CLOSE.Text = ChrW(&HE5CD)
        Me.LBL_REDUCE.Font = LauncherVariables.MATERIAL_ICONS
        Me.LBL_REDUCE.Text = ChrW(&HE5CF)

        ' Modification du label titre
        Me.LBL_TITLE.Font = LauncherVariables.ROBOTO_REGULAR(12)
        Me.LBL_TITLE.Text = Me.Text

        ' Affichage en fondu
        LauncherMethods.FadeWindow(Me, FadeAction.Show, FadeTime.Fast)

      Catch ex As Exception
        Logger.Exception(ex)
      End Try
    End Sub
     
    Au cas où, voici le LauncherVariables actuel (auquel j'ai d'ailleurs ajouté une constante pour la future taille de la bordure) :
    Code (vbnet):

    Public Class LauncherVariables

      ' -------------------------------------------------------------------------------------
      ' ----- [ CONST ] ---------------------------------------------------------------------
      ' -------------------------------------------------------------------------------------

      Public Const DEBUG As Boolean = True
      Public Const BORDER_SIZE As Integer = 2


      ' -------------------------------------------------------------------------------------
      ' ----- [ POLICES ] -------------------------------------------------------------------
      ' -------------------------------------------------------------------------------------

      Public Shared Function MATERIAL_ICONS(Optional ByVal Size As Single = 15) As Font
        Return FontManager.GetFont(My.Resources.MaterialIcons_Regular, Size)
      EndFunction

      Public Shared Function ROBOTO_REGULAR(OptionalByVal Size AsSingle = 12) As Font
        Return FontManager.GetFont(My.Resources.Roboto_Regular, Size)
      EndFunction

      Public Shared Function ROBOTO_MEDIUM(OptionalByVal Size AsSingle = 12) As Font
        Return FontManager.GetFont(My.Resources.Roboto_Medium, Size)
      EndFunction

    EndClass
     
    Vous lancez votre programme avec F5, et là… le texte s'affiche, mais pixellisé. Le souci, ici, c’est l’anti-crénelage (anti-aliasing en anglais). Par défaut, on ne peut pas modifier la qualité de rendu d’un label. Je vais donc créer un label personnalisé, vous n’êtes pas obligés de le faire.


    b. Optionnel - le label personnalisé

    Créez un nouveau dossier Custom Controls et ajoutez-y une class SmoothLabel. Je suis allé piocher un morceau de code assez simple mais plutôt pratique sur Stackoverflow. Pour pouvoir l’utiliser, votre classe doit être partielle, importer System.Drawing.Text et doit être héritée de Label (l’héritage est un concept de la POO, si vous ne savez toujours pas ce que c'est, je vous conseille... le tutoriel donné en début de tutoriel :3).

    Code (vbnet):

    Imports System.Drawing.Text

    Partial Public Class SmoothLabel

      Inherits Label

      Private _Hint As TextRenderingHint = TextRenderingHint.SystemDefault
      Public Property TextRenderingHint() AsTextRenderingHint
        Get
          Return Me._Hint
        EndGet
        Set(value As TextRenderingHint)
          Me._Hint = value
        EndSet
      EndProperty

      Protected Overrides Sub OnPaint(pe As PaintEventArgs)
        pe.Graphics.TextRenderingHint = TextRenderingHint
        MyBase.OnPaint(pe)
      EndSub
     
    Pour ajouter le contrôle, lancez le programme avec F5 et fermez-le.
    Vous pouvez maintenant supprimer l’étiquette LBL_TITLE et la recréer, mais avec le contrôle SmoothLabel, fraichement ajouté à la boite à outils.

    Paramétrez l’étiquette comme précédemment, et vérifiez que le paramètre TextRenderingHint est bien à AntiAlias. Lancez votre programme : le titre est exactement comme il faut !


    c. Des contours

    Attaquons-nous aux contours. Ils sont assez important esthétiquement, et assez faciles à dessiner. Il nous faut utiliser GDI+ : nous allons réécrire la fonction OnPaintBackground afin de dessiner quelque chose.

    Je vous laisse ajouter cette fonction, facile à comprendre :
    Code (vbnet):

      ''' <summary>
      ''' Se déclenche lors que le fond doit être paint.
      ''' </summary>
      Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)
        MyBase.OnPaintBackground(e)

        ' Ligne de gauche
        e.Graphics.FillRectangle(New SolidBrush(Me.PNL_TOP.BackColor),
        New Rectangle(
        New Point(0, Me.PNL_TOP.Height),
        New Size(LauncherVariables.BORDER_SIZE, (Me.Height - Me.PNL_TOP.Height))))

        ' Ligne de droite
        e.Graphics.FillRectangle(New SolidBrush(Me.PNL_TOP.BackColor),
        New Rectangle(
        New Point(Me.Width - LauncherVariables.BORDER_SIZE, Me.PNL_TOP.Height),
        New Size(LauncherVariables.BORDER_SIZE, (Me.Height - Me.PNL_TOP.Height))))

        ' Ligne du bas
        e.Graphics.FillRectangle(New SolidBrush(Me.PNL_TOP.BackColor),
        New Rectangle(
        New Point(LauncherVariables.BORDER_SIZE, (Me.Height - LauncherVariables.BORDER_SIZE)),
        New Size(Me.Width - (2 * LauncherVariables.BORDER_SIZE), LauncherVariables.BORDER_SIZE)))
      End Sub
     
    Vous pouvez voir le résultat en appuyant sur F5.


    d. Déplacement de la fenêtre

    Vous avez sûrement dû remarquer qu’on ne pouvait pas bouger la fenêtre : cela est dû au fait que nous avons enlevé les bordures par défaut, pour ajouter les nôtres.

    Nous allons donc écrire notre propre gestionnaire de déplacement. Créez un nouveau dossier « Managers » et déplacez-y FontManager. Créez ensuite « MoveManager ».

    Nous devons créer une instance de MoveManager à chaque fois qu’une nouvelle fenêtre sans bordure s’ouvre. Il lui faut donc un constructeur.

    Ce constructeur devra enregistrer une référence vers la fenêtre qui l’appelle ainsi qu’une liste de contrôle sur lesquels nos clics déplaceront la fenêtre. Il faut donc une variable privée ainsi qu’une boucle dans laquelle nous ajouterons des gestionnaires pour les évènements MouseDown et MouseMove :

    Code (vbnet):

      ''' <summary>
      ''' Instanciation du MoveManager, lié à l'objet LinkedForm
      ''' </summary>
      ''' <param name="LinkedForm">La fenêtre à laquelle lier le MoveManager</param>
      ''' <remarks></remarks>
      Public Sub New(ByRef LinkedForm As Form, ByRef MoveableControls As List(OfControl))
        Me._MouseOffset = NewPoint(0, 0)
        Me._LinkedForm = LinkedForm

        For Each MoveableControl AsControl In MoveableControls
          AddHandler MoveableControl.MouseDown, AddressOf _LinkedForm_MouseDown
          AddHandler MoveableControl.MouseMove, AddressOf _LinkedForm_MouseMove
        Next
      End Sub
     
    Les évènements MouseDown et MouseMove devront permettre de modifier la position de la fenêtre en fonction de notre clic de souris : MouseDown permettre d’enregistrer un offset (une distance de compensation) entre la position du clic et la position de la fenêtre, et le MouseMove déplacera la fenêtre en fonction de la position de la souris et de cet offset.

    Code (vbnet):

      ''' <summary>
      ''' Se déclenche lorsque l'utilisateur maintient un clic sur un contrôle listé
      ''' </summary>
      Private Sub _LinkedForm_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
        _MouseOffset = New Point(-(e.X + sender.Location.X), -(e.Y + sender.Location.Y))
      EndSub

      ''' <summary>
      ''' Se déclenche lorsque l'utilisateur déplace sa souris
      ''' </summary>
      Private Sub _LinkedForm_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
        If e.Button = MouseButtons.Left Then
          Dim MousePosition As Point = Control.MousePosition
          MousePosition.Offset(_MouseOffset.X, _MouseOffset.Y)
          _LinkedForm.Location = MousePosition
        End If
      End Sub
     
    Il nous reste à créer une instance de MoveManager au démarrage du lanceur. Ajoutez cette ligne dans la fonction Initiate : Dim MoveManager As New MoveManager(Me, New List(Of Control)(New Control() {PNL_TOP, LBL_TITLE, PBX_LOGO})).

    Ce qui se trouve entre crochets sont les noms des contrôles que nous autorisons à utiliser pour le déplacement. Si vous avez bien compris, vous savez que vous pourrez désormais déplacer la fenêtre grâce au cadre noir en haut, au logo ainsi qu’au titre de la fenêtre, mais pas grâce à la Control Box.



    [​IMG]


    X. L’authentification

    Nous sommes des gens bien. Les cracks, c’est pas bien. On ne va pas autoriser les cracks. On pourrait. Mais on ne va pas le faire.


    a. Préparation


    On va déjà commencer par créer les contrôles nécessaires, soit deux zones de texte, une pour le pseudonyme (ou adresse mail), une pour le mot de passe, et un bouton de validation.

    Commencez par ajouter un Panel à votre Main. Modifiez son nom en PNL_LOGIN, son BackColor en 153 ; 0 ; 0 ; 0, son Size en 300 ; 300, et son Location en 84; 172 – ce dernier paramètre est pour centrer verticalement le panel et le rapprocher du bord gauche.
    Changez également son ForeColor à White.


    1. Les zones de texte

    À noter › Je vais expliquer ici comment utiliser une zone de texte transparente. Vous n’êtes pas obligés de suivre ces étapes, et pouvez utiliser une zone de texte normale.

    Nativement, il n’est pas possible de rendre transparente une zone de texte. Mais un gentilhomme nous a fourni une bibliothèque disponible ici, qui permet d’intégrer une zone transparente.

    Pour l’installer, cliquez-droit sur Tous les Windows Forms dans la boîte à outils, cliquez sur Choisir les éléments, puis Parcourir, et enfin, sélectionnez AlphaBlendTextBox.dll là où vous l’avez extrait. Validez en appuyant sur OK, et ajoutez le contrôle qui vient d’apparaître : vous venez d’intégrer une zone de texte transparente.

    [​IMG]
    AlphaBlendTextBox est apparu dans la boîte à outils

    Pour les autres, vous pouvez simplement prendre une zone de texte normale. Dans les deux cas, appelez cette zone de texte TXT_USERNAME.

    Créez un nouveau Panel et insérez-le dans PNL_LOGIN. Voici ses propriétés :

    • Name : PNL_LOGIN_USERNAME
    • BackColor : 153 ; 0 ; 0 ; 0
    • Location : 30; 182
    • Size : 240; 30
    • Cursor : IBeam

    Maintenant, placez votre TXT_USERNAME dans PNL_LOGIN_USERNAME et centrez-la (location : 8 ; 9, et size : 225 ; 13). Cette astuce de type barbare permet de donner l’impression d’avoir une grande zone de texte.

    Faites pareil pour la zone du mot de passe. Le Panel doit se nommer PNL_LOGIN_PASSWORD et se trouver en 30 ; 218. Sa zone de texte doit, elle, avoir le nom TXT_PASSWORD, et la valeur PasswordChar à « × ».

    Placez maintenant le code suivant dans la zone destinées aux évènements du Login Panel :
    Code (vbnet):

        ''' <summary>
        ''' Se déclenche lorsque l'utilisateur clique sur un panel.
        ''' </summary>
        Private Sub PNL_LOGIN_USERNAME_MouseClick(sender As Object, e As MouseEventArgs) Handles PNL_LOGIN_USERNAME.MouseClick
            TXT_USERNAME.Focus()
        End Sub
        Private Sub PNL_LOGIN_PASSWORD_MouseClick(sender As Object, e As MouseEventArgs) Handles PNL_LOGIN_PASSWORD.MouseClick
            TXT_PASSWORD.Focus()
        End Sub
     
    Ce petit bout de code permettre de mettre le focus sur la zone de texte correspondant à chaque Panel, afin que l'impression de grandeur desdites zones soit totale.

    Malheureusement, il est plus compliqué de changer la qualité du texte d’une zone de texte, je ne vais donc pas le voir ici. À la place, je vais mettre la police d’écriture « Segoe UI » pour les deux zones de texte.



    2. Le bouton de connexion

    Certains d’entre vous vont trouver la méthode qui suit barbare, et ils auront raison. Mais c’est le meilleur moyen que j’ai trouvé de faire ce que je voulais (sans passer par GDI+, évidemment).

    Sachez que vous feriez mieux de modifier le fond directement en utilisant GDI+, mais par simplicité, j’ai choisi ce qui suit :

    Créez un SmoothLabel avec les propriétés suivantes :
    • BackColor : 63 ; 0 ; 0 ; 0 (25% noir)
    • Cursor : Hand
    • Font : Roboto ; 9,25pt
    • ForeColor : 236, 240, 241
    • Text : Connexion
    • TextAlign : MiddleCenter
    • Name : BTN_LOGIN
    • Location : 86;255
    • Size : 129;31
    • TextRenderingHint : AntiAlias
    Ce label nous servira de bouton de connexion. Je n’ai pas utilisé de bouton, car il serait plus compliqué de modifier son anti-crénelage, alors que notre SmoothLabel rend exactement comme si c'était un bouton. Autant donc utiliser notre SmoothLabel.

    Créez un nouveau Label (ou SmoothLabel, peu importe) avec les propriétés suivantes :
    • BackColor : 41 ; 128 ; 185
    • Font : Roboto ;9,25pt
    • ForeColor : White
    • Text : vide
    • Name : LBL_LOGIN_UNDERLINE
    • Location : 86; 284
    • Size : 129; 2
    Vous comprenez ? Cette étiquette va nous servir de bordure inférieure.
    Pour rendre le tout sympathique, ajoutez ceci sous le code déjà présent de la control box :

    Code (vbnet):

      ' -------------------------------------------------------------------------------------
      ' ----- [ LOGIN PANEL ] ---------------------------------------------------------------
      ' -------------------------------------------------------------------------------------

      ''' <summary>
      ''' Se déclenche lorsque la souris entre sur le bouton de connexion.
      ''' </summary>
      Private Sub BTN_LOGIN_MouseEnter(sender As Object, e As EventArgs) Handles BTN_LOGIN.MouseEnter
        Transition.run(BTN_LOGIN, "ForeColor", ColorTranslator.FromHtml("#ecf0f1"), NewTransitionType_Linear(250))
        Transition.run(BTN_LOGIN, "BackColor", Color.FromArgb(154, 0, 0, 0), New TransitionType_Linear(350))
        Transition.run(LBL_LOGIN_UNDERLINE, "BackColor", Color.FromArgb(154, 41, 128, 185), New TransitionType_Linear(500))
      End Sub
      Private Sub BTN_LOGIN_MouseLeave(sender As Object, e As EventArgs) Handles BTN_LOGIN.MouseLeave
        Transition.run(BTN_LOGIN, "ForeColor", Color.White, New TransitionType_Linear(250))
        Transition.run(BTN_LOGIN, "BackColor", Color.FromArgb(63, 0, 0, 0), New TransitionType_Linear(350))
        Transition.run(LBL_LOGIN_UNDERLINE, "BackColor", Color.FromArgb(255, 41, 128, 185), New TransitionType_Linear(500))
      End Sub
     
    Ouvrez maintenant votre lanceur, et regardez le résultat. Joli, n’est-ce pas ?

    Je vais également ajouter deux étiquettes de soulignage sous mes zones de texte. Vous n’êtes pas obligés de le faire, mais si vous le faites, elles auront la même couleur que celle sous le bouton, mais leurs couleurs changeront lors du changement de focus de la zone de texte correspondante :

    Code (vbnet):

      ''' <summary>
      ''' Se déclenche lorsque la focus entre ou sort du mot de passe.
      ''' </summary>
      Private Sub TXT_PASSWORD_Enter(sender As Object, e As EventArgs) Handles TXT_PASSWORD.Enter
        Transition.run(LBL_PASSWORD_UNDERLINE, "BackColor", Color.FromArgb(154, 41, 128, 185), New TransitionType_Linear(500))
      End Sub

      Private Sub TXT_PASSWORD_Leave(sender As Object, e As EventArgs) Handles TXT_PASSWORD.Leave
        Transition.run(LBL_PASSWORD_UNDERLINE, "BackColor", Color.FromArgb(255, 41, 128, 185), New TransitionType_Linear(500))
      End Sub
     
    De même pour la zone du nom d’utilisateur.

    Maintenant que les préparations graphiques sont faites, nous allons passer au script d’authentification.

    [​IMG]
    Figure 16 - État actuel du lanceur, un peu vide dans son ensemble



    b. Utilisation de MojangAPI

    MojangAPI est une bibliothèque de classes que j'ai développée dans le cadre de ce tutoriel, afin de faciliter le processus d'authentification auprès des serveurs de Mojang, et en prévention des futures requêtes que nous allons effectuer sur ces mêmes serveurs, notamment pour la récupération du skin.


    Je vous invite à télécharger cette bibliothèque sur sa page GitHub (bouton Télécharger en haut de l'arborescence). Notez qu'elle est open-source, vous pouvez donc voir l'intérieur de la classe.


    [​IMG]

    Figure 17 - Téléchargement de MojangAPI

    Vous n'avez plus qu'à intégrer cette bibliothèque à votre projet.

    Rappel › pour ajouter une bibliothèque, rendez-vous dans les propriétés du projet (My Project), puis dans références, cliquez sur Ajouter, puis Parcourir..., et trouvez la bibliothèque.

    J'ai simplifié au maximum l'utilisation de cet API afin d'avoir le moins de lignes possible à écrire.
    Je vais expliquer ici comment lancer une requête d'authentification ; si vous voulez plus de détails, jetez un œil dans le readme.md de la page GitHub (en anglais).


    Vous devez tout d'abord déclarer un objet Request, situé dans l'espace de noms MojangAPI :
    Code (vbnet):

    Dim AuthRequest As New Request(Request.Method.POST, URL.AUTHENTICATE)
     
    AuthRequest étant le nom de la variable de type Request, et les deux arguments étant respectivement le type de requête http (ici, POST) et l'adresse de la requête (ici, l'adresse du serveur d'authentification avec l'endpoint /Authenticate).

    À noter › plusieurs adresses sont disponibles dans la classe URL, notamment le Refresh, Validate, Invalidate et Signout du serveur d'authentification.

    La requête étant maintenant créée, il va falloir l'exécuter :
    Code (vbnet):

    Dim AuthResponse As New AuthenticationResponse(
          AuthRequest.Execute(
            Headers.Authenticate(TXT_USERNAME.Text, TXT_PASSWORD.Text)))
     

    Nous avons ici une nouvelle variable AuthResponse de type AuthenticationResponse, qui contient comme paramètre un texte JSON obtenu grâce à la méthode Execute de notre type Request, qui lui-même possède comme argument le Header nécessaire aux requêtes de type POST, qui lui-même contient comme argument le nom d'utilisateur et le mot de passe rentrés dans nos zones de texte.

    À noter › ceci est juste une explication, nous allons créer un thread pour éviter de geler la fenêtre. De plus, nous devons vérifier le contenu des zones de texte avant d'envoyer la requête.

    Le code complet donnerait quelque chose comme ça :

    Code (vbnet):

    Dim AuthRequest As New Request(Request.Method.POST, URL.AUTHENTICATE)
    Dim AuthResponseAs New AuthenticationResponse(AuthRequest.Execute(Headers.Authenticate(TXT_USERNAME.Text, TXT_PASSWORD.Text)))

    If AuthResponseAs .GetResponse.Error = Nothing Then ' On vérifie si une erreur est survenue
      ' Si non, nous avons accès aux tokens et au pseudo de l'utilisateur
      Console.WriteLine("AccessToken: " & AuthenticationResponse.GetResponse.AccessToken)
      Console.WriteLine("ClientToken: " & AuthenticationResponse.GetResponse.ClientToken)
      Console.WriteLine("UserName: " & AuthenticationResponse.GetResponse.UserName) ' Le nom d'utilisateur du joueur. Ce nom n'est pas forcément le contenu de TXT_USERNAME, ce dernier pouvant être une adresse mail
    Else
      Console.WriteLine("Error: " & AuthenticationResponse.GetResponse.ErrorMessage) ' Généralement, un nom d'utilisateur ou mot de passe erroné
    End If
     
    Attention › ne copiez pas ce code. Je l'ai mis dans un but explicatif ; de toute manière, il ne fonctionnera pas sur votre lanceur car il n'y a pas de console visible.


    c. AuthManager et threads [non fonctionnel]

    C'est ici que les choses vont se compliquer.
    Si vous avez effectué des tests avec MojangAPI, vous aurez sans doute remarqué qu'une requête est bloquante, car je n'ai pas intégré de multi-threading dans cette bibliothèque de classes.
    Nous allons donc devoir utiliser notre propre système de multi-threading, afin d'éviter de bloquer l'interface utilisateur lors d'une requête.

    À noter › si nous effectuons des actions « bloquantes » sur un thread, nous devrons attendre que l'opération soit terminée pour interagir à nouveau avec ce thread. Créer un autre thread permet d'effectuer des actions bloquantes sur ce dernier et de continuer à interagir avec le premier (ici, l'interface).

    1. Création de la classe AuthManager
    C'est une classe qui va gérer les authentifications. Nous allons définir un évènement AuthRequestFinished avec comme paramètre un objet AuthentificationResponse (de MojangAPI).

    [En cours d'écriture]




    [​IMG]




    Le tutoriel est toujours en cours de rédaction.
    Je passe beaucoup de temps sur sa rédaction, un commentaire ou une appréciation serait la bienvenue :)
    Il ne sera pas finit de si tôt, mais j'avance le plus vite possible. J'attends vos commentaires ! Merci d'avoir lu. :)
    « guillemets »
     
    • J'aime J'aime x 3
    • Utile Utile x 2
    • Gagnant Gagnant x 1
    #1 Hawezo, 10 Fev 2016
    Dernière édition: 14 Fev 2016
  2. Pikachu

    Pikachu Mineur

    Inscrit:
    26 Avr 2014
    Messages:
    392
    Points:
    89
    Sexe:
    Homme
    Je m'y connais pas trop, mais ça à l'air bien.

    Mais sinon... euh... pourquoi ne pas utiliser le launcher par défaut, il est bien non ? :3
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
    • Amusant Amusant x 1
  3. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Salut, merci :)
    De nombreux admins souhaitent avoir leur propre launcher, en signe d'investissement pour leur serveur, et il y a aussi les serveurs moddés, dont le launcher téléchargera automatiquement les mods :p

    EDIT : J'ai commencé la suite. J'ai édité le premier post :)
    EDIT : J'ai bien avancé la partie graphisme, premier post à jour :)
     
    • J'aime J'aime x 1
    #3 Hawezo, 10 Fev 2016
    Dernière édition: 10 Fev 2016
  4. Dracoctix

    Dracoctix Rédacteur en Chef
    Staff

    Inscrit:
    15 Mai 2013
    Messages:
    5 257
    Points:
    239
    Sexe:
    Homme
    Je lisais le début du tutoriel et je me suis interrogé sur quelque chose : pourquoi utiliser Visual Studio Express alors que VS community est plus complet et gratuit (à condition que ce ne soit pas une entreprise de plus de 5 salariés et qu'il n'y ait pas de trop haut revenus)

    A part ça, le tutoriel m'a l'air bien sympa :)
     
    • Sympa Sympa x 1
  5. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Dracoctix > Je ne connaissais pas VS Community, je viens d'aller voir, et effectivement, il est mieux que Visual Studio Express. Je te remercie de me l'avoir montré ^^
    Mais du coup, je vais continuer sous Express, puisque j'ai commencé dessus. Je vais quand même mentionner Community dans le post, merci à toi :)
     
    • J'aime J'aime x 2
  6. Dracoctix

    Dracoctix Rédacteur en Chef
    Staff

    Inscrit:
    15 Mai 2013
    Messages:
    5 257
    Points:
    239
    Sexe:
    Homme
    De rien :)
    Après, un gros avantage de Community est le support des extensions, par exemple pour les personnes qui veulent faire des mods minecraft avec VS (pas bonne idée mais bon), c'est mieux :)

    EDIT : autrement, indiquer "WinForm" ou "WPF" serait bien, car même si l'on sait créer un projet on peut être embrouillé (même si les mentions de size présupposent du WinForm)
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
  7. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Je confirme que c'est un avantage, j'ai déjà essayé d'installer des extensions, impossible avec la version Express :(
    C'était des extensions pour auto-incrémenter le numéro de build et de révision du projet, ce qui s'avérer assez pratique...
    C'est mit à jour dans le post, merci :)
     
    • J'approuve J'approuve x 1
  8. Dracoctix

    Dracoctix Rédacteur en Chef
    Staff

    Inscrit:
    15 Mai 2013
    Messages:
    5 257
    Points:
    239
    Sexe:
    Homme
    Autrement, ce serait une bonne idée de spécifier si le projet doit être WinForm ou WPF car même une personne qui sait créer un projet peut être embrouillée (bien que la mention de Size présuppose du WinForm) :)
     
    • J'aime J'aime x 1
    • J'approuve J'approuve x 1
  9. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    C'est vrai, je n'y ai pas spécialement fait attention. Bien que je parle du WPF en bas, je vais ajouter la précision, au début du tutoriel, au cas où ^^

    EDIT :

    J'ai encore mis à jour le tutoriel. Aujourd'hui j'ai ajouté tout ceci :

    Et je vais peut-être encore continuer ce soir. J'espère au moins que ça vous sera utile \o/
     
    • J'approuve J'approuve x 2
    #9 Hawezo, 10 Fev 2016
    Dernière édition: 10 Fev 2016
  10. Arti_Chaud

    Arti_Chaud Modérateur

    Inscrit:
    17 Sept 2015
    Messages:
    247
    Points:
    93
    Sexe:
    Homme
    @Hawezo attention aux double posts. Tu n'es pourtant pas un nouveau tu dois connaître le règlement ;)
     
    • Sympa Sympa x 1
  11. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Oops, j'étais persuadé que quelqu'un avait répondu :s
    Je vais fusionner ^^'

    EDIT : C'est fait, merci :*
     
  12. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Pour information, je n'avance pas plus le tutoriel à cause d'un soucis d'authentification. À cause de mes tests quand j'ai développé MojangAPI, il m'arrive d'être bloqué temporairement quand j'essaie de me connecter, ce qui est gênant. J'essaierai de reprendre l'écriture du tutoriel dès que possible ^^
     
    • Informatif Informatif x 1
  13. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Yo, à priori, mon problème est résolu. À un jour de la fin de mes vacances, youpi. En plus, je suis interne. Mais je continue dès que je peux !
     
    • Informatif Informatif x 1
  14. MindMod

    MindMod Nouveau

    Inscrit:
    24 Fev 2016
    Messages:
    14
    Points:
    2
    Sexe:
    Homme
    Il y en a qui s’amuse bien on dirait :)
    Étant un grand amateur de Vb.Net je peux dire que c'est simple et bien expliqué en détail mais tu complique un peu les chose dans tes explication, tu gagnerais plus de lisibilité en résument un peu tout ça !
    Et aussi par exemple séparer tout ce qui est GUI du reste...
    Après c'est juste une idée, pour que se soit plus lisible !

    En tout cas il t'a fallu de la patience, bravo :diamond:
     
    • J'approuve J'approuve x 2
    • J'aime J'aime x 1
  15. Hawezo

    Hawezo Mineur de Fer

    Inscrit:
    6 Juin 2013
    Messages:
    545
    Points:
    146
    Sexe:
    Homme
    Salut, merci ^^
    Après avoir finit le tutoriel (ce qui n'est finalement pas pour tout de suite, j'ai repris les cours), je compte le relire entièrement et reformuler les explications, voir peut-être réorganiser certaines parties ^^
    Pour ce qui est de séparer GUI/code, de toute manière la partie la plus important niveau code est pas encore écrite (authentification, récupération du skin (ça ce sera bonus), et lancement de Minecraft).
    Merci pour tes conseils

    EDIT : je vais peut-être même faire un tutoriel pour faire un design en WPF, parce que ça la fout mal la manière dont je design le launcher avec les contrôles de WinForms :p
     
    • Informatif Informatif x 1

Partager cette page