HotXLS peut placer un graphique directement sur une feuille de calcul, ancré à une plage de cellules, au lieu de le mettre sur une feuille de graphique dédiée. En termes BIFF8, cela signifie écrire une forme de dessin avec un enregistrement OBJ de type 5 et garer le sous-flux de graphique à la fin du flux d'enregistrements de la feuille, ce qui est exactement la disposition qu'Excel produit et exactement là où le lecteur s'attend à le trouver
La distinction importe à quiconque génère des rapports opérationnels. Une feuille de graphique est un bon logis pour un visuel de titres unique. Un détail mensuel par région veut le graphique à côté des nombres qu'il résume, sur la même feuille, dimensionné pour le bloc de cellules auquel il appartient, si bien que le lecteur défile une fois au lieu de changer d'onglet et de perdre le contexte
La lecture était déjà là, l'écriture non
L'asymétrie vaut la peine d'être nommée parce qu'elle façonne le travail. HotXLS savait déjà lire les graphiques embarqués : quand le flux d'enregistrements de la feuille contient un BOF marqué comme sous-flux de graphique, l'analyseur change de contexte, collecte les enregistrements de graphique, et au EOF de fermeture les rend à la forme de dessin que l'enregistrement OBJ avait introduite. Ce chemin avait été exercé par chaque classeur créé par Excel que la bibliothèque avait jamais ouvert
Ce qui manquait était le côté rédaction, et la conséquence utile est que le nouveau rédacteur avait une spécification précise à atteindre : produire la disposition d'octets que le lecteur existant rattache déjà. Il n'est pas de meilleur critère d'acceptation pour une fonctionnalité de format binaire qu'un lecteur écrit indépendamment que vous n'aviez pas le droit de modifier
De quoi un graphique embarqué est-il fait ?
Trois pièces doivent concorder. La couche de dessin fournit une forme de contrôle hôte, la couche objet fournit un enregistrement OBJ dont les données d'objet communes déclarent le type d'objet 5, et le flux d'enregistrements fournit le sous-flux de graphique lui-même. Les drapeaux d'option de l'enregistrement OBJ sont ceux qu'Excel écrit pour un cadre de graphique : positionné, verrouillé, ligne automatique et remplissage automatique, et c'est ce qui fait qu'un graphique embarqué se comporte comme un natif quand un utilisateur clique dessus
L'ancre mérite une remarque parce qu'elle est une source courante de bugs de décalage de un. L'API HotXLS prend des numéros de ligne et de colonne à base un, comme le reste de la bibliothèque, et l'ancre cliente écrite dans le fichier est à base zéro. La conversion se passe à l'intérieur de AddChartObject, si bien que les appelants restent dans le système de coordonnées qu'ils utilisent partout ailleurs, mais quiconque compare un dump hexadécimal à son propre appel doit se rappeler de quel côté de cette frontière il lit
var
Book: TXLSWorkbook;
Sheet: TXLSWorksheet;
Series: array[0..1] of TXLSChartSeriesInfo;
begin
Book := TXLSWorkbook.Create(nil);
try
Book.LoadFromFile('regional-sales.xls');
Sheet := Book.Sheets[0];
FillChar(Series, SizeOf(Series), 0);
Series[0].Name := 'Actual';
Series[0].Categories := 'Data!$A$2:$A$13';
Series[0].Values := 'Data!$B$2:$B$13';
Series[0].DataLabels.ShowValue := True;
Series[0].HasDataLabels := True;
Series[1].Name := 'Target';
Series[1].Categories := 'Data!$A$2:$A$13';
Series[1].Values := 'Data!$C$2:$C$13';
Series[1].SecondaryAxis := True;
// Ancré à E2:M20 sur cette feuille, à base un
Sheet.AddChartObject(xlsChartTypeColumn, 'Regional sales',
'Month', 'Amount', Series, 2, 5, 20, 13);
Book.SaveToFile('regional-sales-charted.xls');
finally
Book.Free;
end;
end;
Le FillChar sur le tableau de séries n'est pas décoratif. TXLSChartSeriesInfo transporte plusieurs sous-enregistrements optionnels, étiquettes de données, style par série, courbes de tendance et barres d'erreur, chacun gardé par un booléen, et un enregistrement partiellement initialisé sur la pile remettra à l'émetteur des drapeaux que personne n'a posés. Mettez le tableau à zéro, puis posez les champs voulus
Quelles références de séries le chemin embarqué accepte-t-il ?
Des plages simples de style A1 à l'intérieur du même classeur, et cette restriction est délibérée plutôt qu'un oubli. Chaque référence est résolue contre la liste des feuilles du classeur et transformée en index de référence externe dont les enregistrements de graphique ont besoin. Une plage nommée ou une référence à un classeur externe retombe sur un espace réservé avec une expression analysée de longueur nulle, si bien que le graphique s'écrit proprement mais que cette série particulière n'a pas de source de données tant que vous ne la pointez pas vers une plage
La raison est un arbitrage d'ingénierie direct. Le chemin complet de compilation de références existe sur la route des feuilles de graphique, emballé dans la couche de collection de feuilles, et le sortir proprement signifierait dupliquer une centaine de lignes de logique de résolution pour un cas rare en pratique. Un graphique embarqué trace presque toujours des cellules de sa propre feuille ou d'une feuille de données voisine. Les références nommées et externes sont couvertes sur le chemin des feuilles de graphique via AddChartSheet, donc rien n'est indisponible, juste atteint depuis un autre point d'entrée
Tout le reste du modèle de séries fonctionne à l'identique sur les deux routes. La liaison d'axe secondaire, les styles de ligne, remplissage et marqueur par série, les courbes de tendance, les barres d'erreur et les étiquettes de données font tous partie de TXLSChartSeriesInfo et s'émettent tous de la même façon, si bien qu'une définition de graphique peut passer d'un objet embarqué à une feuille de graphique avec seulement l'appel qui change. La mécanique des groupes d'axes derrière le drapeau d'axe secondaire est couverte dans les groupes d'axes secondaires à l'écriture BIFF
Pourquoi le titre du graphique se lisait-il en deux caractères ?
Parce qu'un compte de caractères a été passé là où un compte d'octets était attendu, et que les chaînes Unicode BIFF rendent cette erreur facile à écrire et difficile à voir. Une chaîne Unicode BIFF courte commence par un compte de caractères et un octet de drapeaux, et l'octet de drapeaux porte le bit de poids haut qui dit si la charge utile est d'un ou de deux octets par caractère. Lisez une charge utile de 16 bits avec le compte de caractères comme si c'était une longueur en octets et vous obtenez exactement la moitié de la chaîne : une série nommée Sales revient en Sa, et un titre de graphique se tronque pareillement parce que titres et étiquettes de séries partagent le chemin de décodage
Ce qui rend ce défaut notable est qu'il est revenu trois fois dans la même famille d'enregistrements, une fois dans les noms de courbes de tendance, une fois dans les noms de graphiques croisés dynamiques, et une fois dans les titres de graphique. Chaque occurrence ressemblait à un bug neuf dans une fonctionnalité neuve. Les trois étaient le même multiply manquant. La règle qui l'a enfin clos est mécanique et devrait être appliquée sans jugement : chaque fois que vous lisez une de ces chaînes, consultez d'abord le drapeau de poids haut et multipliez le compte de caractères par la largeur de charge utile avant de toucher au tampon. Les détails au niveau des enregistrements sont dans le décodage des comptes de caractères XLUnicodeString et du drapeau de poids haut
// Le graphique embarqué partage la couche de dessin avec les images et
// les formes, donc un dessin existant sur la feuille est préservé.
// AddChartObject renvoie l'index de l'objet créé
var
ObjIndex: Integer;
begin
ObjIndex := Sheet.AddChartObject(xlsChartTypeLine, 'Trend',
'Week', 'Units', Series, 2, 8, 18, 16);
if ObjIndex < 0 then
raise Exception.Create('chart object was not created');
end;
Où les graphiques embarqués se situent face aux alternatives
Trois routes existent et répondent à des questions différentes. Un objet graphique embarqué appartient à côté de ses données sur une feuille et c'est ce que veulent la plupart des rapports. Une feuille de graphique convient à un visuel de présentation unique et vous donne le chemin complet de compilation de références. Préserver tel quel un graphique existant d'un fichier chargé est la bonne réponse quand le classeur vient d'Excel avec un formatage que personne ne veut voir une bibliothèque réinterpréter ; ce comportement de pass-through est décrit dans les graphiques ChartML préservés et les graphiques combinés
Comme le graphique embarqué voyage sur la couche de dessin, il coexiste avec les images et les formes de la même feuille au lieu de les remplacer, et le modèle général de cette couche est couvert dans les graphiques, images et dessins dans HotXLS. Les trois routes sont livrées avec le composant tableur Delphi HotXLS, si bien que le choix porte sur l'allure que le rapport doit avoir plutôt que sur ce que la bibliothèque peut exprimer
Le point méthodologique est celui qui vaut d'être gardé. Quand une fonctionnalité de format binaire a un lecteur existant, construisez le rédacteur contre le lecteur plutôt que contre votre lecture de la spécification. Le lecteur encode des années de contact avec les fichiers que de vraies applications ont réellement produits, y compris les parties que la spécification énonce vaguement, et un rédacteur qui le satisfait a bien plus de chances de satisfaire Excel aussi