<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Forum du club des développeurs et IT Pro - Blogs - Blog de Serge Girard (aka SergioMaster) par SergioMaster</title>
		<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/</link>
		<description>Developpez.com, le Club des Développeurs et IT Pro</description>
		<language>fr</language>
		<lastBuildDate>Sat, 11 Apr 2026 16:11:52 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>15</ttl>
		<image>
			<url>https://forum.developpez.be/images/misc/rss.jpg</url>
			<title>Forum du club des développeurs et IT Pro - Blogs - Blog de Serge Girard (aka SergioMaster) par SergioMaster</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/</link>
		</image>
		<item>
			<title><![CDATA[[FMX] Des navigateurs de données (TBindNavigator) en couleur]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10650/fmx-navigateurs-donnees-tbindnavigator-couleur/</link>
			<pubDate>Sat, 09 Nov 2024 10:09:01 GMT</pubDate>
			<description>Via ce billet, je vous...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Via ce billet, je vous propose d'égayer le composant<b> FMX <i>TBindNavigator</i></b>.<br />
On pourrait penser que toucher au style permettrait ce genre de chose, mais cet élément de style n'existe pas. <br />
La couleur appliquée pour les glyphes est celle de la couleur d'un texte du style en cours. Pour les curieux le code d'obtention de cette couleur se trouve dans la procédure <b><i>TBindNavButton.ApplyStyle</i></b> de  l'unité  <b><i>FMX.Bind.Navigator.</i></b><br />
En n'utilisant &quot;aucun&quot; style on obtient ceci<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=661509&amp;d=1731143001" border="0" alt="Nom : Capture_2.PNG
Affichages : 2642
Taille : 5,8 Ko"  style="float: CONFIG" /><br />
<br />
Alors qu'en <b>VCL</b> un navigator s'affiche ainsi<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=661510&amp;d=1731143125" border="0" alt="Nom : Capture_1.PNG
Affichages : 598
Taille : 4,8 Ko"  style="float: CONFIG" /><br />
<br />
Bien qu'en FMX je ne suis pas un fervent utilisateur du composant <b><i>TBindNavigator</i></b> ou alors uniquement de la partie concernant la navigation, je me suis mis au défi de customiser ce composant. Avant de passer à de grands travaux, l'écriture d'un composant, j'ai voulu tester la faisabilité via des <b><i>Helpers</i></b>.<br />
<br />
Je vous propose donc cette unité <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br /></div></td><td valign="top"><pre style="margin: 0">unit ColoredBindNavigator;

interface

 uses System.Classes, System.UIConsts,System.UITypes,
      FMX.Bind.Navigator, Data.Bind.Controls;

/// range TNavigateButton in three groups
const   NavigatorScrollings = [nbFirst, nbPrior, nbNext, nbLast,nbRefresh];
        NavigatorValidations = [nbInsert, nbDelete, nbEdit, nbPost, nbCancel,
                                nbApplyUpdates];
        NavigatorCancelations = [nbDelete,nbCancel,nbCancelUpdates];

type

  TNavigatorColors = record
    scroll : TAlphacolor;
    update : TAlphacolor;
    cancel : TAlphacolor;
    class operator initialize (out Dest: TNavigatorColors);
    class operator finalize (var Dest: TNavigatorColors);
  end;

  TColorNavButton = class helper for TBindNavButton
    /// set the color of the Tpath.fill.color property
    procedure setcolor(c : TAlphaColor);
    /// apply the custom colors corresponding to the TNavigateButton type
    /// Three groups NavigatorScrollings,NavigatorValidations,NavigatorCancelations
    /// see const part
    procedure ApplyColorStyle(customcolors : TNavigatorColors);
  end;

  TColorBindNavigator = class helper for TCustomBindNavigator
    /// initialize and apply custom colors
    function customcolors(scrollcolor, Updatecolor, cancelcolor : TAlphaColor) : TNavigatorColors; overload;
    function customcolors(colors : TNavigatorColors) : TNavigatorColors; overload;
  end;

implementation

{ TColorNavButton }
procedure TColorNavButton.ApplyColorStyle(customcolors : TNavigatorColors);
var defaultstylecolor : TAlphaColor;
begin
inherited;
with Self do
  DefaultStylecolor:=FPath.Fill.Color;
if (TNavigateButton(Self.index) in NavigatorScrollings)
    AND (customcolors.scroll&lt;&gt;TAlphacolors.Alpha)
// todo test    AND (customcolors.scroll&lt;&gt;DefaultStyleColor)
 then Setcolor(customcolors.scroll);
if (TNavigateButton(Self.index) in NavigatorValidations)
    AND (customcolors.update&lt;&gt;TAlphacolors.Alpha)
 then Setcolor(customcolors.update);
if (TNavigateButton(Self.index) in NavigatorCancelations)
    AND (customcolors.cancel&lt;&gt;TAlphacolors.Alpha)
 then Setcolor(customcolors.cancel);
end;

procedure TColorNavButton.setcolor(c: TAlphaColor);
begin
with Self do
   FPath.Fill.Color:=c;
end;

{ TNavigatorColors }
class operator TNavigatorColors.finalize(var Dest: TNavigatorColors);
begin
// nothing to do
end;

class operator TNavigatorColors.initialize(out Dest: TNavigatorColors);
begin
Dest.scroll:=TAlphaColors.Alpha;
Dest.update:=TAlphaColors.Alpha;
Dest.cancel:=TAlphaColors.Alpha;
end;


{ TColorBindNavigator }
function TColorBindNavigator.customcolors(scrollcolor, Updatecolor,
  cancelcolor: TAlphaColor) : TNavigatorColors;
begin
result.scroll:=scrollcolor;
result.update:=updatecolor;
result.cancel:=cancelcolor;
for var i := 0 to  self.ControlsCount-1 do
      TBindNavButton(Self.Controls[i]).ApplyColorStyle(result);
end;

function TColorBindNavigator.customcolors(
  colors: TNavigatorColors): TNavigatorColors;
begin
for var i := 0 to  self.ControlsCount-1 do
      TBindNavButton(Self.Controls[i]).ApplyColorStyle(colors);
end;

end.</pre></td></tr></table></pre>
</div>L'utilisation en est assez simple :<br />
<ol class="decimal"><li style="">Ajoutez l'unité au projet.</li><li style="">Dans la forme contenant le composant <b><i>TBindNavigator</i></b> que vous voulez &quot;colorier&quot;, ajoutez l'unité à la clause uses dans la partie interface.Vous obtiendrez alors quelque chose de ce genre :</li></ol><br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:192px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td valign="top"><pre style="margin: 0">
interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  Data.Bind.Controls, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts,
  Fmx.Bind.Navigator, FMX.Memo.Types, FMX.ScrollBox, FMX.Memo, FMX.Objects,
  FireDAC.Stan.Intf, FireDAC.Stan.Option, FireDAC.Stan.Param,
  FireDAC.Stan.Error, FireDAC.DatS, FireDAC.Phys.Intf, FireDAC.DApt.Intf,
  FireDAC.Stan.StorageBin, Data.Bind.Components, Data.Bind.DBScope, Data.DB,
  FireDAC.Comp.DataSet, FireDAC.Comp.Client<b>,
  ColoredBindNavigator</b>;</pre></td></tr></table></pre>
</div><ol class="decimal"><li style="">Déclarez une variable privée (à moins que vous ne vouliez la partager) au sein de votre forme.</li></ol><br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td valign="top"><pre style="margin: 0">type
  TForm1 = class(TForm)
    BindNavigator1: TBindNavigator;
    btnDark: TButton;
    Memo1: TMemo;
    FDMemTable1: TFDMemTable;
    BindSourceDB1: TBindSourceDB;
    Label1: TLabel;
    StyleBook1: TStyleBook;
    Button1: TButton;
    procedure btnDarkClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
<b>     Colors : TNavigatorColors;</b>
  public
    { Déclarations publiques }
  end;</pre></td></tr></table></pre>
</div><ol class="decimal"><li style="">Utilisez ensuite les diverses fonctions proposées.</li></ol><br />
Deux exemples :<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:108px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0">
procedure TForm1.FormCreate(Sender: TObject);
begin
CustomColorsNavigator :=true;
colors:=BindNavigator1.customcolors(Talphacolors.blue,Talphacolors.Green,Talphacolors.Red);
end;</pre></td></tr></table></pre>
</div><div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">
procedure TForm1.btnDarkClick(Sender: TObject);
begin
 colors.scroll:=Talphacolors.darkBlue;
 colors.update:=Talphacolors.darkGreen;
 colors.cancel:=TAlphacolors.darkRed;
 for var i := 0 to  BindNavigator1.ControlsCount-1 do
      TBindNavButton(BindNavigator1.Controls[i]).ApplyColorStyle(colors);
end;</pre></td></tr></table></pre>
</div>Vous pourrez ainsi obtenir ce navigateur, qui sans être totalement identique à celui proposé en VCL, la technique des <b><i>TPath</i></b> utilisée empêchant un remplissage autre que monochrome les boutons <b><i>nbApplyUpdates</i></b> et<b><i> nbCancelUpdates</i></b> sont donc un peu pénalisés. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=661511&amp;d=1731144508" border="0" alt="Nom : Capture_3.PNG
Affichages : 594
Taille : 5,3 Ko"  style="float: CONFIG" /><br />
<br />
<a href="https://www.developpez.net/forums/attachment.php?attachmentid=661512&amp;d=1731146490"  title="Nom : CustomNavigator.zip
Affichages : 81
Taille : 108,0 Ko">CustomNavigator.zip</a> contient les sources de mon programme test écrit en Delphi 12&#1469;_1. <br />
Note : L'utilisation d'un <a href="https://blogs.embarcadero.com/custom-managed-records-coming-to-delphi-10-4/" target="_blank">managed record</a> limite aux versions supérieures ou égales à 10_4.<br />
<br />
Que reste t-il à contrôler ? L'utilisation d'un style, mes essais m'ont imposé l'utilisation d'une variable et d'un évènement OnPainting (commentés dans le source proposé), vérifiez donc que les commentaires sur ce billet ne contienne pas un correctif car bien évidemment ;) je ne veux pas rester sur cette constatation.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10650/fmx-navigateurs-donnees-tbindnavigator-couleur/</guid>
		</item>
		<item>
			<title>Transformer une base de données CHARACTER SET NONE, SQL DIALECT 1</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10643/transformer-base-donnees-character-set-none-sql-dialect-1/</link>
			<pubDate>Tue, 22 Oct 2024 14:02:41 GMT</pubDate>
			<description><![CDATA[J'utilise Firebird depuis des...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">J'utilise Firebird depuis des années, en fait pratiquement depuis sa parution, et ce, à la place d'Interbase.<br />
J'ai commencé avec Interbase 5, novice à l'époque ma base de données avait été créée avec le set de caractères <b>CHARACTER SET NONE</b> et en <b>DIALECT SQL 1</b>, rien n'indiquait à l'époque qu''il était fortement conseillé d'utiliser des CHARACTER SET différent de celui par défaut (le fameux NONE) quant au SQL DIALECT soit j'ai mal cherché dans la documentation que j'ai encore, soit il n'existait que le 1 (et peut-être le 2).<br />
<br />
La base de données ayant été ensuite mise en production, autant par fénéantise que par méconnaissance, elle est restée telle quelle depuis lors. <br />
La migration d'interbase vers Firebird 1.5, 2 puis 2.5 s'étant passé sans difficultés (par l'intermédaire d'un backup portable de l'ancienne version puis d'un restore avec la nouvelle), à part quelques frustations à cause du SQL DIALECT entre autres avec les fonctions de Date.<br />
<br />
Passer la base de données telle quelle vers les nouvelles versions Firebird 3, 4 ou 5 avec cette même technique, c'est possible, mais j'ai voulu profiter de cette occasion pour opérer ces changements.<br />
<br />
<b><u>Changer de CHARACTER SET</u></b><br />
Sous Windows, lancez dans une console (powershell ou cmd) le programme ISQL que l'on peut trouver dans la racine de l'installation de Firebird<br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>PowerShell</strong>
					
				</div>
				<div class="message">PS  ... &gt; CD &quot;C:\program files\firebird\firebird_4_0&quot;<br />
PS  C:\program files\firebird\firebird_4_0 &gt; ./ISQL -user sysdba -password masterkey &lt;nom de la base à transformer entre &quot; &quot; ou nom de l'alias&gt;<br />
SQL &gt; ALTER DATABASE SET DEFAULT CHARACTER SET WIN1252;<br />
SQL &gt; QUIT; </div>
			
		</div>
	</div>
</div>:alerte: AMHA Changer de set de caractère devra forcément passer par l'étape WIN1252<br />
<br />
<b><u>Changer de SQL DIALECT </u></b><br />
Sous Windows, lancez dans une console (powershell ou cmd) le programme gfix que l'on peut trouver dans la racine de l'installation de Firebird<br />
<div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				PS  ... &gt; <br />
CD &quot;C:\program files\firebird\firebird_4_0&quot;<br />
PS C:\program files\firebird\firebird_4_0&gt; ./gfix -sql_dialect 3 &lt;nom de la base à transformer entre &quot; &quot; ou nom de l'alias&gt; -user sysdba -password masterkey
			
		</div>
	</div>
</div>Pour vous assurer que tout est OK un retour dans ISQL et la commande <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">SHOW</span> SQL DIALECT;</span> devrait vous rassurer.<br />
<br />
Bien évidemment il faudra ensuite faire la chasse <a href="https://firebirdsql.org/file/documentation/release_notes/html/en/4_0/rlsnotes40.html#rnfb40-reswords" target="_blank">aux mots clés</a>, abandonner les UDFs et prendre en compte les nouveaux types de données (en particulier l'utilisation des CURRENT_TIMESTAMP et CURRENT_TIME dans les procedures à remplacer par LOCALTIMESTAMP et LOCALTIME) qui sont elles rapportées dans <a href="https://ib-aid.com/download/docs/fb4migrationguide.pdf" target="_blank">les guides de migration</a> chapitre 2.<br />
<br />
Notes : <br />
<ul><li style="">Par &quot;abandon des UDF&quot; je veux souligner que l'utilisation des UDF est désormais considéré comme obsolète (chapitre 2.2).</li><li style="">Les littéraux de dates ou heure ('NOW','TODAY',...) sont désormais dépréciés et peuvent produire des résultats inattendus. </li></ul><br />
<br />
<br />
Cependant, mes dernières interventions ou contacts via le forum, me font penser que beaucoup sont dans le cas tel que décrit, c'est pour ceux-là que j'ai voulu vous faire part de ces deux petites astuces ;)</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10643/transformer-base-donnees-character-set-none-sql-dialect-1/</guid>
		</item>
		<item>
			<title>Sortie des éditions communautaires Delphi 12 et C++Builder 12 !</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10623/sortie-editions-communautaires-delphi-12-cppbuilder-12/</link>
			<pubDate>Tue, 30 Jul 2024 13:09:59 GMT</pubDate>
			<description>---Citation (Envoyé par...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><div class="bbcode_container">
	<div class="bbcode_quote">
		<div class="quote_container">
			<div class="bbcode_quote_container"></div>
			
				<div class="bbcode_postedby">
					<img src="https://forum.developpez.be/images/misc/quote_icon.png" alt="Citation" /> Envoyé par <strong>SergioMaster</strong>
					<a href="showthread.php?p=12037046#post12037046" rel="nofollow"><img class="inlineimg" src="https://forum.developpez.be/images/buttons/viewpost-right.png" alt="Voir le message" /></a>
				</div>
				<div class="message"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=657690&amp;d=1722344772" border="0" alt="Nom : Capture.PNG
Affichages : 8980
Taille : 929,9 Ko"  style="float: CONFIG" /><br />
<br />
<a href="https://blogs.embarcadero.com/delphi-12-and-cbuilder-12-community-editions-released/?utm_source=Eloqua&amp;utm_medium=email&amp;utm_content=Article-240730-Multicontent" target="_blank">Source de l'annonce</a><br />
<br />
Embarcadero vient d'annoncer le lancement de Delphi 12 Community Edition et de C++Builder 12 Community, deux versions gratuites et complètes du célèbre IDE Delphi et de l'IDE phare C++Builder.<br />
<br />
Les versions Community Edition sont conçues pour permettre aux startups, aux étudiants et aux amateurs de créer des applications Delphi robustes et évolutives sur plusieurs plates-formes, notamment iOS, Android, Windows et macOS, ou de puissantes applications C++ pour Windows.<br />
<br />
Bien que le programme Community Edition ne soit pas nouveau, Embarcadero propose aujourd'hui la version et la licence Community Edition pour la version 12.1 la plus récente de Delphi et C++Builder. Bien qu'il y ait souvent eu du retard dans la mise à disposition de CE vers les dernières versions, Embarcadero a décidé de publier les éditions communautaires plus tôt afin d'offrir toutes les nouvelles fonctionnalités de Delphi 12 et C++Builder 12 à la communauté des développeurs dans son ensemble.<br />
<br />
<b>Qu’est-ce que l’édition communautaire*?</b><br />
<br />
Les éditions communautaires gratuites et complètes de Delphi et C++Builder sont conçues pour vous aider à démarrer la programmation. <br />
<br />
Principales caractéristiques:<br />
<br />
<ul><li style="">IDE complet*: profitez d'un environnement de développement complet avec un puissant éditeur de code, des outils de débogage et un accès intégré aux bases de données locales populaires.</li><li style="">Pour Delphi, développement multiplateforme*: créez des applications à partir d'une seule base de code Delphi qui s'exécutent de manière native sur plusieurs plates-formes.</li><li style="">Pour Delphi et C++Builder, cadres et composants visuels*: utilisez les cadres et composants visuels renommés de RAD Studio pour fournir de superbes interfaces utilisateur stylisées pour vos applications.</li></ul><br />
<br />
<br />
Avec cette nouvelle version, les utilisateurs de Community Edition peuvent désormais profiter des innovations marquantes des versions 12 Athens et 12.1 Athens, notamment la nouvelle chaîne d'outils Clang dans C++Builder, la prise en charge des dernières versions d'Android pour Delphi, la prise en charge de Skia FireMonkey et de nouvelles fonctionnalités. dans l'EDI RAD Studio pour les deux produits.<br />
<br />
<b>À qui s'adresse l'édition communautaire*?<br />
</b><br />
Les éditions communautaires sont parfaites pour*:<br />
<br />
<ul><li style="">Développeurs indépendants*: créez et vendez des applications jusqu'à ce que vos revenus atteignent 5*000*$ par an.</li><li style="">Startups*: utilisez l'édition communautaire si votre chiffre d'affaires annuel est inférieur à 5 000 $ et si votre équipe compte jusqu'à 5 développeurs.</li><li style="">Étudiants*: découvrez et expérimentez des outils de niveau professionnel pour démarrer votre carrière de développement.</li></ul><br />
<br />
<br />
Les éditions communautaires sont disponibles gratuitement pour les développeurs et les organisations comptant moins de cinq développeurs. <u>Vous ou votre entreprise devez avoir un chiffre d'affaires inférieur à 5 000 $ US.</u> Ils sont accompagnés d'une licence d'un an et d'une licence commerciale limitée. Si vous n'êtes pas sûr d'être admissible à la licence CE, commencez par l'essai gratuit ou consultez la FAQ sur la licence Community Edition.<br />
<br />
Une fois que vous êtes devenu trop grand pour Community Edition, passez à une licence perpétuelle avec une licence commerciale sans restriction et choisissez entre les éditions Professional, Enterprise et Architect de Delphi, C++Builder et RAD Studio.<br />
<br />
Notez que l'édition communautaire ne doit pas être utilisée comme essai prolongé, car les licences sont différentes. De plus, CE ne doit pas être utilisé par des entreprises disposant d’autres licences régulières.<br />
<br />
<b>Télécharger maintenant!</b><br />
<br />
Téléchargez Delphi Community Edition ou C++Builder Community Edition et rejoignez une communauté dynamique de développeurs. Que vous soyez un développeur chevronné ou débutant, ces éditions communautaires fournissent les outils dont vous avez besoin pour donner vie à vos idées*:<br />
<br />
   <a href="https://www.embarcadero.com/products/delphi/starter" target="_blank">Télécharger Delphi 12 CE</a><br />
   <a href="https://www.embarcadero.com/products/cbuilder/starter" target="_blank"> Télécharger C++Builder 12 CE</a></div>
			
		</div>
	</div>
</div></blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10623/sortie-editions-communautaires-delphi-12-cppbuilder-12/</guid>
		</item>
		<item>
			<title>Le composant TFDQBE de la version Delphi 12 (Athènes)</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10557/composant-tfdqbe-version-delphi-12-athenes/</link>
			<pubDate>Fri, 22 Dec 2023 13:45:39 GMT</pubDate>
			<description><![CDATA[La requête par l'exemple...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">La requête par l'exemple (QBE), à l'origine fournie avec BDE est encore actuelle même si obsolète.<br />
<br />
Ci-dessous l'utilisation du programme dbd32.exe qui était fourni avec BDE sous d'anciennes versions.<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=648206&amp;d=1703231798" border="0" alt="Nom : Capture.PNG
Affichages : 8405
Taille : 169,9 Ko"  style="float: CONFIG" /><br />
<br />
Firedac qui, sur certains aspects, est proche des composants BDE, remet cette possibilité intéressante en selle grâce au nouveau composant FDQBE.<br />
<br />
Ci-dessous mon programme d'essais  <br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=648207&amp;d=1703231907" border="0" alt="Nom : Capture_1.PNG
Affichages : 4618
Taille : 37,0 Ko"  style="float: CONFIG" /><br />
<br />
En pièce jointe, au bas du billet, vous trouverez les sources de la version FMX. <br />
<br />
Reste à parler de la syntaxe utilisée par le composant, j'ai essayé d'en faire une synthèse, déduite de l'unité du composant et de mes essais.<br />
  <br />
<b><u>Terme</u></b><br />
Un terme permet d'indiquer la ou les valeurs recherchées pour une colonne ainsi que les conditions à appliquer.<br />
<u><i>Syntaxe d'un terme<br />
</i></u><div class="cms_table"><table width="400" class="cms_table_grid"><tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"></td>
<td class="cms_table_grid_td"><div style="text-align: center;">NOT</div></td>
<td class="cms_table_grid_td"><div style="text-align: center;">OR</div></td>
<td class="cms_table_grid_td"><div style="text-align: center;">AND</div></td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td">Terme0</td>
<td class="cms_table_grid_td">'<b>!</b>' Terme0</td>
<td class="cms_table_grid_td">Terme0 '<b>|</b>' Terme0</td>
<td class="cms_table_grid_td">Terme0 '<b>&amp;</b>' Terme0</td>
</tr>
</table></div>
                                     <br />
Terme0 = valeur | EQ valeur | direct | macro | masque | valeur '~' valeur | '(' valeur ')'<br />
valeur = nombre | chaine de caractères<br />
EQ = '<b>=</b>' | '<b>&gt;</b>' | '<b>&lt;</b>' | '<b>&gt;=</b>' | '<b>&lt;=</b>' | '<b>&lt;&gt;</b>'<br />
masque = chaine de caractères pouvant contenir les charactères de substitution '<b>%</b>' ou '<b>_</b>'<br />
direct = '[' instruction ']'    *si <b>[qoNoDirect]</b> est exclu des Options <br />
macro = '@' nom  <i>*nom = nom de la macro</i><br />
Tri = '<b>#</b>' ('<b>+</b>'|'<b>-</b>') numéro  *<i>numéro = ordre de tri</i><br />
<br />
<br />
Un terme commencera, la plupart du temps, par un comparateur '<b>=</b>','<b>&gt;</b>','<b>&lt;</b>','<b>&gt;=</b>','<b>&lt;=</b>' ou '<b>&lt;&gt;</b>' ou par une négation '<b>!</b>', généralement suivi d'une valeur.<br />
Exemples : <br />
Le terme <b>=1</b> (le signe '=' est optionnel, le terme 1 est équivalent à =1) sera interprété en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(A.nomcolonne = 1)</span>.<br />
<b>&lt;&gt;1</b> peut s'écrire<b> !1</b>. Ces deux termes seront interprétés de la même manière par <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(NOT A.nomcolonne = 1)</span>.<br />
<br />
Il est possible de combiner plusieurs termes pour une même colonne par les opérateurs ('<b>&amp;</b>' pour AND et '<b>|</b>' pour OR).<br />
Exemples : <br />
Le terme <b>1&amp;&gt;4</b> sera interprété en  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(A.nomcolonne = 1 AND A.nomcolonne &gt; 4)</span>.<br />
Le terme <b>1|4</b>  sera interprété en  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(A.nomcolonne = 1 OR  A.nomcolonne = 4)</span>.<br />
<br />
Cas particuliers :<br />
<br />
<b>NULL</b> <br />
Pour obtenir une comparaison sur une valeur indéterminée (NULL) d'un champ annulable (pouvant avoir une absence de valeur), le terme ne contiendra que l'opérande '<b>=</b>','<b>!=</b>' ou '<b>&lt;&gt;</b>' permettant ainsi d'obtenir IS NULL dans le premier cas ou IS NOT NULL pour les deux autres<br />
<br />
<b>Intervalle de valeurs </b><br />
Il est possible d'utiliser l'opérateur '~' pour obtenir un intervalle de valeurs <br />
Exemple : <br />
Le terme <b>1~5</b> sera interprété en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(A.nomcolonne BETWEEN 1 AND 6)</span>.<br />
<br />
Colonnes Chaîne de caractères<br />
<br />
Par défaut, une valeur contenant une chaîne de caractères sera interprétée comme une recherche partielle. <br />
<br />
Une recherche partielle utilisera les caractères de substitution '<b>_</b>' ou '<b>%</b>' pour remplacer, respectivement, un ou plusieurs caractères.<br />
Par défaut, cette recherche ne sera pas sensible à la casse. <br />
Exemples : <br />
Le terme <b>%o% </b>recherchera toutes les valeurs (chaine de caractères) contenant '<b>o</b>', interpété par  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">({fn UCASE(A.nomcolonne)} LIKE '%O%')</span>.<br />
Le terme <b>Co%</b> recherchera toutes les valeurs (chaine de caractères) commençant par '<b>Co</b>', interpété par  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">({fn UCASE(A.nomcolonne)} LIKE 'CO%')</span>.<br />
Le terme <b>_o%</b> recherchera toutes les valeurs (chaine de caractères) dont la seconde lettre est '<b>o</b>' ou  '<b>O</b>' , interpété par  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">({fn UCASE(A.nomcolonne)} LIKE '_O%')</span>. <br />
<br />
:question: Quid de cette expression <b>{fn UCASE(A.CategoryName)}</b> ? Ici, vous voyez en œuvre une des fonctionnalités de Firedac, le prétraitement de commandes. <br />
Plus d'informations sur le prétraitement de Firedac <a href="https://docwiki.embarcadero.com/RADStudio/Alexandria/fr/Pr%C3%A9traitement_du_texte_des_commandes_(FireDAC)" target="_blank">ici</a><br />
<br />
Il est possible de changer ce comportement en modifiant la propriété Options du composant FDQBE en retirant [qoPartial].<br />
Exemples :<br />
[qoPartial] inclus dans Options<br />
Le terme <b>Boissons</b> sera interprété en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span><span class="br0">&#123;</span>fn UCASE<span class="br0">&#40;</span>A.nomcolonne<span class="br0">&#41;</span><span class="br0">&#125;</span> <span style="color: #0000ff;">LIKE</span> <span style="color: #FF0000;">'%BOISSONS%'</span><span class="br0">&#41;</span></span>.<br />
Un moyen d'éviter le <b>LIKE</b> sans passer par la modification de la propriété Options est d'écrire le terme ainsi (Boissons) pour obtenir <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#123;</span>fn UCASE<span class="br0">&#40;</span>A.CategoryName<span class="br0">&#41;</span><span class="br0">&#125;</span> = <span style="color: #FF0000;">'BOISSONS'</span><span class="br0">&#41;</span></span>.  <br />
[qoPartial] non inclus <br />
Le terme <b>Boissons</b> sera interprété en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span><span class="br0">&#123;</span>fn UCASE<span class="br0">&#40;</span>A.nomcolonne<span class="br0">&#41;</span><span class="br0">&#125;</span> = <span style="color: #FF0000;">'BOISSONS'</span><span class="br0">&#41;</span></span> à l'identique du terme <b>(Boissons)</b>.<br />
 <br />
De même que pour la sensibilité à la casse, le comportement peut en être modifié en retirant la valeur <b>[qoNocase]</b> de la propriété Options.<br />
Ainsi :<br />
<ul><li style="">Le même terme <b>Boissons</b> ne fera plus d'appel à la fonction UCASE <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span>A.nomcolonne <span style="color: #0000ff;">LIKE</span> <span style="color: #FF0000;">'%Boissons%'</span><span class="br0">&#41;</span></span>.</li><li style="">Le terme <b>(Boissons)</b> étant interprété en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span>A.nomcolonne=<span style="color: #FF0000;">'Boissons'</span><span class="br0">&#41;</span></span>.  </li></ul><br />
<br />
Colonnes de type numériques<br />
le point décimal (si besoin) doit être utilisé dans le terme.<br />
Exemple : <b>&lt;=19.75</b> sera interprété ainsi <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span>A.ColonneNumerique &lt;= <span style="color: #cc66cc;">19.75</span><span class="br0">&#41;</span></span>.    <br />
		  <br />
<b>Tri </b><br />
Un tri peut être indiqué pour une colonne, soit seul, soit à la fin d'un terme ou d'une combinaison de terme.<br />
Un tri s'exprime en ajoutant un '#' suivi du type '+' (optionnel) pour ASCendant ou '-' DESCendant et obligatoirement d'un numéro d'ordre.<br />
Exemples : <br />
Le terme <b>#1</b>  sera interprété par la clause <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">ORDER</span> <span style="color: #0000ff;">BY</span> A.nomcolonne</span>.<br />
Le terme <b>#-1</b> sera interprété par la clause <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">ORDER</span> <span style="color: #0000ff;">BY</span> A.nomcolonne <span style="color: #0000ff;">DESC</span></span>.<br />
Dans ce tableau<br />
<div class="cms_table"><table width="100" class="cms_table_grid"><tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td">Colonne1</td>
<td class="cms_table_grid_td">Colonne2</td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td">#-2</td>
<td class="cms_table_grid_td">#1</td>
</tr>
</table></div>
<b>[#-2][#1]</b> sera interprété par la clause <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">ORDER</span> <span style="color: #0000ff;">BY</span> A.Colonne2,A.Colonne1 <span style="color: #0000ff;">DESC</span></span>. <br />
Vous comprendrez donc qu'il est important de bien indiquer un numéro d'ordre unique pour chaque colonne.<br />
<br />
<b>Utilisation de fonctions</b><br />
Une dernière possibilité s'offre à nous. Lors de mon paragraphe sur les recherches partielles, nous avons vu une utilisation du prétraitement des commandes.<br />
Pour peu que, dans la propriété Options du composant FDQBE, la directive <b>[qoNoDirect]</b> ne soit pas incluse, nous pourrons utiliser cette fonctionnalité.<br />
Le terme devra alors être entre crochets <b>[ ]</b> <br />
Exemple : Le terme <b>[{year(colonnedate)} = 1997]</b> permettra une sélection sur la partie année d'une date et sera interprété ainsi <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">(year(colonnedate)=1996)</span>.<br />
<br />
Cette nouvelle syntaxe augmente considérablement les possibilités (même si toutes les fonctions ne sont peut-être pas valides).<br />
<div class="cms_table"><table width="600" class="cms_table_grid"><tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><b>Rubrique</b></td>
<td class="cms_table_grid_td"><b>Description</b></td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><a href="https://docwiki.embarcadero.com/RADStudio/Athens/fr/Fonctions_macro_caract%C3%A8res_(FireDAC)" target="_blank">Fonctions macro caractères</a></td>
<td class="cms_table_grid_td">Liste des fonctions utilisant des chaînes de caractères.</td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><a href="https://docwiki.embarcadero.com/RADStudio/Athens/fr/Fonctions_macro_num%C3%A9riques_(FireDAC)" target="_blank">Fonctions macro numériques</a></td>
<td class="cms_table_grid_td">Liste des fonctions utilisant des nombres.</td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><a href="https://docwiki.embarcadero.com/RADStudio/Athens/fr/Fonctions_macro_date_et_heure_(FireDAC)" target="_blank">Fonctions macro date et heure</a></td>
<td class="cms_table_grid_td">Liste des fonctions utilisant la date et l'heure.</td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><a href="https://docwiki.embarcadero.com/RADStudio/Athens/fr/Fonctions_macro_syst%C3%A8me_(FireDAC)" target="_blank">Fonctions macro système</a></td>
<td class="cms_table_grid_td">Liste des fonctions externes.</td>
</tr>
<tr valign="top" class="cms_table_grid_tr"><td class="cms_table_grid_td"><a href="https://docwiki.embarcadero.com/RADStudio/Athens/fr/Fonction_macro_CONVERT_(FireDAC)" target="_blank">Fonction macro CONVERT</a></td>
<td class="cms_table_grid_td">Décrit la fonction CONVERT.</td>
</tr>
</table></div>
<br />
J'ai retrouvé dans mes archives MKQueryBuilder (D3-D6) que vous pouvez retrouver <a href="https://torry.net/db-aware-components/packs/other/mk-query-builder#downloads" target="_blank">ici</a><br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=648222&amp;d=1703252362" border="0" alt="Nom : Capture.PNG
Affichages : 1190
Taille : 30,2 Ko"  style="float: CONFIG" /> <br />
<br />
Voilà le challenge posé, reste à savoir comment ce nouveau composant pourrait y répondre au sein d'une application proposant ce design.</blockquote>


<!-- attachments -->
	<div class="blogattachments">
		
		
		
		
			<fieldset class="blogcontent">
				<legend>Fichiers attachés</legend>
				<ul>
					
				</ul>
			</fieldset>
		

	</div>
<!-- / attachments -->
]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10557/composant-tfdqbe-version-delphi-12-athenes/</guid>
		</item>
		<item>
			<title>TControlList et sélection multiple</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10545/tcontrollist-selection-multiple/</link>
			<pubDate>Sat, 11 Nov 2023 10:03:06 GMT</pubDate>
			<description>La version Delphi 11 a...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">La version Delphi 11 a apporté la possibilité de faire une multiple sélection d'éléments avec les classiques manipulations de clavier (Ctrl+Click, Ctrl+Shift+Click). Si je n'avais rien publié à ce sujet, c'est parce que l'obtention des éléments sélectionnés me paraissait boguée (ce qui a d'ailleurs fait l'objet d'une demande sur le portail qualité <a href="https://quality.embarcadero.com/browse/RSP-40821" target="_blank">RSP-40821</a>). En effet, lorsque l'on tentait d'obtenir la liste des éléments sélectionnés, souvent le dernier élément était omis.    <br />
<br />
L'objectif de ce billet est de vous montrer le symptôme et surtout de proposer une solution. <br />
<br />
Le design du programme est simple : <br />
<ul><li style="">Un<b> TControList</b>, l'élément contiendra un <b>TLabel</b> pour afficher une valeur</li><li style="">Un <b>TMemo.</b></li><li style="">Un <b>TButton</b>.</li><li style="">Et, pour ce qui est des données, un <b>TProtypeBindSource</b> pour obtenir une liste de contact.</li></ul><br />
Comme déjà montré dans mes billets sur ce composant, il faudra utiliser LiveBinding pour lier la liste à la source de données et au libellé (<b><i>Label1</i></b>)<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=646417&amp;d=1699693888" border="0" alt="Nom : Capture_listD.PNG
Affichages : 10410
Taille : 26,5 Ko"  style="float: CONFIG" /><br />
<br />
Cette fonctionnalité de multiple sélection doit être activée par code <br />
<br />
Pour les besoins de mon test, je le fais dès la création de la forme.<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:84px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormTest.FormCreate(Sender: TObject);
begin
ControlList1.MultiSelect:=True;
end;</pre></td></tr></table></pre>
</div>:!: La version 12 propose une propriété <b><i>mutiselect</i></b> accessible au design. <br />
<br />
Pour obtenir la liste des éléments sélectionnés, il faut parcourir l'ensemble des éléments et tester si oui ou non, il l'est.  <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:180px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td valign="top"><pre style="margin: 0">
procedure TFormTest.btnListeSelectionClick(Sender: TObject);
begin
Memo1.Lines.Clear; // efface l'ancien résultat
for var i:= 0 to ControlList1.ItemCount-1 do   // parcourir l'ensemble des élémnts
  if ControlList1.Selected[i] then                    // élément sélectionné ?
   begin
        ControlList1.ItemIndex:=i;                   // se positionner dessus pour accéder à label1 
        Memo1.Lines.Add(i.ToString+ ' - '
                                   +label1.caption); 
    end;
end;</pre></td></tr></table></pre>
</div>À l'exécution, la sélection fonctionne <br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=646420&amp;d=1699695500" border="0" alt="Nom : Capture_List1.PNG
Affichages : 4102
Taille : 14,5 Ko"  style="float: CONFIG" /> <br />
mais le résultat déçoit <br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=646421&amp;d=1699695547" border="0" alt="Nom : Capture_List2.PNG
Affichages : 4047
Taille : 17,0 Ko"  style="float: CONFIG" /><br />
Christine Jones, dernier nom sélectionné, n'est pas listé dans le mémo et n'apparait plus comme tel dans la <b>TControlList</b> :weird:<br />
La faute en est très certainement au repositionnement pour accéder à label1.<br />
<br />
P.S. Cet effet sera beaucoup plus visible si vous jouez avec les <b><i>ItemSelectionOptions</i></b> permettant de modifier couleurs et transparences  <br />
 <b><i><ul><li style="">   HotColor</li><li style="">    SelectedColor</li><li style="">    FocusedColor</li><li style="">    HotColorAlpha</li><li style="">    SelectedColorAlpha</li><li style="">    FocusedColorAlpha</li></ul><br />
</i></b><br />
et même la couleur de fonte selon l'état  <br />
<b><i><ul><li style="">    HotFontColor</li><li style="">    SelectedFontColor</li><li style="">    FocusedFontColor</li><li style="">    UseFontColorForLabels</li></ul><br />
</i></b> <br />
<br />
Maintenant, voici comment contourner ce problème<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormTest.btnListeSelectionClick(Sender: TObject);
var lastSelected : integer;
begin
Memo1.Lines.Clear;
// mémorise la position
LastSelected:=ControlList1.ItemIndex;
// au cas où l'élément ne ferait pas partie de la sélection
// ne devrait pas arriver
if not ControlList1.Selected[LastSelected] then LastSelected:=-1;
for var i:= 0 to ControlList1.ItemCount-1 do
  if ControlList1.Selected[i] OR (i=lastSelected)
  then
   begin
        ControlList1.ItemIndex:=i;
        Memo1.Lines.Add(i.ToString+
                        ' - '+label1.caption);
end;
// Se repositionner sur le dernier élément sélectionné
ControlList1.ItemIndex:=LastSelected;
// redessiner la liste
ControlList1.Invalidate;
end;</pre></td></tr></table></pre>
</div><img src="https://www.developpez.net/forums/attachment.php?attachmentid=646422&amp;d=1699696164" border="0" alt="Nom : Capture_list3.PNG
Affichages : 4046
Taille : 16,5 Ko"  style="float: CONFIG" /></blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10545/tcontrollist-selection-multiple/</guid>
		</item>
		<item>
			<title>Obtention du Statut de MVP Embarcadero</title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10543/obtention-statut-mvp-embarcadero/</link>
			<pubDate>Sat, 28 Oct 2023 09:03:40 GMT</pubDate>
			<description><![CDATA[C'est désormais officiel, je...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">C'est désormais officiel, je suis entré dans le club des MVPs.<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=645850&amp;d=1698483804" border="0" alt="Nom : mvp_logo_small.png
Affichages : 2599
Taille : 81,4 Ko"  style="float: CONFIG" /><br />
<br />
Je prévois un temps d'adaptation à ce nouveau titre, temps qui matchera avec mon changement de statut de professionnel vers celui de retraité</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10543/obtention-statut-mvp-embarcadero/</guid>
		</item>
		<item>
			<title><![CDATA[[FMX] Boutons et glyphe : Astuces]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10378/fmx-boutons-glyphe-astuces/</link>
			<pubDate>Wed, 07 Sep 2022 15:40:10 GMT</pubDate>
			<description>En avançant sur le sujet des...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">En avançant sur le sujet des composants prenant en compte le format SVG, je suis  en train d'établir les différences entre le <b><i>TPath</i></b> et les composants tiers <a href="https://github.com/skia4delphi/skia4delphi" target="_blank">Skia4Delpi</a> et <a href="https://github.com/EtheaDev/SVGIconImageList" target="_blank">SVGIconImageList</a>.<br />
<br />
Au cours de mes essais, je me suis aperçu que le composant <b><i>SVGIconImageList</i></b> pouvait être utilisé comme liste d'images à associer à un <b><i>TSpeedButton</i></b> ou <b><i>TButton</i></b>. Intéressant, mais l'icône est vraiment petite et donc, visuellement inefficace. <br />
<br />
La première idée qui m'est venue à l'esprit : créer un style personnalisé. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=625183&amp;d=1662789757" border="0" alt="Nom : Capture.PNG
Affichages : 553
Taille : 16,6 Ko"  style="float: CONFIG" /><br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=624977&amp;d=1662536305" border="0" alt="Nom : Capture.PNG
Affichages : 5342
Taille : 29,9 Ko"  style="float: CONFIG" /><br />
<br />
Avantage : la visibilité au niveau du design. Plus inattendu, car j'avais créé le style à partir d'un <b><i>stylelookup</i></b> prédéfini, le glyphe s'il existe dans la liste écrase l'icône prédéfinie. Toutefois, si l'index de l'image est hors limites, l'icône prédéfinie reste visible. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=624978&amp;d=1662536752" border="0" alt="Nom : Capture_1.PNG
Affichages : 857
Taille : 1,6 Ko"  style="float: CONFIG" /><br />
<br />
Inconvénient : la création nécessaire du <b><i>TStyleBook</i></b> sur la forme. Une parade à cet inconvénient quand on a plusieurs formes dans l'application : mettre ce style personnalisé dans un module de données (<b><i>TDataModule</i></b>) mais l'on y perd souvent la visualisation au moment du design (en particulier si le DataModule n'est pas ouvert dans l'IDE).<br />
<br />
Du coup, d'autres solutions ont commencé à germer. <br />
<br />
J'ai d'abord tenté l'approche de l'évènement<b><i> OnStyleLookup</i></b> du composant<br />
    <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm31.SpeedButton2ApplyStyleLookup(Sender: TObject);
var Align : TValue;   // méthode styledata
    aGlyph : TGlyph;
    aText : TText;
begin
//<b><u> méthode styledata</u></b>. utiliser StyleData a été classée comme obsolète dans certaines versions
//TValue.Make(Ord(TAlignLayout.Client),TypeInfo(TAlignLayout),Align);
//TSpeedButton(Sender).StylesData['glyphstyle.align']:=Align;
//TSpeedButton(Sender).StylesData['text.visible']:=False;

// <b><u>méthode findStyleResource</u></b>
(Sender as TSpeedButton).FindStyleResource&lt;TGlyph&gt;('glyphstyle',aGlyph);
if assigned(aglyph) then aGlyph.Align:=TalignLayout.Contents;
(Sender as TSpeedButton).FindStyleResource&lt;TText&gt;('text',aText);
if assigned(aText) then aText.Visible:=False;
end;</pre></td></tr></table></pre>
</div>Puis j'ai osé modifier directement le style en cours au sein d'un module de données (une première pour moi).<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td valign="top"><pre style="margin: 0">{$R *.dfm}
uses FMX.Styles, FMX.StdCtrls, FMX.Objects, FMX.ImgList;

procedure TDataModule.DataModuleCreate(Sender: TObject);
var  sb,obj: TFmxObject;
     aGlyph : TGlyph;
     aText : TText;
begin
  sb:=TStyleManager.ActiveStyle(nil);
  if assigned(sb) then begin
    obj:=sb.FindStyleResource('icondpeedbutton');
    if not assigned(obj) then
      begin
        obj:=sb.FindStyleResource('toolbutton',<b>true</b>); // duplication d'un style prédéfini. Utilisez un style avec glyphe pour obtenir une icône par défaut  
        if Assigned(obj) then
           begin
            aGlyph:= obj.FindStyleResource('glyphstyle') as TGlyph;
            aGlyph.Align:=TalignLayout.Client;
            aText:= obj.FindStyleResource('text') as TText;
            aText.Visible:=false;
            obj.StyleName:='icondpeedbutton';
            sb.AddObject(obj);
           end;
      end;
  end;
end;</pre></td></tr></table></pre>
</div>Voici en image le résultat, comparant les différentes approches et le rendu au moment du design <br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=624979&amp;d=1662537470" border="0" alt="Nom : Capture_2.PNG
Affichages : 241
Taille : 53,8 Ko"  style="float: CONFIG" /><br />
<br />
Pour l'instant mes tests n'ont été réalisés que sur Windows et quelques styles fournis. <br />
Dans un prochain billet, j'espère bien pousser plus loin. <br />
Dans ma liste des choses à tenter : <br />
<ul><li style="">Mixer glyphe et texte à la manière de boutons Office;</li><li style="">Jouer avec deux styles. </li></ul><br />
:fleche: N'hésitez pas à me proposer d'autres essais.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10378/fmx-boutons-glyphe-astuces/</guid>
		</item>
		<item>
			<title><![CDATA[[Tutoriel] FMX : Créer un composant observable  (épisode 2)]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10360/tutoriel-fmx-creer-composant-observable-episode-2/</link>
			<pubDate>Sat, 06 Aug 2022 08:35:42 GMT</pubDate>
			<description>Enfin terminé  
*LiveBindings...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Enfin terminé <br />
<b><div style="text-align: center;"><font size="4"><a href="https://serge-girard.developpez.com/tutoriels/Delphi/Livebindings/Episode4-II/" target="_blank"><font color="#0000FF">LiveBindings de A à … Écrire un composant observable II</font></a></font></div></b><br />
<br />
Lors du tutoriel précédent <a href="https://serge-girard.developpez.com/tutoriels/Delphi/Livebindings/Composant_A/" target="_blank">(LiveBindings de A à … Écrire un composant observable</a>),  je m’étais arrêté à une liaison unidirectionnelle ou, du moins, était-ce mon objectif.<br />
Cette fois, je reprends l’ouvrage avec un objectif plus simple : une simple diode qui sera déclinée par la suite, mais surtout uniquement pour la plateforme FMX.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=623398&amp;d=1659774918" border="0" alt="Nom : diode_test_1a.PNG
Affichages : 2098
Taille : 70,5 Ko"  style="float: CONFIG" /></div><br />
Dans le prochain (et dernier de la série ?), je m'attaquerai à l'équivalent d'un TDBRadioGroupBox</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10360/tutoriel-fmx-creer-composant-observable-episode-2/</guid>
		</item>
		<item>
			<title><![CDATA[[FMX] Grilles et couleurs]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10357/fmx-grilles-couleurs/</link>
			<pubDate>Mon, 01 Aug 2022 07:46:26 GMT</pubDate>
			<description>Trois évènements sont...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Trois évènements sont proposés pour dessiner au sein d'une grille, et l'ordre d'exécution en est important. <br />
<br />
Il m'a fallu, dans un premier temps, à comprendre pourquoi l'évènement <b><i>onDrawColumnBackground</i></b> ne se déclenchait pas dans mes programmes. Première ambiguïté, le nom de l'évènement fait croire que l'on va travailler sur la colonne entière, la <a href="https://docwiki.embarcadero.com/Libraries/Sydney/fr/FMX.Grid.TGrid.OnDrawColumnBackground" target="_blank">documentation</a>, indique bien qu'il s'agira de la zone d'une cellule, par contre, ce qui n'est pas indiqué, c'est que l'option <b><i>AlternatingRowBackground</i></b> doit être activée pour que l'événement soit levé.<br />
<br />
Un simple programme <br />
<ul><li style="">   Une grille contenant une seule colonne et une seule ligne&#8239;;</li><li style="">   Un mémo pour récupérer des informations&#8239;;</li><li style="">   Et le codage des 3 évènements.</li></ul><br />
m'a permis de trouver la hiérarchie de ceux-ci. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=623064&amp;d=1659082861" border="0" alt="Nom : Capture_1.PNG
Affichages : 160
Taille : 44,0 Ko"  style="float: CONFIG" /><br />
<br />
J'aurais pu en rester là, mais rien ne vaut une petite démo et de fil en aiguille, je me suis un peu pris au jeu. <br />
Voici ce que donne une grille simple avec l'option <b><i>AlternatingRowBackground</i></b> active, dans ce cas, c'est le style qui fourni les couleurs de fond. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=623176&amp;d=1659338710" border="0" alt="Nom : Capture_1.PNG
Affichages : 149
Taille : 3,6 Ko"  style="float: CONFIG" /><br />
<br />
Il serait bien évidemment possible de modifier le style (au design ou au runtime) pour changer les deux couleurs mais, cela changerait toutes les grilles de la forme.<br />
Coder l'évènement  <b><i>onDrawColumnBackground</i></b> est plus simple.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm1.DrawStripesBackground(Sender: TObject;
  const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF;
  const Row: Integer; const Value: TValue; const State: TGridDrawStates);
var aBrush : TBrush; // 
begin
aBrush:=TBrush.Create(TBrushKind.Solid,TAlphaColors.Null);
try
if  odd(row)
    then aBrush.Color:=TAlphaColors.white
    else aBrush.Color:=TAlphaColors.red;
Canvas.FillRect(Bounds,1,aBrush);
finally
  aBrush.Free;
end;
end;</pre></td></tr></table></pre>
</div><img src="https://www.developpez.net/forums/attachment.php?attachmentid=623169&amp;d=1659335813" border="0" alt="Nom : Capture_2.PNG
Affichages : 141
Taille : 3,7 Ko"  style="float: CONFIG" /><br />
<br />
Cela ne vous rappelle pas quelque chose ? Oui, c'est à dessein que j'ai utilisé l'alternance de blanc et rouge et cela va montrer l'utilisation de <b><i>OnDrawColumnCell</i></b>.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br /></div></td><td valign="top"><pre style="margin: 0">
procedure TForm3.btnUSAClick(Sender: TObject);
var
  I: Integer;
const  oddstars ='* * * * * *';
       evenstars=' * * * * * *';
begin
StringGrid1.OnDrawColumnBackground:=DrawStripesBackground;
StringGrid1.OnDrawColumnCell:=DrawStarsColumnCell;
Stringgrid1.ClearColumns;
StringGrid1.RowCount:=13;
StringGrid1.RowHeight:=20;
with TColumn.Create(StringGrid1) do  parent:=StringGrid1;
with TColumn.Create(StringGrid1) do  parent:=StringGrid1;
with TColumn.Create(StringGrid1) do  parent:=StringGrid1;
for I := 0 to 7 do
begin
 if odd(i) then StringGrid1.Cells[0,i]:=oddstars
           else StringGrid1.Cells[0,i]:=evenstars;
end;
end;

procedure TForm1.testDrawStarsColumnCell(Sender: TObject; const Canvas: TCanvas;
  const Column: TColumn; const Bounds: TRectF; const Row: Integer;
  const Value: TValue; const State: TGridDrawStates);
var aTextLayout : TTextLayout;
      aRectF : TrectF;
      aBrush : TBrush;
begin
if Value.IsEmpty then exit;

aBrush:=TBrush.Create(TBrushKind.Solid,TAlphaColors.Null);
try
 if (column.Index=0) AND (row&lt;=7) then aBrush.Color:=TAlphaColors.Midnightblue;
 aRectF:=Bounds;
 aRectf.Inflate(3,3); // agrandir le rectangle
 Canvas.FillRect(aRectF,1,aBrush);

 // utilisation d'un TextLayout plutôt qu'un simple Canvas.Drawtext
 // permet de changer la couleur, la taille de la fonte, l'alignement etc... 
 ATextLayout:=TTextLayoutManager.TextLayoutByCanvas(Canvas.ClassType).Create(Canvas);
 ATextLayout.BeginUpdate;
 ATextLayout.Text:=Value.ToString;
 ATextLayout.Color:=Talphacolors.Antiquewhite;
 ATextLayout.TopLeft:=Bounds.TopLeft;
 ATextLayout.MaxSize := PointF(ArectF.Width, aRectf.Height);
 ATextLayout.Font.Size:=20;
 ATextLayout.VerticalAlign:=TTextAlign.Center;
 ATextLayout.HorizontalAlign:=TTextAlign.Center;
 ATextLayout.EndUpdate;
 ATextLayout.RenderLayout(Canvas);
finally
 ATextLayout.Free;
 aBrush.Free;
end; 
end;</pre></td></tr></table></pre>
</div><img src="https://www.developpez.net/forums/attachment.php?attachmentid=623174&amp;d=1659336705" border="0" alt="Nom : Capture_3.PNG
Affichages : 184
Taille : 6,6 Ko"  style="float: CONFIG" /><br />
<br />
Ce que j'ai découvert, à ce stade, c'est que la taille des rectangles (<b><i>Bounds</i></b>) est différente entre les deux évènements, d'où la nécessité d'agrandir le rectangle ligne 35 du code.<br />
NB. j'ai caché les entêtes, option<b><i> Header</i></b> ôtée, mais gardé les options  <b><i>ColLines</i></b> et <b><i>RowLines</i></b> pour bien montrer qu'il s'agit d'une grille.<br />
<br />
J'aurais pu m'arrêter là mais, poussé par la curiosité, je me suis lancé dans la construction d'un échiquier <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=623175&amp;d=1659337702" border="0" alt="Nom : Capture_4.PNG
Affichages : 180
Taille : 21,7 Ko"  style="float: CONFIG" /><br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm1.btnPionsClick(Sender: TObject);
var
  I: Integer;
  c : string;  // couleur du pion
begin
if Tbutton(Sender).Tag=0 then c:='b' else c:='w';  // choix blancs ou noirs

StringGrid1.OnDrawColumnBackground:=StringGrid1DrawChessBackground;
StringGrid1.OnDrawColumnCell:=StringGrid1DrawPawnColumnCell;

Stringgrid1.ClearColumns;
StringGrid1.RowCount:=8;
StringGrid1.RowHeight:=40;
stringGrid1.Height:=347;
stringGrid1.width:=347;

for I := 1 to 8 do
  begin
    with TColumn.Create(StringGrid1) do
     begin
       parent:=StringGrid1;
       width:=40;
     end;
  end;
for I := 0 to 7 do
   StringGrid1.Cells[i,1]:='P'+c;
StringGrid1.Cells[0,0]:='T'+c;
StringGrid1.Cells[7,0]:='T'+c;
StringGrid1.Cells[1,0]:='C'+c;
StringGrid1.Cells[6,0]:='C'+c;
StringGrid1.Cells[2,0]:='B'+c;
StringGrid1.Cells[5,0]:='B'+c;
StringGrid1.Cells[3,0]:='Q'+c;
StringGrid1.Cells[4,0]:='K'+c;
if c='w' then c:='b' else c:='w';
for I := 0 to 7 do
   StringGrid1.Cells[i,6]:='P'+c;
StringGrid1.Cells[0,7]:='T'+c;
StringGrid1.Cells[7,7]:='T'+c;
StringGrid1.Cells[1,7]:='C'+c;
StringGrid1.Cells[6,7]:='C'+c;
StringGrid1.Cells[2,7]:='B'+c;
StringGrid1.Cells[5,7]:='B'+c;
StringGrid1.Cells[3,7]:='Q'+c;
StringGrid1.Cells[4,7]:='K'+c;
end;

procedure TForm1.StringGrid1DrawChessBackground(Sender: TObject;
  const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF;
  const Row: Integer; const Value: TValue; const State: TGridDrawStates);
var aBrush : TBrush;
begin
aBrush:=TBrush.Create(TBrushKind.Solid,TAlphaColors.Null);
 try
   if (odd(column.Index) AND odd(row)) OR NOT(odd(column.Index) OR odd(row))
     then aBrush.Color:=TAlphaColors.Ivory
     else aBrush.Color:=TAlphaColors.Chocolate;
   Canvas.FillRect(Bounds,1,aBrush);
 finally
  aBrush.Free;
 end;
end;</pre></td></tr></table></pre>
</div>Le challenge pour ce dernier était plus le dessin des pièces <br />
 <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm3.StringGrid1DrawColumnCell(Sender: TObject;
  const Canvas: TCanvas; const Column: TColumn; const Bounds: TRectF;
  const Row: Integer; const Value: TValue; const State: TGridDrawStates);
const bishop='M19,22H5V20H19V22M17.16,8.26C18.22,9.63 18.86,11.28 19,13C19,15.76 15.87,18 12,18'+
             'C8.13,18 5,15.76 5,13C5,10.62 7.33,6.39 10.46,5.27C10.16,4.91 10,4.46 10,4A2,2 0 0,1'+
             ' 12,2A2,2 0 0,1 14,4C14,4.46 13.84,4.91 13.54,5.27C14.4,5.6 15.18,6.1 15.84,6.74L11.29,11.29L12.71,12.71L17.16,8.26Z';
      king='M19,22H5V20H19V22M17,10C15.58,10 14.26,10.77 13.55,12H13V7H16V5H13V2H11V5H8V7H11V12H10.45C9.35,10.09 6.9,9.43 5,10.54C3.07,11.64 2.42,14.09 3.5,16C4.24,17.24 5.57,18 7,18H17A4,4 0 0,0 21,14A4,4 0 0,0 17,10Z';
      cavalier='M19,22H5V20H19V22M13,2V2C11.75,2 10.58,2.62 9.89,3.66L7,8L9,10L11.06,8.63C11.5,8.32 '+
               '12.14,8.44 12.45,8.9C12.47,8.93 12.5,8.96 12.5,9V9C12.8,9.59 12.69,10.3 12.22,10.77L7.42,15.57C6.87,16.13 6.87,17.03 7.43,17.58C7.69,17.84 8.05,18 8.42,18H17V6A4,4 0 0,0 13,2Z';
      pion='M19 22H5V20H19V22M16 18H8L10.18 10H8V8H10.72L10.79 7.74C10.1 7.44 9.55 6.89 9.25 6.2C8.58 4.68 9.27 2.91 10.79 2.25C12.31 1.58 14.08 2.27 14.74 3.79C15.41 5.31 14.72 7.07 13.2 7.74L13.27 8H16V10H13.82L16 18Z';
      queen='M18,3A2,2 0 0,1 20,5C20,5.81 19.5,6.5 18.83,6.82L17,13.15V18H7V13.15L5.17,6.82'+
            'C4.5,6.5 4,5.81 4,5A2,2 0 0,1 6,3A2,2 0 0,1 8,5C8,5.5 7.82,5.95 7.5,6.3L10.3,9.35L10.83,5.62C10.33,5.26 10,4.67 10,4A2,2 0 0,1 12,2A2,2 0 0,1 14,4C14,4.67 13.67,5.26 13.17,5.62L13.7,9.35L16.47,6.29C16.18,5.94 16,5.5 16,5A2,2 0 0,1 18,3M5,20H19V22H5V20Z';
      tower='M5,20H19V22H5V20M17,2V5H15V2H13V5H11V2H9V5H7V2H5V8H7V18H17V8H19V2H17Z';

 var aBrush : TBrush;
    aRectf : TRectF;
    aPath : TPath;

begin
if Value.IsEmpty then  exit;
aBrush:=TBrush.Create(TBrushKind.Solid,TAlphaColors.Null);
 try
// effacer le texte existant 
  aRectF:=Bounds;
  aRectf.Inflate(3,3);
  aRectF.Left:=aRectf.Left-3;
  if (odd(column.Index) AND odd(row)) OR NOT(odd(column.Index) OR odd(row))
    then aBrush.Color:=TAlphaColors.Ivory
    else aBrush.Color:=TAlphaColors.Chocolate;
  Canvas.FillRect(arectf,1,aBrush);

  if value.ToString.EndsWith('w') then ABrush.color:=Talphacolors.Aqua
                                else ABrush.color:=Talphacolors.black;
 // remplacement du texte par un dessin SVG
  aPath:=Tpath.Create(nil);
  if value.ToString.StartsWith('K') then aPath.Data.Data:=King;
  if value.ToString.StartsWith('Q') then aPath.Data.Data:=Queen;
  if value.ToString.StartsWith('B') then aPath.Data.Data:=bishop;
  if value.ToString.StartsWith('C') then aPath.Data.Data:=cavalier;
  if value.ToString.StartsWith('T') then aPath.Data.Data:=Tower;
  if value.ToString.StartsWith('P') then aPath.Data.Data:=Pion;
  aPath.Fill:=aBrush;
  aPath.width:=40;
  aPath.Height:=40;
  aPath.Parent:=Self;
  aPath.PaintTo(Canvas,Bounds,Stringgrid1); // dessin dans la grille
finally
 aPath.free;
 aBrush.free;
end;

end;</pre></td></tr></table></pre>
</div>Les entêtes étant vraiment séparées du reste, je n'ai pas vraiment cherché à tester l'événement associé <b><i>OnDrawColumnHeader</i></b> si ce n'est pour en trouver son niveau de hiérarchie. Il peut quand même être intéressant de noter que cet évènement se déclenche une fois toutes les cellules prises en compte.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10357/fmx-grilles-couleurs/</guid>
		</item>
		<item>
			<title><![CDATA[[FMX] TStringGrid, copie des données vers le presse-papier]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10348/fmx-tstringgrid-copie-donnees-vers-presse-papier/</link>
			<pubDate>Mon, 04 Jul 2022 08:58:24 GMT</pubDate>
			<description>Le contexte   
Récemment, je...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore"><font color="#0000CD"><font size="2">Le contexte</font> </font> <br />
Récemment, je me suis confronté à un échange de données entre deux sociétés (un fabricant et un prestataire logistique) et ai découvert de nombreuses incohérences de codification entre celles-ci. Mauvaise orthographe de nom de produit ou, pire, mauvaise codification de l'article et même doublons font partie du recensement.<br />
Pour pallier les problèmes d'échanges, il m'a fallu écrire un programme pour d'un côté lire le fichier CSV et le contrôler par rapport aux données du fabricant, le rapport étant mis dans un tableau (TStringGrid). L'idée de pouvoir copier les données du tableau dans le presse-papier pour pouvoir ensuite traiter celles-ci indifféremment dans un tableur ou autre s'est alors imposée assez naturellement.<br />
<br />
Je vous avoue que lorsque j'écris des programmes FMX, je n'utilise que très rarement des grilles, et plus souvent le TGrid d'ailleurs, aussi ai-je été étonné de certains manques par rapport aux &quot;mêmes&quot; grilles VCL. Par &quot;même&quot;, j'entends de mêmes noms, aussi, pour les distinguer, j'ai désormais tendance à mettre le préfixe devant.<br />
Des différences essentielles dans ce contexte sautent aux yeux :<br />
<ul><li style="">VCL.StringGrid permet de fixer des lignes et des colonnes (propriétés FixedRows et FixedCols) ce qui n'est pas le cas pour son synonyme FMX.</li><li style="">VCL.StringGrid offre une option de sélection multiple (goRangeSelect) totalement absente de FMW.StringGrid.Options.</li></ul><br />
D'autres différences seront plus &quot;subtiles&quot; pour tout ce qui est dessin de cellule mais, j'y reviendrai plus tard.<br />
    <br />
Alors que mon objectif de départ était de faire une copie entière du tableau, de fil en aiguille, je me suis pris au jeu de proposer une solution plus indépendante et plus sélective. Assez vite s'est imposée dans mon esprit l'utilisation d'un Helper (les <a href="https://docwiki.embarcadero.com/RADStudio/Sydney/en/Class_and_Record_Helpers_(Delphi)" target="_blank">Class Helpers</a> sont apparus avec la version Delphi 2005 et ont largement évolués au fil des versions suivantes), dans une unité indépendante pour réutilisation possible.<br />
<br />
<font color="#0000CD"><font size="2">Proposition de code</font> </font> <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:192px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td valign="top"><pre style="margin: 0">
TStringGrid2Clipboard = class helper for TStringGrid
  private
    function AddStringSeparator(const s : String; const stringseparator : Char) : String;
  public
    // fonctions sur tableau
    function FullGrid2Clipboard(const addheader : boolean = true; const stringseparator : char =#0) : boolean;
    function SelectColumns2Clipboard(var Cols : TArray&lt;integer&gt;; const addheader : boolean = false; const stringseparator : char =#0) : boolean;
    function SelectRows2Clipboard(var Rows : TArray&lt;integer&gt;; const addheader : boolean = false; const stringseparator : char =#0) : boolean;
    function SelectColRows2Clipboard(var Cols,Rows : TArray&lt;integer&gt;; const addheader : boolean = false; const stringseparator : char = #0) : boolean;
    // fonction sur sélection de cellules
    function CellRange2ClipBoard(var Selected : TRect ; const addheader : boolean = false; const stringseparator : char =#0) : boolean;
  end;</pre></td></tr></table></pre>
</div>Code complet <a href="https://www.developpez.net/forums/attachment.php?attachmentid=621751&amp;d=1656922777"  title="Nom : FMX.StringGridHelper.pas
Affichages : 82
Taille : 10,3 Ko">FMX.StringGridHelper.pas</a><br />
<br />
Il ne me restait plus alors qu'à élaborer un programme de test.<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=621752&amp;d=1656923347" border="0" alt="Nom : Capture.PNG
Affichages : 267
Taille : 70,8 Ko"  style="float: CONFIG" /><br />
<br />
Qui m'a permis de me confronter aux diverses difficultés de l'interface utilisateur concernant les sélections, mais aussi affichages. <br />
N'étant le sujet principal de ce billet, vous retrouverez les sources de ce test à jour dans ce <a href="https://github.com/Serge-Girard/StringGrid2Clipboard" target="_blank">dépôt Github</a><br />
<br />
N.B. Loin d'être parfait, mon attention étant surtout tournée vers les applications Desktop, n'hésitez pas à participer à son évolution via vos commentaires ou des interventions directes sur mon dépôt (Issues ou Pull request). <br />
<br />
D'ores et déjà, je prévois  : <br />
<ul><li style="">Une étude de l'affichage prenant en compte les styles,</li><li style="">Des tests plus poussés en cas de cibles &quot;mobiles&quot; impliquant donc les gestes,</li><li style="">Une intégration plus poussée passant par une modification du composant FMX.StringGrid</li></ul><br />
Enfin, si vous ne voulez pas réinventer la roue, des composants tiers proposent déjà ces fonctionnalités, je pense en particulier au TMSFMXGrid qu'il m'est arrivé d'utiliser à cet effet.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10348/fmx-tstringgrid-copie-donnees-vers-presse-papier/</guid>
		</item>
		<item>
			<title><![CDATA[Utilisation ludique d'un style FMX (jeu de taquin)]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10132/utilisation-ludique-d-style-fmx-jeu-taquin/</link>
			<pubDate>Thu, 03 Jun 2021 15:38:33 GMT</pubDate>
			<description><![CDATA[L'objectif de ce billet n'est...]]></description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">L'objectif de ce billet n'est pas de refaire une nouvelle version d'un jeu de Taquin que vous pourrez retrouver dans <a href="https://www.developpez.net/forums/d2110238-nouveau/environnements-developpement/delphi/codes-sources-telecharger/jeu-taquin-sidney-10-4-2-a/" target="_blank">cette discussion</a>.<br />
<br />
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 <b><i>Style</i></b> m'était jusqu'à présent plutôt &quot;terra incognita&quot; et ses objets souvent source de frustrations au cours de mes divers démêlés avec les styles.<br />
 <br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599080&amp;d=1622706752" border="0" alt="Nom : Style_01.PNG
Affichages : 8314
Taille : 13,0 Ko"  style="float: CONFIG" /></div><br />
:alerte: Je tiens à souligner qu'il s'agit bien des styles FMX, ceux utilisés en VCL sont beaucoup plus &quot;figés&quot; et, s'il y a similitudes et possibilités de transformation de l'un vers l'autre mes &quot;recherches&quot; n'ont pas été plus loin dans cette direction.<br />
<br />
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.<br />
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é.<br />
Je suis alors passé par ce que je connais mieux : le dépôt d'un <b><i>TStyleBook</i></b> sur une forme et l'ouverture de son éditeur.<br />
<br />
Voilà ce que je veux obtenir :<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599081&amp;d=1622706773" border="0" alt="Nom : Style_02.png
Affichages : 3854
Taille : 127,7 Ko"  style="float: CONFIG" /></div><br />
Je vais maintenant indiquer les diverses étapes qui m'ont été nécessaires pour réaliser cela. <br />
Mais, tout d'abord, notez que le style sera un style dit 'Default' afin qu'il s'applique quelle que soit la plateforme cible.<br />
<br />
<ul><li style="">Double-cliquez sur le composant <b><i>StyleBook1</i></b> déposé sur la forme afin d'ouvrir le concepteur de styles.</li><li style="">Glissez-déposez ensuite un <b><i>TImage</i></b> dans l'arborescence du <b><i>StyleContainer</i></b>. </li></ul><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599126&amp;d=1622734583" border="0" alt="Nom : Style_03.png
Affichages : 3936
Taille : 32,1 Ko"  style="float: CONFIG" /></div><br />
<ul><li style="">Chargez une image (propriété <b><i>MultiResBitmap</i></b>) et changer la propriété <b><i>StyleName</i></b> en quelque chose de plus &quot;parlant&quot; que le nom par défaut proposé <b><i>Image1Style</i></b>(un nom neutre me sera utile plus tard aussi utiliserai-je <b><i>'modele'</i></b> pour la suite).</li></ul><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599127&amp;d=1622734603" border="0" alt="Nom : Style_04.png
Affichages : 3853
Taille : 53,3 Ko"  style="float: CONFIG" /></div><br />
Il est désormais temps de créer notre première pièce du puzzle.<br />
<ul><li style="">Glissez-déposez un <b><i>TLayout</i></b> au niveau de la racine (StyleContainer) et dans ce <b><i>TLayout</i></b>, auquel vous aurez changé la propriété <b><i>StyleName</i></b> en '<b><i>piece01</i></b>', ajoutez un <b><i>TStyleObject</i></b>.</li><li style="">Changez la propriété <b><i>StyleLookup</i></b> du <b><i>StyleObject</i></b> créé (y mettre le <b><i>StyleName</i></b> du <b><i>TImage</i></b>).</li><li style="">Utilisez le bouton proposé par la propriété <b><i>SourceLink</i></b> qui va ouvrir une nouvelle fenêtre, <b>Éditeur BitmapLinks</b>.</li></ul><br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599128&amp;d=1622734626" border="0" alt="Nom : Style_05.png
Affichages : 3854
Taille : 95,2 Ko"  style="float: CONFIG" /><br />
</div><br />
<ul><li style="">La première chose à faire est de réduire le zoom de façon à visualiser l'image entière.</li><li style="">Agrippez les deux coins jaunes de façon à retailler la zone à définir. Quand vous les déplacerez, les valeurs <b><i>TBounds</i></b> (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).</li></ul><br />
:weird: 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.<br />
<ul><li style="">Refaites alors les opérations pour chaque pièce. </li></ul><br />
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   <br />
créer ces pièces plus rapidement, prenez le temps de créer la pièce numéro 2 (à droite de la première, <font color="#A9A9A9">TBounds(100,00,0,00)-(200,00,100,00)</font>)  et celle qui sera sous la première (pièce numéro 5, <font color="#A9A9A9">TBounds(0,00,100,00)-(100,00,200,00)</font>).<br />
<br />
Je vous livre donc l'astuce, pour éviter ces répétitions et corriger les petits défauts de positions : <br />
<ul><li style="">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 &quot;compilée&quot;, j'écrirai plutôt compressée, illisible.</li><li style="">Ouvrez le fichier créé avec un outil tel que Notepad++.</li></ul><br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code XML :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
object TStyleContainer
  object TImage
    StyleName = 'modele'
    MultiResBitmap.Height = 400
    MultiResBitmap.Width = 400
    MultiResBitmap = <span style="color: #009900;">&lt;</span>
<span style="color: #009900;">      item</span>
<span style="color: #009900;">        Width = 400</span>
<span style="color: #009900;">        Height = 400</span>
<span style="color: #009900;">        PNG = <span style="color: black">&#123;</span></span>
<span style="color: #009900;">          89504E470D0A1A0A0000000D494844520000019000000190080600000080BF36</span>
<span style="color: #009900;">          CC000000017352474200AECE1CE90000000467414D410000B18F0BFC61050000</span>
<span style="color: #009900;">          FFBA49444154785EECBD07A0654771E75D2FE737392AA2882414404248800011</span>
<span style="color: #009900;">&lt;!-- je vous fais gr&acirc;ce des quelque 2700 lignes suivantes de l<span style="color: #FF0000;">''</span>image --<span style="color: #0000ff;">&gt;</span></span>
         66FB0FEEB55FF8D0476CDFCEFD9136373F671DED1DE107350352A142850A152A
          340EB3FF13E4E33CC0A3EE7CFE0000000049454E44AE426082}
        FileName = 
          'D:\serge\Documents\Embarcadero\Studio\Projets\Sidney\stoneedge.png'
      end&gt;
    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 = <span style="color: #009900;">&lt;</span>
<span style="color: #009900;">        item</span>
<span style="color: #009900;">          SourceRect.Left = 2.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Top = 1.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Right = 100.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Bottom = 100.000000000000000000</span>
<span style="color: #009900;">        end<span style="color: #0000ff;">&gt;</span></span>
    end
  end
  object TLayout
    StyleName = 'piece02'
    Align = Center
    Visible = False
    TabOrder = 2
    object TStyleObject
      StyleName = 'StyleObject1Style'
      SourceLookup = 'Modele'
      SourceLink = <span style="color: #009900;">&lt;</span>
<span style="color: #009900;">        item</span>
<span style="color: #009900;">          SourceRect.Left = 100.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Right = 200.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Bottom = 100.000000000000000000</span>
<span style="color: #009900;">        end<span style="color: #0000ff;">&gt;</span></span>
    end
  end
  object TLayout
    StyleName = 'piece05'
    Align = Center
    TabOrder = 1
    object TStyleObject
      StyleName = 'StyleObject1Style'
      SourceLookup = 'Modele'
      SourceLink = <span style="color: #009900;">&lt;</span>
<span style="color: #009900;">        item</span>
<span style="color: #009900;">          SourceRect.Top = 100.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Right = 100.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Bottom = 200.000000000000000000</span>
<span style="color: #009900;">        end<span style="color: #0000ff;">&gt;</span></span>
    end
  end
 end</pre></td></tr></table></pre>
</div>Ce qui nous intéresse, c'est un bloc de TLayout, définissant une piéce<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code XML :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
  object TLayout
    StyleName = 'piece01'
    Align = Center
    Visible = False
    TabOrder = 3
    object TStyleObject
      StyleName = 'StyleObject1Style'
      SourceLookup = 'Modele'
      SourceLink = <span style="color: #009900;">&lt;</span>
<span style="color: #009900;">        item</span>
<span style="color: #009900;">          SourceRect.Left = 2.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Top = 1.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Right = 100.000000000000000000</span>
<span style="color: #009900;">          SourceRect.Bottom = 100.000000000000000000</span>
<span style="color: #009900;">        end<span style="color: #0000ff;">&gt;</span></span>
    end
  end</pre></td></tr></table></pre>
</div>Il suffira de le reproduire par copier-coller en changeant la propriété <b><i>StyleName</i></b> et les différentes propriétés de <b><i>SourceLink</i></b> pour obtenir un découpage parfait. Une fois fait :<br />
<ul><li style="">Sauvegardez le fichier modifié.</li><li style="">Revenez à l'IDE Delphi et à votre programme.</li><li style="">Chargez à nouveau le style (pour récupérer les modifications faites).</li></ul><br />
<br />
<br />
Il ne reste plus qu'à utiliser le style.<br />
:alerte: N'oubliez pas, même si la clôture de l'onglet <b>Concepteur de styles</b> se charge de vous le rappeler, d'appliquer le style (bouton le plus à droite).<br />
<br />
Dans la deuxième image de cet article, pour illustrer l'objectif, j'ai utilisé un <b><i>TGridLayout</i></b> pour contenir des <b><i>TPanels</i></b> qui, eux, auront chacun une propriété <b><i>StyleLookup</i></b> différent.<br />
Il n'est pas sûr que le <b><i>TGridLayout</i></b> soit le composant le plus adapté pour codifier le jeu, mais, il n'était pas non plus dans mes desseins que de le faire.      <br />
<br />
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 ?<br />
J'aurais, bien sûr, pu faire un style par image, mais ma curiosité m'a poussé à le vérifier. <br />
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é.<br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code Delphi :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">procedure</span> TMainForm.ButtonChangeImageClick<span class="br0">&#40;</span>Sender: <span style="color: #0080ff;">TObject</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">var</span> pStream : TMemoryStream;
    pFMXObj : TFMXObject;
<span style="color: #0000ff;">begin</span>
&nbsp;
<span style="color: #808080;">// Passage de l'image via un stream</span>
pStream:=TMemoryStream.Create;
<span style="color: #0000ff;">try</span>
  PStream.LoadFromFile<span class="br0">&#40;</span><span style="color: #FF0000;">'test1.png'</span><span class="br0">&#41;</span>;
  pFMXObj:=StyleBook1.Style.FindStyleResource<span class="br0">&#40;</span><span style="color: #FF0000;">'modele'</span><span class="br0">&#41;</span>;
  <span style="color: #0000ff;">if</span> Assigned<span class="br0">&#40;</span>pFMXObj<span class="br0">&#41;</span> <span style="color: #0000ff;">then</span>
    <span style="color: #0000ff;">begin</span>
      PStream.Position:=<span style="color: #cc66cc;">0</span>;
      TImage<span class="br0">&#40;</span>pfMXObj<span class="br0">&#41;</span>.Bitmap.LoadFromStream<span class="br0">&#40;</span>Pstream<span class="br0">&#41;</span>;
    <span style="color: #0000ff;">end</span>;
<span style="color: #0000ff;">finally</span>
  pStream.Free;
<span style="color: #0000ff;">end</span>;
&nbsp;
<span style="color: #808080;">//pFMXObj:=StyleBook1.Style.FindStyleResource('modele');</span>
<span style="color: #808080;">//if Assigned(pFMXObj) then</span>
<span style="color: #808080;">//    begin</span>
<span style="color: #808080;">//      TImage(pfMXObj).Bitmap.LoadFromFile('test1.png');</span>
<span style="color: #808080;">//    end;</span>
&nbsp;
<span style="color: #808080;">// Forcer le dessin du GridLayout</span>
GridLayout1.BeginUpdate;
GridLayout1.EndUpdate;
&nbsp;
<span style="color: #808080;">// variante Repaint par piece</span>
<span style="color: #808080;">//for var i:= 0 to GridLayout1.ChildrenCount-1 do</span>
<span style="color: #808080;">//  TPanel(Gridlayout1.Children[i]).Repaint;</span>
&nbsp;
&nbsp;
<span style="color: #808080;">// Variante re-dessin complet</span>
<span style="color: #808080;">//for var i:= GridLayout1.ChildrenCount-1 downto 0 do</span>
<span style="color: #808080;">//  Gridlayout1.Children[i].Free;</span>
<span style="color: #808080;">//</span>
<span style="color: #808080;">//for var i := 1 to 16 do</span>
<span style="color: #808080;">//   begin</span>
<span style="color: #808080;">//     with TPanel.Create(Self) do</span>
<span style="color: #808080;">//      begin</span>
<span style="color: #808080;">//         StyleLookup:=Format('piece%.2d',[i]);</span>
<span style="color: #808080;">//         Parent:=GridLayout1;</span>
<span style="color: #808080;">//     end;</span>
<span style="color: #808080;">//   end;</span>
<span style="color: #0000ff;">end</span>;</pre></td></tr></table></pre>
</div><br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachment.php?attachmentid=599089&amp;d=1622708108" border="0" alt="Nom : Style_06.png
Affichages : 3781
Taille : 438,5 Ko"  style="float: CONFIG" /></div><br />
Je suis prêt à parier qu'il y a encore d'autres solutions code que je n'ai pas explorées à l'heure actuelle.<br />
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 <b><i>SourceRect</i></b> ne sera pas aussi simple.<br />
<br />
En tout cas, j'espère que cette utilisation &quot;ludique&quot; des styles FMX changera peut-être votre opinion sur ceux-ci.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10132/utilisation-ludique-d-style-fmx-jeu-taquin/</guid>
		</item>
		<item>
			<title><![CDATA[[Dephi][VCL]Carnet de plongées : TControlList - webinaire]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10130/dephi-vcl-carnet-plongees-tcontrollist-webinaire/</link>
			<pubDate>Sun, 30 May 2021 08:14:27 GMT</pubDate>
			<description>Le 20 mai 2021, Patrick aka...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Le 20 mai 2021, Patrick aka <a href="https://www.developpez.net/forums/u666471/pprem/" target="_blank">pprem</a> m'ouvrait sa chaine Twitch pour que je présente mes &quot;recherches/essais&quot; sur le composant TControlList et je l'en remercie ainsi que du travail qu'il a pu faire en aval par la suite (découpages et publications).<br />
Ma présentation étant enregistrée vous pouvez la visionner <a href="https://delphi.developpez.com/webinaires/voir/id/5" target="_blank">ici</a><br />
<br />
En fin de présentation j'ai évoqué une utilisation &quot;ludique&quot; de ce composant en programmant un jeu de Taquin que vous pourrez retrouver en source <a href="https://delphi.developpez.com/telecharger/detail/id/7185/Jeu-de-taquin-Sidney-10-4-2" target="_blank">ici</a>, mais aussi des ébauches : plateau de dames et échiquier.<br />
<br />
Si je parle du jeu de Taquin c'est que, après exploré la rétrogradation de version comme la possiblité d'une version FMX il m'est venu à l'idée d'utiliser une feuille de style pour découper une image. Cela sera certainement l'objet de mon futur billet, une pierre supplémentaire à mon étude sur les styles FMX.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10130/dephi-vcl-carnet-plongees-tcontrollist-webinaire/</guid>
		</item>
		<item>
			<title><![CDATA[[Delphi][VCL] Carnet de Plongées : TControlList - Bilan]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10074/delphi-vcl-carnet-plongees-tcontrollist-bilan/</link>
			<pubDate>Thu, 29 Apr 2021 06:09:46 GMT</pubDate>
			<description>En clôture de cette série de...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">En clôture de cette série de billets, il est temps de faire le bilan.<br />
<br />
Ma première impression, trop habitué maintenant aux listes FMX (FMX.TListView), j'ai d'abord cru à un équivalent, en mieux puisqu'il y avait la possibilité de créer des colonnes. Cette première réaction s'est avérée plus ou moins fausse, oui, effectivement, cela y ressemble par exemple par la nécessité de l'utilisation des Livebindings pour lier ce composant à un ensemble de données.<br />
Une fois l'habitude prise, on est vite frustré par le peu de composants que l'on peut utiliser. Seuls des composants dits &quot;contrôles graphiques&quot; (TGraphicControl) sont acceptés soit : des TLabel, TImage, TVirtualImage, TShape, TSpeedButton et TSplitter (et encore ce dernier n'est pas fonctionnel) en sus du nouveau et spécifique TControlListButton.<br />
Comme pour la FMX.TListview, ce n'est pas un composant équivalent d'une grille donnant la possibilité d'éditer des données en son sein.<br />
<br />
Une compréhension de ce que je nommerai un cycle de dessin est absolument nécessaire pour avoir une maitrise fine de ce composant. Je le schématiserai ainsi :<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=596797&amp;d=1619673649" border="0" alt="Nom : cycle.png
Affichages : 572
Taille : 148,5 Ko"  style="float: CONFIG" /><br />
* notez que les évènements onEnableControl, onShowControl ne sont que des modifications des propriétés Enable et Visible du contrôle, ces mêmes propriétés (ainsi que d'autres) pouvant être modifiées dans les évènements plus généraux (OnBeforeDrawItem, onAfterDrawItem).<br />
<br />
En théorie donc, seuls les éléments &quot;visibles&quot; sont dessinés. Néanmoins, cette &quot;économie&quot; est légèrement gâchée (démonstration avec <a href="https://www.developpez.net/forums/blogs/138527-sergiomaster/b10065/delphi-vcl-carnet-plongees-tcontrollist-boite-nuit-soiree/" target="_blank">ce billet</a>) par le fait qu'un déplacement de la souris sur les éléments de la liste entraine un rafraichissement de la liste entière (entre autres pour les effets visuels). <br />
<br />
Dans la partie positive :<br />
<ul><li style="">Les diverses présentations possibles. (ColumnLayout)</li><li style="">La facilité de réalisation, surtout dans le cadre d'une utilisation d'un ensemble de données liées (LiveBindings).</li><li style="">La vitesse du dessin (dépendant quand même des tailles d'image).</li></ul><br />
<br />
Dans la partie négative :<br />
<ul><li style="">Le peu de contrôles utilisables.</li><li style="">Les divers bogues constatés (onItemClick intempestifs, liaison avec TProtypeBindSource).</li><li style="">L'impossibilité d'accéder à certaines méthodes (par exemple : ItemAtPos  cf. <a href="https://www.developpez.net/forums/blogs/138527-sergiomaster/b10098/delphi-vcl-carnet-plongees-tcontrollist-dragdrop/" target="_blank">le billet sur le Drag&amp;Drop</a>) </li></ul><br />
<br />
Dans la liste des regrets : <br />
<ul><li style="">L'impossibilité d'avoir des éléments de tailles variables.</li><li style="">L'impossibilité de gérer le nombre de colonnes ou lignes selon le   maximum</li><li style="">Le fait que les éléments affichés ne soient pas &quot;mémorisés&quot; de façon à accéder facilement à ses éléments.  </li></ul><br />
<br />
En conclusion générale, un gadget améliorable.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10074/delphi-vcl-carnet-plongees-tcontrollist-bilan/</guid>
		</item>
		<item>
			<title><![CDATA[[Delphi][VCL] Carnet de Plongées : TControlList - PrototypeBindSource]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10108/delphi-vcl-carnet-plongees-tcontrollist-prototypebindsource/</link>
			<pubDate>Wed, 28 Apr 2021 05:18:02 GMT</pubDate>
			<description>Ce billet sera le dernier de...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Ce billet sera le dernier de la série avant de refermer ce carnet. Cette fois-ci je m'attaque à la liaison entre un<b><i> TPrototypeBindSource</i></b> et le <b><i>TControlList</i></b>.<br />
<br />
Pour ceux qui ne sont pas habitués, un <b><i>TPrototypeBindSource</i></b> permet de créer un ensemble de données qui contiendra des valeurs aléatoires, en fonction des types colonnes souhaitées. Pratique pour un design rapide d'interface, inutile dans une application réelle si ce n'est qu'une simple instruction fera basculer cet ensemble de données aléatoires en chargeant une liste de vos propres objets et valeurs.<br />
<br />
Pourquoi, alors, n'ai-je point commencé par là au lieu d'utiliser le fichier <b>biolife.cds</b> ? De fait, lors de la sortie de la version 10.4, fort de mon expérience FMX, j'ai commencé par ça et ait été totalement déçu par le comportement de TControlList. De mon point de vue, le scénario à éviter pour une première démonstration est bien ce type d'association ! Plusieurs bogues et manques se révèlent très vite, en partie dû à la liaison entre les deux composants via l'utilisation de LiveBindings.<br />
<br />
Commençons par quelque chose de simple avant de nous mettre dans les eaux troubles.<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=596347&amp;d=1619100192" border="0" alt="Nom : prototype.png
Affichages : 628
Taille : 125,0 Ko"  style="float: CONFIG" /><br />
<br />
Ce premier programme, que vous pourrez retrouver dans mon <a href="https://github.com/Serge-Girard/TControlList/tree/main/10-PrototypeSource" target="_blank">dépôt GitHub</a>, est largement inspiré d'une démonstration de Jim McKeeth trouvée <a href="https://github.com/Embarcadero/RADStudio-DemoKit/tree/main/10.4.2-demos/ControlListLiveBinding" target="_blank">ici</a>. <br />
Question remplissage de la liste, je n'ai pas tout à fait suivi le même schéma, en effet Jim récupère le nom de la couleur affichée. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">ACanvas.Brush.Color := StrToInt(lblColorValue.Caption);</pre>
</div>De mon côté, j'ai préféré récupérer directement la valeur de la couleur générée<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">ACanvas.Brush.Color := Couleurs.DataGenerator.FindField('Color1').GetTValue.AsInteger;</pre>
</div>Petite cerise sur le gâteau, j'ai également géré la couleur de fonte des libellés  <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormCouleurs.ControlList1BeforeDrawItem(AIndex: Integer;
  ACanvas: TCanvas; ARect: TRect; AState: TOwnerDrawState);
var
  FontColor: TColor;

  function IsDark(AColor: TColor): Boolean;
  // Paul Toth
  var
    Color: Integer;
  begin
    Color := ColorToRGB(AColor); // conversion clXXX en couleur RGB
    Result := 0.2125 * TColorRec(Color).R + 0.7174 * TColorRec(Color).G + 0.0721
      * TColorRec(Color).B &lt;= 128;
  end;

begin
  ACanvas.Brush.Color := Couleurs.DataGenerator.FindField('Color1').GetTValue.AsInteger;
  ACanvas.FillRect(ARect);

  if IsDark(ACanvas.Brush.Color) then
    FontColor := clWhite
  else
    FontColor := clBlack;
  LblCouleur.Font.Color := FontColor;
  LblItem.Font.Color := FontColor;
  LblItem.Caption := Format('Item n°%d', [AIndex]);
end;</pre></td></tr></table></pre>
</div>Si, a priori, il semble fonctionner correctement cela gêne aux entournures. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=596703&amp;d=1619586895" border="0" alt="Nom : Capture_2.PNG
Affichages : 267
Taille : 57,7 Ko"  style="float: CONFIG" /><br />
<br />
Regardez dans le cadre rouge les valeurs liées ne sont pas les valeurs de l'élément sélectionné, mais celle du dernier élément dessiné visible dans la liste !<br />
<br />
Comment s'en sortir ? Tout d'abord <u>en n'associant pas les données via Livebindings</u> puis en utilisant l'évènement OnAfterDrawItems pour :<br />
<ul><li style="">Me positionner dans le TPrototypeBindSource (que j'ai nommé <b>couleurs</b>).</li><li style="">Renseigner par code les deux zones. </li></ul><br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormCouleurs.ControlList1AfterDrawItems(ACanvas: TCanvas;
  ARect: TRect);
begin
  // positionnement dans &quot;fichier&quot;
  Couleurs.ItemIndex := ControlList1.ItemIndex;
  // écriture des valeurs
  Couleur.Brush.Color := Couleurs.DataGenerator.FindField('Color1').GetTValue.AsInteger;
  NomCouleur.Caption := Couleurs.DataGenerator.FindField('ColorsName1').GetTValue.AsString;
end;</pre></td></tr></table></pre>
</div>Pour être sûr de mon fait, j'ai ajouté un TNumberBox qui permet de visualiser le numéro de l'élément en cours, mais aussi de se déplacer au sein de la liste (toujours grâce aux Livebindings) <br />
<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:144px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormCouleurs.ControlList1ItemClick(Sender: TObject);
begin
  NumberBox1.Value := ControlList1.ItemIndex;
end;

procedure TFormCouleurs.FormCreate(Sender: TObject);
begin
  NumberBox1.MaxValue := ControlList1.ItemCount - 1;
end;</pre></td></tr></table></pre>
</div>Maintenant qu'un moyen de résoudre le problème est possible, il ne s'agit pas de rester sur un truc qui reste malgré tout très théorique, mais plutôt de démontrer qu'il est possible de remplir un TControlList avec notre propre liste d'objets. Je vais partir sur une sorte de trombinoscope pour pouvoir mêler images et libellés (un nom et une date).<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br /></div></td><td valign="top"><pre style="margin: 0">
unit UCtrlListContacts;

interface

uses System.SysUtils
  // nécessaire pour obtenir la date système, le type TFileName
    , System.Generics.Collections
  // nécessaire pour la déclaration de liste d'objets
    , System.Generics.Defaults, System.Classes, System.types,
  System.NetEncoding, System.DateUtils // nécessaire pour EncodeDate
    , VCL.graphics, VCL.Imaging.pngimage, System.UITypes;
type
  TContact = Class
  strict private
    FNom: String;
    FDate: String;
    FPhoto: TPicture;
  private
    // ...
    procedure SetNom(const Value: String);
    procedure SetDate(const Value: String);
    procedure SetPhoto(const Value: TPicture);
  public
    constructor Create(); overload;
    constructor Create(Nom: String; UneDate: String; Photo: TPicture); overload;
    property ContactNom: String read FNom write SetNom;
    property ContactDate: String read FDate write SetDate;
    property ContactPhoto: TPicture read FPhoto write SetPhoto;
  end;

// ..
var
  MesContacts: TObjectList&lt;TContact&gt;;

implementation
//...
initialization
   MesContacts := TObjectList&lt;TContact&gt;.Create;</pre></td></tr></table></pre>
</div>L'astuce pour construire la forme est de déposer un <b><i>TProtypeBindSource</i></b> sur celle-ci avec &quot;la même structure&quot; que la classe <b>TContact</b>. Par même structure, il faut surtout comprendre même noms de colonnes et type. <br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=596596&amp;d=1619449301" border="0" alt="Nom : Capture_3.PNG
Affichages : 317
Taille : 47,0 Ko"  style="float: CONFIG" /><br />
<br />
À nouveau un peu de turbidité s'élève du fond : le générateur ContactBitmaps ne fonctionne pas correctement (une seule image est rendue dans la liste). J'ai tout d'abord incriminé le TControlList mais en fait il s'agit bien d'un problème de générateur, étrangement ce générateur n'est pas déclaré dans l'unité <b>Data.Bind.GenData</b> (alors qu'il est proposé). Je n'ai pas ou déterminer d'où pouvait bien provenir l'image (en FMX, le générateur et ces images sont déclarées dans <b>FMX.Bind.GenData</b>). Cela n'a aucune importance mais... En VCL, oublier les générateurs du <b><i>TPrototypeBindSource</i></b>  <b>ContactBimaps</b> et <b>ContactBitmapsL</b> et en rester à <b>Bitmaps</b> est donc une idée à garder en mémoire pour éviter ce petit désagrément.<br />
<br />
Il ne me reste plus qu'à mettre en place l'utilisation de la collection. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:120px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm14.ContactsCreateAdapter(Sender: TObject;
  var ABindSourceAdapter: TBindSourceAdapter);
begin
 P_DonneesInternes; // charge les données, fonction de classe
 ABindSourceAdapter:=TListBindSourceAdapter&lt;TContact&gt;.Create(self,MesContacts, True);  // remplace les données du TPrototypeBindSource
 ControlList1.ItemCount:=MesContacts.Count;  // Nombre d'élément dans la liste
end;</pre></td></tr></table></pre>
</div>Puis appliquer la solution exposée plus haut<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br /></div></td><td valign="top"><pre style="margin: 0">procedure TForm14.ControlList1AfterDrawItems(ACanvas: TCanvas; ARect: TRect);
var aStream : TMemoryStream;
    avar : TPicture;
begin
if  Contacts.ItemIndex&lt;&gt;ControlList1.ItemIndex then Contacts.ItemIndex:=ControlList1.ItemIndex;
Nom.Text:=MesContacts[ControlList1.ItemIndex].ContactNom;
DateC.Date:=StrToDate(MesContacts[ControlList1.ItemIndex].ContactDate);
// partie chargement image
aStream:=TmemoryStream.Create;
try
    avar:=MesContacts[ControlList1.ItemIndex].ContactPhoto;
    if assigned(avar) then
     begin
      avar.savetostream(astream);
      aStream.Position:=0;
      Photo.Picture.LoadFromStream(aStream);
     end;
finally
  aStream.Free;
end;</pre></td></tr></table></pre>
</div><img src="https://www.developpez.net/forums/attachment.php?attachmentid=596701&amp;d=1619585710" border="0" alt="Nom : Capture_6.PNG
Affichages : 273
Taille : 43,7 Ko"  style="float: CONFIG" /><br />
<br />
Vous retrouverez dans mon dépôt github<a href="https://github.com/Serge-Girard/TControlList/tree/main/11-PrototypeContacts" target="_blank"> le source du programme</a> et ma solution de sauvegarde/chargement des données. N.B. je n'ai pas géré les ajouts et suppressions, cela fera peut-être lieu à une mise à jour dans le futur.<br />
<br />
Quels enseignements tirés de cette partie : <br />
Le composant TControlList est bogué s'il est en liaison avec un TProtypeBindSource, néanmoins il est utilisable une fois cette mise en garde connue.</blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10108/delphi-vcl-carnet-plongees-tcontrollist-prototypebindsource/</guid>
		</item>
		<item>
			<title><![CDATA[[Delphi][VCL] Carnet de Plongées : TControlList - Drag&Drop]]></title>
			<link>https://www.developpez.net/forums/blogs/138527-sergiomaster/b10098/delphi-vcl-carnet-plongees-tcontrollist-dragdrop/</link>
			<pubDate>Thu, 22 Apr 2021 06:06:04 GMT</pubDate>
			<description>Passons à un peu plus...</description>
			<content:encoded><![CDATA[<blockquote class="blogcontent restore">Passons à un peu plus sérieux.<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=595444&amp;d=1618209040" border="0" alt="Nom : ScpahEchelle_small.PNG
Affichages : 2130
Taille : 85,1 Ko"  style="float: CONFIG" /> <br />
<br />
Après avoir étudié les évènements spécifiques au TControlList dans les précédents billets<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=595453&amp;d=1618213018" border="0" alt="Nom : Capture_6.PNG
Affichages : 8669
Taille : 36,9 Ko"  style="float: CONFIG" /><br />
<br />
les opérations de drag&amp;drop étant proposées, j'ai trouvé intéressant de me pencher dessus. Je pense que bien m'en a pris, car cela m'a permis de me confronter à quelques problématiques inhérentes au concept de ce composant, m'obligeant à faire de la plongée profonde dans les sources et découvrir, avouons-le, des parties de codes qui m'ont déstabilisé ou frustré !<br />
<br />
Plantons le décor :<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=595465&amp;d=1618220708" border="0" alt="Nom : Capture.PNG
Affichages : 454
Taille : 38,1 Ko"  style="float: CONFIG" /><br />
<br />
L'objectif principal est d'attacher à un élément de la liste de gauche, une image contenue dans la liste de droite. Le premier défi est déjà d'avoir une variable quelconque pour stocker les données, bien sûr il y a la possibilité d'une table, mais j'ai plutôt choisi d'utiliser une simple collection (un TDictionnary&lt;integer,integer&gt;) avec comme clé le numéro de l'élément et comme valeur un numéro d'image.<br />
<br />
Afficher une liste d'image est assez simple, les données utilisées sont de fait celle de la collection d'image. L'image présentée au sein de la liste étant une image virtuelle liée à la collection, changer sa propriété ImageIndex fait le boulot.<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormDragdrop.ControlListImagesBeforeDrawItem(AIndex: Integer; ACanvas: TCanvas;
  ARect: TRect; AState: TOwnerDrawState);
begin
  VirtualImage3.ImageIndex := AIndex;
end;</pre></td></tr></table></pre>
</div>Pour afficher la liste de gauche il ne faut guère plus d'astuce<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:168px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormDragdrop.ControlListGaucheBeforeDrawItem(AIndex: Integer; ACanvas: TCanvas;
  ARect: TRect; AState: TOwnerDrawState);
var
  imagenumber: Integer;
begin
  lblTitre.Caption := 'Item ' + AIndex.ToString;   // affichage du titre
  if ItemImages.TryGetValue(AIndex, imagenumber) then  // affichage de l'image chosie
    VirtualImage1.ImageIndex := imagenumber
  else
    VirtualImage1.ImageIndex := -1;
end;</pre></td></tr></table></pre>
</div>Dans les deux cas il s'agit d'utiliser, ce que j'ai déjà décrit dans mes divers billets : l'évènement OnBeforeDrawItem du TControlList.<br />
<br />
<img src="https://www.developpez.net/forums/attachment.php?attachmentid=595855&amp;d=1618662743" border="0" alt="Nom : Capture_2.PNG
Affichages : 418
Taille : 108,0 Ko"  style="float: CONFIG" /><br />
*La capture d'écran ne rend pas hommage au programme, aussi je vous invite à lancer la vidéo via<a href="https://serge-girard.developpez.com/tutoriels/temp/Video_dragdrop.webm" target="_blank"> ce lien</a><br />
<br />
<b><u>Comment en suis-je arrivé là ?</u></b><br />
Pour initier l'opération de glissement<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:120px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormDragdrop.ControlListImagesMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  itemidx := ControlListImages.ItemIndex;  // mémorisation de l'index 
  if (Button = mbLeft) AND (ssShift in Shift) then
    ControlListImages.BeginDrag(true);
end;</pre></td></tr></table></pre>
</div>Si coder l'acceptation du glissement est facile <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:96px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0">procedure TFormDragdrop.ControlListGaucheDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
begin
  Accept := Source is TControlList;
end;</pre></td></tr></table></pre>
</div>Le problème qui se pose est de retrouver le numéro de l'élément qui va recevoir l'image choisie lors de l'évènement OnDragDrop. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">procedure TFormDragdrop.ControlListGaucheDragDrop(Sender, Source: TObject; X, Y: Integer);</pre>
</div>En effet, aucune fonction &quot;visible&quot;, du genre &quot;quel est l'élément à la position X,Y ?&quot;  n'est disponible :weird:.<br />
<br />
Réflexe de vieux loup de mer, j'ai d'abord fait une tentative de &quot;piratage&quot; (hacking) du contrôle pour accéder aux fonctions et propriétés privées. <br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:60px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">type
  THackCtrlList = class(TControlList);</pre></td></tr></table></pre>
</div>Utilisation : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">THackCtrlList(ControlListGauche).</span> rien que ceci et l'EDI nous affiche tout ce qui est désormais accessible. Malheureusement, les fonctions qui pourraient nous intéresser ne sont toujours pas disponibles :calim2:. Une descente dans les sources (Ctrl+Clic gauche sur l'unité VCL.ControlList pour passer au mélange Hélium/Oxygène) nous montre que la plupart de ces fonctions (et procédures)  sont définies dans la zone privée.<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0">
private
 ...
    <b>function ItemAtPos(AX, AY: Integer; var ARect: TRect): Integer;</b> <font color="#0000CD"><i>// celle-ci est celle qui nous serait utile</i></font>
..    
    <font color="#0000CD"><i> // les diverses fonctions suivantes montrent aussi un intérêt pour les déplacements</i></font>  
    function GetFirstDrawItemIndex: Integer;
    function GetLastDrawItemIndex: Integer;
    procedure ScrollToItem(AIndex: Integer; ASelect: Boolean; AUpdate: Boolean);
    procedure FindFirstItem;
    procedure FindLastItem;
    procedure FindLeftItem;
    procedure FindRightItem;
    procedure FindUpItem;
    procedure FindDownItem;
    procedure FindPageUpItem;
    procedure FindPageDownItem;
...</pre></td></tr></table></pre>
</div>Une solution, est de surcharger les diverses fonctions voulues, cependant cela s'est vite avéré fastidieux et pas très probant. De plus le hacking est quand même &quot;inélégant&quot;.<br />
<br />
Je suis parti sur une autre solution, la création d'un Helper.<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:204px;"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="40"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br />92<br />93<br />94<br />95<br />96<br />97<br />98<br />99<br />100<br />101<br />102<br />103<br />104<br />105<br />106<br />107<br />108<br />109<br />110<br />111<br />112<br />113<br />114<br />115<br />116<br />117<br />118<br />119<br />120<br />121<br />122<br />123<br />124<br />125<br />126<br />127<br />128<br />129<br />130<br />131<br />132<br />133<br />134<br />135<br />136<br />137<br />138<br />139<br />140<br />141<br />142<br />143<br />144<br />145<br />146<br />147<br />148<br />149<br />150<br />151<br />152<br />153<br />154<br />155<br />156<br />157<br />158<br />159<br />160<br />161<br />162<br />163<br />164<br />165<br />166<br />167<br />168<br />169<br />170<br />171<br />172<br />173<br />174<br />175<br />176<br />177<br />178<br />179<br />180<br />181<br />182<br />183<br /></div></td><td valign="top"><pre style="margin: 0">
unit ControlListHelper;

interface

uses WinApi.Windows, WinApi.Messages,
  System.Types, System.Math, System.Classes, System.Generics.Collections,
  Vcl.ControlList;

type
  TControlListHelper = class helper for TCustomControlList
  public
    function _Columns : Integer;
    function _Rows : Integer;
    function _ItemAtPos(X, Y: Integer;
                        iv: TDictionary&lt;Integer, TRect&gt;=nil): Integer;
    function _GetItemRect(AIndex : Integer): TRect;
    procedure _PageDown;
    procedure _PageUp;
    procedure _PageLeft;
    procedure _PageRight;
    procedure _Home;
    procedure _End;
  end;

var VisibleItems : TDictionary&lt;integer,TRect&gt;;

implementation

{ TControlListHelper }


/// &lt;summary&gt;
/// Get the rect of the drawed item on the TControlList
/// &lt;/summary&gt;
/// &lt;param name=&quot;AIndex&quot;&gt;
///   Index of the item
/// &lt;/param&gt;
/// &lt;returns&gt;a TRect
/// &lt;/returns&gt;
function TControlListHelper._GetItemRect(AIndex : Integer): TRect;
begin
  Result := TRect.Empty;
  case InternalColumnLayout of
    cltSingle:
      begin
        Result.Top := ItemHeight * AIndex;
        Result.Height := ItemHeight;
        Result.Width := IfThen(ItemWidth = 0, Width - 28, ItemWidth);
      end;
    cltMultiTopToBottom:
      begin
        var Cols : integer :=_Columns;
        Result.Left := (AIndex mod Cols) * ItemWidth;
        Result.Top := ((AIndex div Cols) * ItemHeight);
        Result.Height := ItemHeight;
        Result.Width := ItemWidth;
      end;
    cltMultiLeftToRight:
      begin
        var Rows : integer :=_Rows;
        Result.Left := (AIndex div Rows) * ItemWidth;
        Result.Top := (AIndex mod Rows) * ItemHeight;
        Result.Height := ItemHeight;
        Result.Width := ItemWidth;
      end;
  end;
end;

/// &lt;summary&gt;
/// Get index of the TControlList item
/// &lt;/summary&gt;
/// &lt;param name=&quot;X&quot;&gt;
///  X coordinate of the mouse
/// &lt;/param&gt;
/// &lt;param name=&quot;Y&quot;&gt;
///  Y coordinate of the mouse
/// &lt;/param&gt;
/// &lt;param name=&quot;iv&quot;&gt;
///  Items visible on the TControlList
///  a TDictionary&lt;Integer,TRect&gt; to implement during OnDrawItem or AfterDrawItem event
/// &lt;/param&gt;
/// &lt;remarks&gt;
///
/// &lt;/remarks&gt;
/// &lt;returns&gt;Item index; -1 if invalid
/// &lt;/returns&gt;
function TControlListHelper._ItemAtPos(X, Y: Integer;
  iv: TDictionary&lt;Integer, TRect&gt;=nil): Integer;
var
  I: Integer;
  ofHorz, ofVert: Integer;
  ARect: TRect;
begin
  if not Assigned(iv) then iv:=VisibleItems;
  ofHorz := GetScrollPos(Handle, SB_HORZ);
  ofVert := GetScrollPos(Handle, SB_VERT);
  Result := -1;
  for I := 0 to ItemCount - 1 do
  begin
    if iv.TryGetValue(I, ARect) then
    begin
      if ARect.Contains(TPoint.Create(X + ofHorz, Y + ofVert)) then
        exit(I);
    end;
  end;
end;

/// &lt;summary&gt;
/// Get number of columns of the TControlList
/// &lt;/summary&gt;
/// &lt;returns&gt;Number of columns
/// &lt;/returns&gt;
function TControlListHelper._Columns: Integer;
begin
case InternalColumnLayout of
  cltSingle : result:=1;
  cltMultiTopToBottom : result:=ClientWidth div ItemWidth;
  cltMultiLeftToRight : begin
                           var nr : integer := _Rows;
                           result:=ItemCount div nr;
                           if (ItemCount mod nr)&gt;0 then inc(Result);
                        end;
 end;
end;

/// &lt;summary&gt;
/// Get number of rows of the TControlList
/// &lt;/summary&gt;
/// &lt;returns&gt;Number of rows
/// &lt;/returns&gt;
function TControlListHelper._Rows: Integer;
begin
result:=1;
case InternalColumnLayout of
  cltSingle : result:=ItemCount;
  cltMultiTopToBottom : begin
                          var nc : integer := _Columns;
                          result:=ItemCount div nc;
                          if (ItemCount mod nc)&gt;0 then inc(result);
                        end;
  cltMultiLeftToRight : result:=ClientHeight div ItemHeight;
 end;
end;

/// &lt;summary&gt;
/// For gesture usage ???
/// &lt;/summary&gt;
procedure TControlListHelper._PageDown;
begin
SendMessage(Handle, WM_KEYDOWN, VK_NEXT, 0);
end;

procedure TControlListHelper._PageUp;
begin
SendMessage(Handle, WM_KEYDOWN, VK_PRIOR, 0);
end;

procedure TControlListHelper._PageLeft;
begin
SendMessage(Handle, WM_KEYDOWN, VK_LEFT, 0);
end;

procedure TControlListHelper._PageRight;
begin
SendMessage(Handle, WM_KEYDOWN, VK_RIGHT, 0);
end;

procedure TControlListHelper._Home;
begin
SendMessage(Handle, WM_KEYDOWN, VK_HOME, 0);
end;

procedure TControlListHelper._End;
begin
SendMessage(Handle, WM_KEYDOWN, VK_END, 0);
end;

initialization
  VisibleItems := TDictionary&lt;integer,TRect&gt;.Create;
finalization
  VisibleItems.Free;
end.</pre></td></tr></table></pre>
</div><b><u>Le principe ? </u></b>Les rectangles des éléments visibles sont mémorisés dans un dictionnaire (soit celui de l'unité, soit un dictionnaire indépendant).<br />
<b><u>Ce qu'il faut faire pour remplir ce dictionnaire ?</u></b> <br />
<ol class="decimal"><li style="">Utiliser OnBeforeDrawItems pour l'effacer  <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">VisibleItems.Clear;</span></li><li style="">Utiliser OnBeforeDrawItem ou OnAfterDrawItem pour inscrire un rectangle dans la collection <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">VisibleItems.AddOrSetValue(AIndex,ControlListGauche._GetItemRect(AIndex))</span></li></ol><br />
<br />
Obtenir l'index de l'élément sur lequel est l'opération de Drag&amp;drop se termine se fait alors avec le code suivant.<br />
<div class="bbcode_container">
	<table width="100%" border="0" cellspacing="0" cellpadding="0"><tr>
	<td style="border: 0; padding: 0; text-align: left">Code  :</td>
	<td style="border: 0; padding: 0; text-align: right"><a href="#" onclick="return ano_selectionnerCode(this);">Sélectionner tout</a> -
	<a href="#" onclick="return ano_etendreCode(this);">Visualiser dans une fenêtre à part</a></td></tr></table>
	<pre class="bbcode_code" style="height:36px;">Index:=ControlListGauche._ItemAtPos(X,Y);</pre>
</div>À ce stade, je suis sûr que vous avez hâte de voir le code source. Je crois qu'il est temps que je dévoile que tous les programmes de cette série peuvent se retrouver dans un de mes dépôts GitHub, à<a href="https://github.com/Serge-Girard/TControlList" target="_blank"> cette adresse </a></blockquote>

]]></content:encoded>
			<dc:creator>SergioMaster</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/blogs/138527-sergiomaster/b10098/delphi-vcl-carnet-plongees-tcontrollist-dragdrop/</guid>
		</item>
	</channel>
</rss>
