Lors de l'écriture de la version FMX de ce jeu, une idée, en relation avec mes travaux sur les styles, m'a titillé : était-il possible d'utiliser un style pour charger les pièces du puzzle ? L'utilisation de la palette Style m'était jusqu'à présent plutôt "terra incognita" et ses objets souvent source de frustrations au cours de mes divers démêlés avec les styles.
Je tiens à souligner qu'il s'agit bien des styles FMX, ceux utilisés en VCL sont beaucoup plus "figés" et, s'il y a similitudes et possibilités de transformation de l'un vers l'autre mes "recherches" n'ont pas été plus loin dans cette direction.
L'occasion faisant donc le larron, je me suis donc mis en tête de créer un style qui contiendrait l'image de mon puzzle ainsi que la découpe de ses différentes pièces.
Un outil est proposé : le concepteur de style de bitmaps et c'est d'abord par là que mes efforts se sont portés. Mal m'en a pris pour une première utilisation, ce fut un échec total ! J'en ai certainement mal compris les arcanes ou l'outil n'est pas fait pour l'objectif fixé.
Je suis alors passé par ce que je connais mieux : le dépôt d'un TStyleBook sur une forme et l'ouverture de son éditeur.
Voilà ce que je veux obtenir :
Je vais maintenant indiquer les diverses étapes qui m'ont été nécessaires pour réaliser cela.
Mais, tout d'abord, notez que le style sera un style dit 'Default' afin qu'il s'applique quelle que soit la plateforme cible.
- Double-cliquez sur le composant StyleBook1 déposé sur la forme afin d'ouvrir le concepteur de styles.
- Glissez-déposez ensuite un TImage dans l'arborescence du StyleContainer.
- Chargez une image (propriété MultiResBitmap) et changer la propriété StyleName en quelque chose de plus "parlant" que le nom par défaut proposé Image1Style(un nom neutre me sera utile plus tard aussi utiliserai-je 'modele' pour la suite).
Il est désormais temps de créer notre première pièce du puzzle.
- Glissez-déposez un TLayout au niveau de la racine (StyleContainer) et dans ce TLayout, auquel vous aurez changé la propriété StyleName en 'piece01', ajoutez un TStyleObject.
- Changez la propriété StyleLookup du StyleObject créé (y mettre le StyleName du TImage).
- Utilisez le bouton proposé par la propriété SourceLink qui va ouvrir une nouvelle fenêtre, Éditeur BitmapLinks.
- La première chose à faire est de réduire le zoom de façon à visualiser l'image entière.
- Agrippez les deux coins jaunes de façon à retailler la zone à définir. Quand vous les déplacerez, les valeurs TBounds (en haut de la fenêtre) se modifieront. L'objectif est d'obtenir une taille de 100 x 100 (mon image de base étant en 400 x 400).
Ce n'est pas forcément évident au début, ne vous focalisez pas trop sur des délimitations juste, nous verrons plus tard comment ranger cela.
- Refaites alors les opérations pour chaque pièce.
Le refaire pour chaque pièce, même s'il y en a que 16, c'est long ! Toutefois, pour comprendre certains principes et avant que j'explique comment
créer ces pièces plus rapidement, prenez le temps de créer la pièce numéro 2 (à droite de la première, TBounds(100,00,0,00)-(200,00,100,00)) et celle qui sera sous la première (pièce numéro 5, TBounds(0,00,100,00)-(100,00,200,00)).
Je vous livre donc l'astuce, pour éviter ces répétitions et corriger les petits défauts de positions :
- Sauvegardez votre style (vous avez un bouton pour cela). Assurez vous de bien utiliser l'extension .style pour obtenir une version texte de ce dernier, l'extension .fsf produira une version "compilée", j'écrirai plutôt compressée, illisible.
- Ouvrez le fichier créé avec un outil tel que Notepad++.
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | object TStyleContainer object TImage StyleName = 'modele' MultiResBitmap.Height = 400 MultiResBitmap.Width = 400 MultiResBitmap = < item Width = 400 Height = 400 PNG = { 89504E470D0A1A0A0000000D494844520000019000000190080600000080BF36 CC000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000 FFBA49444154785EECBD07A0654771E75D2FE737392AA2882414404248800011 <!-- je vous fais grâce des quelque 2700 lignes suivantes de l''image --> 66FB0FEEB55FF8D0476CDFCEFD9136373F671DED1DE107350352A142850A152A 340EB3FF13E4E33CC0A3EE7CFE0000000049454E44AE426082} FileName = 'D:\serge\Documents\Embarcadero\Studio\Projets\Sidney\stoneedge.png' end> Align = Center Size.Width = 274.000000000000000000 Size.Height = 269.000000000000000000 Size.PlatformDefault = False Visible = False end object TLayout StyleName = 'piece01' Align = Center Visible = False TabOrder = 3 object TStyleObject StyleName = 'StyleObject1Style' SourceLookup = 'Modele' SourceLink = < item SourceRect.Left = 2.000000000000000000 SourceRect.Top = 1.000000000000000000 SourceRect.Right = 100.000000000000000000 SourceRect.Bottom = 100.000000000000000000 end> end end object TLayout StyleName = 'piece02' Align = Center Visible = False TabOrder = 2 object TStyleObject StyleName = 'StyleObject1Style' SourceLookup = 'Modele' SourceLink = < item SourceRect.Left = 100.000000000000000000 SourceRect.Right = 200.000000000000000000 SourceRect.Bottom = 100.000000000000000000 end> end end object TLayout StyleName = 'piece05' Align = Center TabOrder = 1 object TStyleObject StyleName = 'StyleObject1Style' SourceLookup = 'Modele' SourceLink = < item SourceRect.Top = 100.000000000000000000 SourceRect.Right = 100.000000000000000000 SourceRect.Bottom = 200.000000000000000000 end> end end end |
Ce qui nous intéresse, c'est un bloc de TLayout, définissant une piéce
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | object TLayout StyleName = 'piece01' Align = Center Visible = False TabOrder = 3 object TStyleObject StyleName = 'StyleObject1Style' SourceLookup = 'Modele' SourceLink = < item SourceRect.Left = 2.000000000000000000 SourceRect.Top = 1.000000000000000000 SourceRect.Right = 100.000000000000000000 SourceRect.Bottom = 100.000000000000000000 end> end end |
- Sauvegardez le fichier modifié.
- Revenez à l'IDE Delphi et à votre programme.
- Chargez à nouveau le style (pour récupérer les modifications faites).
Il ne reste plus qu'à utiliser le style.
N'oubliez pas, même si la clôture de l'onglet Concepteur de styles se charge de vous le rappeler, d'appliquer le style (bouton le plus à droite).
Dans la deuxième image de cet article, pour illustrer l'objectif, j'ai utilisé un TGridLayout pour contenir des TPanels qui, eux, auront chacun une propriété StyleLookup différent.
Il n'est pas sûr que le TGridLayout soit le composant le plus adapté pour codifier le jeu, mais, il n'était pas non plus dans mes desseins que de le faire.
Par contre, je me suis plus attardé sur l'image, était-il possible de changer l'image utilisée dans le style à l'exécution ?
J'aurais, bien sûr, pu faire un style par image, mais ma curiosité m'a poussé à le vérifier.
De l'idée, loufoque, à la réalisation, il ne m'a fallu qu'un peu de code et quelques explorations de solutions concernant l'application du style ainsi modifié.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | procedure TMainForm.ButtonChangeImageClick(Sender: TObject); var pStream : TMemoryStream; pFMXObj : TFMXObject; begin // Passage de l'image via un stream pStream:=TMemoryStream.Create; try PStream.LoadFromFile('test1.png'); pFMXObj:=StyleBook1.Style.FindStyleResource('modele'); if Assigned(pFMXObj) then begin PStream.Position:=0; TImage(pfMXObj).Bitmap.LoadFromStream(Pstream); end; finally pStream.Free; end; //pFMXObj:=StyleBook1.Style.FindStyleResource('modele'); //if Assigned(pFMXObj) then // begin // TImage(pfMXObj).Bitmap.LoadFromFile('test1.png'); // end; // Forcer le dessin du GridLayout GridLayout1.BeginUpdate; GridLayout1.EndUpdate; // variante Repaint par piece //for var i:= 0 to GridLayout1.ChildrenCount-1 do // TPanel(Gridlayout1.Children[i]).Repaint; // Variante re-dessin complet //for var i:= GridLayout1.ChildrenCount-1 downto 0 do // Gridlayout1.Children[i].Free; // //for var i := 1 to 16 do // begin // with TPanel.Create(Self) do // begin // StyleLookup:=Format('piece%.2d',[i]); // Parent:=GridLayout1; // end; // end; end; |
Je suis prêt à parier qu'il y a encore d'autres solutions code que je n'ai pas explorées à l'heure actuelle.
Je gage aussi que changer le découpage de pièces en fonction de la taille de l'image (j'ai triché en utilisant des images de tailles identiques de 400x400) l'est tout autant. C'est une autre histoire à écrire. Atteindre les propriétés de SourceRect ne sera pas aussi simple.
En tout cas, j'espère que cette utilisation "ludique" des styles FMX changera peut-être votre opinion sur ceux-ci.