| auteur : Alacazam | Surchargeons la méthode OnDrawCell : cette méthode est appelée pour chaque cellule devant être (re)dessinée.
Attention : Les attributs Col, Row, Rect et State concernent donc la cellule en train d'être dessinée, et non la cellule courante (que vous sélectionnez par exemple avec votre souris).
TColor CLTitre = clBtnFace, CLFond = clYellow, CLSelection = clRed;
AnsiString s = StringGrid1- > Cells[ACol][ARow];
if (ACol < StringGrid1- > FixedCols | | ARow < StringGrid1- > FixedRows) {
StringGrid1- > Canvas- > Brush- > Color = CLTitre;
StringGrid1- > Canvas- > FillRect (Rect);
StringGrid1- > Canvas- > Font- > Style = StringGrid1- > Canvas- > Font- > Style < < fsBold;
StringGrid1- > Canvas- > TextRect (
Rect,
(Rect.Right + Rect.Left - StringGrid1- > Canvas- > TextWidth (s)) / 2 ,
(Rect.Top + Rect.Bottom - StringGrid1- > Canvas- > TextHeight (s)) / 2 ,
s);
}
else if (State.Contains (gdSelected)) {
StringGrid1- > Canvas- > Brush- > Color = CLSelection;
StringGrid1- > Canvas- > FillRect (Rect);
StringGrid1- > Canvas- > Font- > Color = clWhite;
StringGrid1- > Canvas- > TextRect (Rect, Rect.Left + 1 , Rect.Top + 1 , s);
}
else {
StringGrid1- > Canvas- > Brush- > Color = CLFond;
StringGrid1- > Canvas- > FillRect (Rect);
StringGrid1- > Canvas- > TextRect (Rect, Rect.Left + 1 , Rect.Top + 1 , s);
}
|
N.B. Pour centrer un texte dans un rectangle, on égale les coordonnées du centre du rectangle et celles du centre du texte.
|
| auteur : Alacazam | Le but est donc tout simplement d'afficher le texte de votre cellule sur plusieurs lignes, s'il est trop long par exemple, ou simplement pour améliorer la présentation de vos données.
Le principe :
- Utiliser un TMemo invisible de la largeur de la case, et le laisser découper votre texte (propriété WordWrap à true).
- Récupérer les n lignes du TMemo une par une, et les afficher dans des rectangles n fois plus petits (en hauteur).
N.B. Si vous ne maitrisez pas trop le OnDrawCell ou l'utilisation du TCanvas de la grille, je vous conseille de lire d'abord Comment personnaliser un ensemble de cellules sans modifier toute la grille dans un TStringGrid ?.
# include <math.hpp>
TMemo * Memo = new TMemo (this );
Memo- > Visible = false ;
Memo- > Parent = this ;
Memo- > Lines- > Text = StringGrid1- > Cells[ACol][ARow];
Memo- > Width = StringGrid1- > ColWidths[ACol];
int Cell_Height = Rect.Bottom - Rect.Top, Ligne_Nbr = Memo- > Lines- > Count;
Ligne_Nbr = Min (Ligne_Nbr, (Rect.Bottom - Rect.Top) / StringGrid1- > Canvas- > TextHeight (" " ) + 1 );
for (int i = 0 ; i < Ligne_Nbr ; i+ + )
{
TRect R = Rect;
AnsiString Text_i = Memo- > Lines- > Strings[i];
R.Top = Rect.Top + i * Cell_Height / Ligne_Nbr;
R.Bottom = Rect.Top + (i + 1 ) * Cell_Height / Ligne_Nbr;
StringGrid1- > Canvas- > TextRect (
R,
(R.Right + R.Left - StringGrid1- > Canvas- > TextWidth (Text_i)) / 2 ,
(R.Top + R.Bottom - StringGrid1- > Canvas- > TextHeight (Text_i)) / 2 ,
Text_i);
}
delete Memo;
|
Signalons que si vous souhaitez forcer un retour à la ligne après un mot, vous n'avez qu'à le faire suivre de "\n", qui sera traité correctement par le TMemo.
|
lien : Comment personnaliser un ensemble de cellules sans modifier toute la grille dans un TStringGrid ?
|
| auteur : Nono40 |
La roulette n'est pas gérée correctement par défaut dans le composant TDBGrid. Pour qu'elle soit prise en compte il faut suivre la méthode suivante, elle est basée sur la dérivation de la méthode WindowProc de la grille afin de gérer le message WM_MOUSEWHEEL.
Dans le header de la fiche, ajouter :
private :
TWndMethod OldWindowProc;
void __fastcall DBGridNewWindowProc (TMessage & Msg);
|
Puis, dans le corps du gestionnaire d'évènements OnCreate (dans le .cpp) :
OldWindowProc = DBGrid1- > WindowProc;
DBGrid1- > WindowProc = DBGridNewWindowProc;
|
Enfin, dans le .cpp :
void __fastcall TForm1:: DBGridNewWindowProc (TMessage & Msg)
{
if (Msg.Msg = = WM_MOUSEWHEEL)
{
if (DBGrid1- > DataSource- > DataSet- > Active)
{
if (short (Msg.WParamHi) < 0 )
{
DBGrid1- > DataSource- > DataSet- > Next ();
}
else
{
DBGrid1- > DataSource- > DataSet- > Prior ();
}
}
return ;
}
OldWindowProc (Msg);
}
|
Remarque : Le code ci-dessus suppose que DBGrid1->DataSource et DBGrid1->DataSource->DataSet soient assignés. Si on se trouve dans un contexte où l'on n'est pas sûr qu'ils le soient, il faut le vérifier.
|
| auteurs : pottiez, blondelle, LadyWasky |
Il suffit de rendre publiques les méthodes DeleteRow et DeleteColumn de la classe TCustomGrid dont hérite la classe TStringGrid à travers le transtypage de cette dernière en une classe dérivée déclarée dans la même unité :
class TPublicStringGrid: public TCustomGrid
{
public :
using TCustomGrid:: DeleteRow;
using TCustomGrid:: DeleteColumn;
} ;
((TPublicStringGrid* )StringGrid1)- > DeleteRow (2 );
((TPublicStringGrid* )StringGrid1)- > DeleteColumn (1 );
|
|
| auteurs : Sunchaser, MiGoN |
Pour simuler la sélection multiple dans cet objet, il faudra intercepter des évènements clavier et ainsi il faut que la propriété KeyPreview de la TForm contenant la grille soit à true.
Ensuite, il faut travailler sur les évènements suivants :
- OnClick
- OnDrawCell
- OnKeyDown
- OnKeyUp
- OnMouseMove
Dans le .h |
Private :
TStringGrid * pGrille;
TStringList * pListeIndex;
bool MultiSelect;
|
Dans le .cpp |
void __fastcall TForm1:: FormCreate (TObject * Sender)
{
MultiSelect = false ;
}
void __fastcall TForm1:: FormClose (TObject * Sender, TCloseAction & Action)
{
if (pListeIndex ! = NULL )
delete pListeIndex;
}
|
Interception des évènements clavier |
void __fastcall TForm1:: StringGridKeyDown (TObject * Sender, WORD & Key,
TShiftState Shift)
{
if (Key = = VK_CONTROL)
{
MultiSelect = true ;
if (pListeIndex = = NULL )
{
pListeIndex = new TStringList ();
}
}
}
void __fastcall TForm1:: StringGridKeyUp (TObject * Sender, WORD & Key,
TShiftState Shift)
{
if (Key = = VK_CONTROL)
{
MultiSelect = false ;
if (! pListeIndex = = NULL )
{
pListeIndex- > Clear ();
}
}
}
|
Dessin des éléments dans la grille |
void __fastcall TForm1:: StringGridDrawCell (TObject * Sender, int ACol,
int ARow, TRect & Rect, TGridDrawState State)
{
pGrille = (TStringGrid* )Sender;
if (! pListeIndex = = NULL )
{
if (pListeIndex- > IndexOf (ARow)! = - 1 )
{
pGrille- > Canvas- > Brush- > Color = clHighlight;
pGrille- > Canvas- > Font- > Color = clWhite;
pGrille- > Canvas- > FillRect (Rect);
pGrille- > Canvas- > TextRect (Rect, Rect.Left+ 2 , Rect.Top+ 2 , pGrille- > Cells[ACol][ARow]);
}
}
else
{
pGrille- > Canvas- > Brush- > Color = clWindow;
pGrille- > Canvas- > Font- > Color = clBlack;
}
}
|
NB : Cet évènement fonctionne quelle que soit la valeur de la propriété DefaultDraw de la grille.
Sélection d'une ligne |
void __fastcall TForm1:: StringGridClick (TObject * Sender)
{
pGrille = (TStringGrid* )Sender;
if (MultiSelect = = true )
{
pListeIndex- > Add (pGrille- > Row);
}
pGrille- > Repaint ();
}
|
void __fastcall TForm1:: StringGridMouseMove (TObject * Sender,
TShiftState Shift, int X, int Y)
{
pGrille = (TStringGrid* )Sender;
pGrille- > SetFocus ();
}
|
NB : Sans cet évènement, cette astuce pour simuler la multiselection ne fonctionne pas dès le premier click.
|
| auteur : pottiez |
Pour empêcher l'édition des cellules du TStringGrid, il faut jouer sur la propriété option de celui-ci. En effet, dans les options du TStringGrid, on peut cocher l'option goEditing qui permet d'autoriser ou non l'édition du TStringGrid.
Il vous suffit alors de vérifier quelle est la cellule que l'utilisateur souhaite éditer, et autoriser ainsi cette édition ou non. Cela se fait grâce à l'évènement OnSelectCell().
Cela donne ce code (ici pour vérouiller la cellule de coordonné 1;1) :
if ((ACol = = 1 ) & & (ARow = = 1 )){
StringGrid1- > Options > > goEditing;
} else {
StringGrid1- > Options < < goEditing;
}
|
Si vous voulez vérouiller plusieurs cellules, je vous propose d'utiliser un vecteur et de vérifier chaque valeur du vecteur grâce à un boucle
int vectCoordonnee[5 ][2 ] = { { 1 ,1 } ,{ 2 ,5 } ,{ 3 ,1 } ,{ 1 ,4 } ,{ 1 ,2 } } ;
int i ;
StringGrid1- > Options < < goEditing;
for (i= 0 ;i< 5 ;i+ + ){
if ((ACol = = vectCoordonnee[i][0 ]) & & (ARow = = vectCoordonnee[i][1 ])){
StringGrid1- > Options > > goEditing;
}
}
|
|
| auteurs : blondelle, Pedro, LadyWasky |
Il suffit de rendre publiques les méthodes MoveRow et MoveColumn de la classe TCustomGrid dont hérite la classe TStringGrid à travers le transtypage de cette dernière en une classe dérivée déclarée dans la même unité :
void __fastcall TForm1:: Button1Click (TObject * Sender)
{
class TPublicStringGrid: public TCustomGrid
{
public :
using TCustomGrid:: MoveRow;
using TCustomGrid:: MoveColumn;
} ;
((TPublicStringGrid* )StringGrid1)- > MoveRow (0 ,1 );
((TPublicStringGrid* )StringGrid1)- > MoveColumn (0 ,1 );
}
|
Il est a noter que si les cellules vers lesquelles on déplace avec MoveRow ou MoveColumn ne sont pas vides, les valeurs seront permutées avec celles que l'on veut déplacer.
|
| auteurs : blondelle, rbag | Pour cela, il faut activer l'option goAlwaysShowEditor et ajouter le code suivant dans l'événement OnKeyDown :
void __fastcall TForm1:: StringGrid1KeyDown (TObject * Sender, WORD & Key,
TShiftState Shift)
{
if (Key = = VK_RETURN)
{
StringGrid1- > Cells[StringGrid1- > Col][StringGrid1- > Row] = StringGrid1- > Cells[StringGrid1- > Col][StringGrid1- > Row] + sLineBreak;
}
}
|
et dans l'événement OnDrawCell :
void __fastcall TForm1:: StringGrid1DrawCell (TObject * Sender, int ACol,
int ARow, TRect & Rect, TGridDrawState State)
{
if (State.Contains (gdFixed))
{
StringGrid1- > Canvas- > Brush- > Color = clBtnFace;
}
else if (State.Contains (gdSelected))
{
StringGrid1- > Canvas- > Brush- > Color = clNavy;
}
else
{
StringGrid1- > Canvas- > Brush- > Color = clWhite;
}
StringGrid1- > Canvas- > FillRect (Rect);
if (State.Contains (gdSelected))
{
SetTextColor (Canvas- > Handle, clWhite);
}
else
{
SetTextColor (Canvas- > Handle, clBlack);
}
DrawText (StringGrid1- > Canvas- > Handle, (StringGrid1- > Cells[ACol][ARow]).c_str (), - 1 , & Rect, DT_NOPREFIX | DT_WORDBREAK );
}
|
|
| auteurs : blondelle, Nono40 |
Voici le code à appliquer pour mettre une image en fond des cellules blanches d'un TStringGrid. L'image est contenue dans un Bitmap, mais elle peut aussi être contenue dans un TImage. Cette procédure gère le déplacement du fond de l'image si l'utilisateur se sert des barres de défilement :
void __fastcall TForm1:: StringGrid1DrawCell (TObject * Sender, int ACol,
int ARow, TRect & Rect, TGridDrawState State)
{
int i, j, X, Y;
TRect R;
if (State.Contains (gdFixed))
{
StringGrid1- > Canvas- > Brush- > Color = clBtnFace;
StringGrid1- > Canvas- > Brush- > Style = bsSolid;
StringGrid1- > Canvas- > FillRect (Rect);
}
else if (State.Contains (gdSelected))
{
StringGrid1- > Canvas- > Brush- > Color = clNavy;
StringGrid1- > Canvas- > Brush- > Style = bsSolid;
StringGrid1- > Canvas- > FillRect (Rect);
}
else
{
X = 0 ;
for (i = StringGrid1- > FixedCols + 1 ; i <= ACol; i+ + ) (X+ + , StringGrid1- > ColWidths [i]);
{
Y = 0 ;
for (i = StringGrid1- > FixedRows + 1 ; i <= ARow; i+ + ) (Y+ + , StringGrid1- > RowHeights[i]);
{
R.Left = X;
R.Right = X + Rect.Right - Rect.Left;
R.Top = Y;
R.Bottom = Y + Rect.Bottom - Rect.Top;
Image1- > Visible = false ;
Image1- > Picture- > Bitmap- > LoadFromFile (" C:\\Documents and Settings\\toto\\Mes documents\\Mes images\\Massiv10\\Massiv10\\Bitmaps\\Arrow\\arcarrow1.bmp " );
StringGrid1- > Canvas- > CopyRect (Rect, Image1- > Picture- > Bitmap- > Canvas, R);
StringGrid1- > Canvas- > Brush- > Style = bsClear;
}
}
}
if (State.Contains (gdSelected))
{
SetTextColor (StringGrid1- > Canvas- > Handle, clWhite);
}
else
{
SetTextColor (StringGrid1- > Canvas- > Handle, clBlack);
}
DrawText (StringGrid1- > Canvas- > Handle, (StringGrid1- > Cells[ACol][ARow]).c_str (), - 1 , & Rect, DT_NOPREFIX );
}
|
MonBitMap est un objet de type TBitMap qui doit avoir été chargé avec l'image. L'image doit être suffisamment grande pour couvrir le fond du TStringGrid.
|
| auteurs : blondelle, Nono40 |
Le code suivant permet de centrer le texte dans les cellules d'un TStringGrid. Le centrage est à la fois vertical et horizontal. Le dessin est ici effectué avec l'API de Windows car la fonction TextOut du canevas des composants ne permet pas directement le centrage.
void __fastcall TForm1:: StringGrid1DrawCell (TObject * Sender, int ACol,
int ARow, TRect & Rect, TGridDrawState State)
{
if (State.Contains (gdFixed))
{
StringGrid1- > Canvas- > Brush- > Color = clBtnFace;
}
else if (State.Contains (gdSelected))
{
StringGrid1- > Canvas- > Brush- > Color = clNavy;
}
else
{
StringGrid1- > Canvas- > Brush- > Color = clWhite;
}
StringGrid1- > Canvas- > FillRect (Rect);
if (State.Contains (gdSelected))
{
StringGrid1- > Font- > Color = clWhite;
}
else
{
StringGrid1- > Font- > Color = clBlack;
}
DrawText (StringGrid1- > Canvas- > Handle, (StringGrid1- > Cells[ACol][ARow]).c_str (), - 1 , & Rect, DT_CENTER | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE );
}
|
|
| auteurs : blondelle, Nono40 |
Le code suivant permet d'écrire le texte d'une cellule d'un TStringGrid sur plusieurs lignes.
void __fastcall TForm1:: StringGrid1DrawCell (TObject * Sender, int ACol,
int ARow, TRect & Rect, TGridDrawState State)
{
if (State.Contains (gdFixed))
{
StringGrid1- > Canvas- > Brush- > Color = clBtnFace;
}
else if (State.Contains (gdSelected))
{
StringGrid1- > Canvas- > Brush- > Color = clNavy;
}
else
{
StringGrid1- > Canvas- > Brush- > Color = clWhite;
}
StringGrid1- > Canvas- > FillRect (Rect);
if (State.Contains (gdSelected))
{
SetTextColor (StringGrid1- > Canvas- > Handle, clWhite);
}
else
{
SetTextColor (StringGrid1- > Canvas- > Handle, clBlack);
}
DrawText (StringGrid1- > Canvas- > Handle, (StringGrid1- > Cells[ACol][ARow]).c_str (), - 1 , & Rect, DT_CENTER | DT_NOPREFIX | DT_WORDBREAK);
}
|
|
Consultez les autres F.A.Q.
|
|