Bonjour à tous,
On met la valeur dbEditing à vrai Pour modifier les enregistrements d'une table dans un DBGrid.
Est il possible d'autoriser la modification sur par exemple une seule colonne et l'empêcher sur les autres ?
Merci de votre aide
Version imprimable
Bonjour à tous,
On met la valeur dbEditing à vrai Pour modifier les enregistrements d'une table dans un DBGrid.
Est il possible d'autoriser la modification sur par exemple une seule colonne et l'empêcher sur les autres ?
Merci de votre aide
Property ReadOnly de chaque TColumn
A ne pas confondre avec le ReadOnly du TDBGrid
Perso, je préfère dans ce cas conservé un TDBGrid non éditable (surtout si j'ai des OnDraw pour la coloration) et founir une edition via un Editeur géré au OnCellClick
Je met au bout de ma colonne un bouton "..." et si l'on clique dessus cela lance un editeur pour le moment, je n'ai traduit en DelphiX2 que le DateTime et le Combo
Un InputQuery peut faire largement l'affaire pour un texte libre
Voici le code que j'utilise
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402 //------------------------------------------------------------------------------ (* SoLuTions is an Versatile Library for Delphi - * - * Copyright ou © ou Copr. "SLT Solutions", (2006) - * contributeur : ShaiLeTroll (2007) - Passage en Classe d'un code procédural - * contributeur : ShaiLeTroll (2012) - Renommage Fichier et Correction XE2 - * contributeur : ShaiLeTroll (2012) - Gestion des Styles sous C++BuilderXE2 - * contributeur : ShaiLeTroll (2012) - Documentation Insight - * contributeur : ShaiLeTroll (2014) - Traduction du code C++Builder vers DelphiXE2 * - * ShaiLeTroll@gmail.com - * - * Ce logiciel est un programme informatique servant à aider les développeurs - * Delphi avec une bibliothèque polyvalente, adaptable et fragmentable. - * - * Ce logiciel est régi par la licence CeCILL-C soumise au droit français et - * respectant les principes de diffusion des logiciels libres. Vous pouvez - * utiliser, modifier et/ou redistribuer ce programme sous les conditions - * de la licence CeCILL-C telle que diffusée par le CEA, le CNRS et l'INRIA - * sur le site "http://www.cecill.info". - * - * En contrepartie de l'accessibilité au code source et des droits de copie, - * de modification et de redistribution accordés par cette licence, il n'est - * offert aux utilisateurs qu'une garantie limitée. Pour les mêmes raisons, - * seule une responsabilité restreinte pèse sur l'auteur du programme, le - * titulaire des droits patrimoniaux et les concédants successifs. - * - * A cet égard l'attention de l'utilisateur est attirée sur les risques - * associés au chargement, à l'utilisation, à la modification et/ou au - * développement et à la reproduction du logiciel par l'utilisateur étant - * donné sa spécificité de logiciel libre, qui peut le rendre complexe à - * manipuler et qui le réserve donc à des développeurs et des professionnels - * avertis possédant des connaissances informatiques approfondies. Les - * utilisateurs sont donc invités à charger et tester l'adéquation du - * logiciel à leurs besoins dans des conditions permettant d'assurer la - * sécurité de leurs systèmes et ou de leurs données et, plus généralement, - * à l'utiliser et l'exploiter dans les mêmes conditions de sécurité. - * - * Le fait que vous puissiez accéder à cet en-tête signifie que vous avez - * pris connaissance de la licence CeCILL-C, et que vous en avez accepté les - * termes. - * - *----------------------------------------------------------------------------*) unit SLT.Controls.VCL.DBGridsEx; interface uses System.Classes, System.SysUtils, System.Types, Vcl.Grids, Vcl.DBGrids, Vcl.Themes, Vcl.Graphics, Data.DB, Winapi.Windows; type /// <summary>Erreur liée à l'assistant TDBGridSLTAssistant de la classe TDBGrid</summary> EDBGridSLTAssistantError = class(Exception); /// <summary>Assistance de la classe TDBGrid </summary> /// <remarks>Le TDBGridSLTAssistant n'est pas un class helper car lors de sa création en 2002 sous Delphi 5, le code était procédural, /// lors de la refonte en classe en 2007 et 2012, les versions utilisées était Delphi 7 et C++Builder 2007 puis C++Builder XE2. /// <para>Reprise en Delphi XE2 (en 2014) en s'inspirant du concept des Assistances de classes (Class Helper) du Delphi /// tout en conservant une approche OO sous la forme d'une classe externe plus élégant et explicite que les véritables "class helper".</para></remarks> TDBGridSLTAssistant = class(TObject) strict private type TDBGridHack = class(TDBGrid); private // Membres privés FDBGrid: TDBGrid; public // Constructeurs constructor Create(ADBGrid: TDBGrid); overload; constructor Create(Sender: TObject); overload; /// <summary>EditButtonInputDatePicker fournit un assistant d'implémentation d'un TDBGrid.OnEditButtonClick</summary> function EditButtonInputDatePicker(const Msg: string; AField: TField): Boolean; /// <summary>EditButtonInputCombo fournit un assistant d'implémentation d'un TDBGrid.OnCellClick gérant manuellement un d'Ellipis avec une grille en ReadOnly</summary> /// <param name="Msg">descriptif de la liste déroulante</param> /// <param name="APickList">Cela fourni la liste déroulante</param> /// <param name="APickListIndex">Cela fourni la valeur courante</param> /// <returns>Indique qu'élément a été selectionné dans la liste déroulante</returns> function ShowCombo(const Msg: string; APickList: TStrings; var APickListIndex: Integer): Boolean; /// <summary>DrawCheckBox fournit un assistant d'implémentation d'un TDBGrid.OnDrawColumnCell qui dessine une case à cocher centrée dans la zone définie par ARect</summary> /// <param name="ARect">Zone à dessiner</param> /// <param name="AChecked">Etat de la case à cocher</param> /// <param name="AEnabled">la case à cocher est-elle active</param> /// <param name="ABackgroundColor">Couleur de fond, clNone pour utiliser la couleur du thème</param> procedure DrawCheckBox(const ARect: TRect; AChecked: Boolean; AEnabled: Boolean = True; ABackgroundColor: TColor = clNone); /// <summary>DrawEllipsisButton fournit un assistant d'implémentation d'un TDBGrid.OnDrawColumnCell qui dessine un bouton '...' dans la zone définie par ARect</summary> /// <param name="ARect">Zone à dessiner, la taille et l'alignement sont calculés automatiquement</param> /// <param name="ABackgroundColor">Couleur de fond, clNone pour utiliser la couleur du thème</param> /// <param name="AColumn">La colonne dont l'on souhaite avoir un bouton '...'</param> procedure DrawEllipsisButton(const ARect: TRect; ABackgroundColor: TColor = clNone; AColumn: TColumn = nil); /// <summary>GetColumnScreenRect fournit un assistant d'implémentation d'un TDBGrid.OnCellClick qui donne la position et dimension de la cellule</summary> /// <param name="AColumn">La colonne dont l'on souhaite connaitre la position</param> /// <returns>la position du bouton en coordonnées écran de la grille TDBGrid possédant cette TColumn, ces coordonnées écran sont compatibles avec le curseur de la souris idéal pour la fonction PtInRects.</returns> function GetColumnScreenRect(const AColumn: TColumn): TRect; /// <summary>GetEllipsisButtonRect fournit un assistant d'implémentation d'un TDBGrid.OnCellClick qui donne la position théorique d'un bouton '...'</summary> /// <param name="AColumn">La colonne dans lequel pourrait exister un bouton dît ellipse, la taille et l'alignement sont calculés automatiquement</param> /// <returns>la position du bouton en coordonnées écran de la grille TDBGrid possédant cette TColumn, ces coordonnées écran sont compatibles avec le curseur de la souris idéal pour la fonction PtInRects.</returns> function GetEllipsisButtonScreenRect(const AColumn: TColumn): TRect; /// <summary>DrawTextWithBackgroundColor fournit un assistant d'implémentation d'un TDBGrid.OnDrawColumnCell qui dessine un texte et un fond coloré dans la zone définie par ARect</summary> /// <param name="ABackgroundColor">Couleur de fond, la couleur inverse sera utilisé pour le texte pour garantir le constrate</param> /// <param name="ARect">Zone à dessiner</param> /// <param name="AColumn">Indique la colonne concerné cela donne accès à la donnée via Field et aux informations tel que Alignment</param> /// <param name="AState">Le paramètre AState indique si la cellule a la focalisation et si la cellule est une cellule fixe de la partie immobile de la grille</param> procedure DrawTextWithBackgroundColor(ABackgroundColor: TColor; const ARect: TRect; AColumn: TColumn; AState: TGridDrawState); /// <summary>GetThemedBackgroundColor renvoie la couleur de fond d'une TDBGrid dans le thème actif</summary> function GetThemedBackgroundColor(): TColor; // Propriétés property DBGrid: TDBGrid read FDBGrid; end; implementation uses SLT.Controls.VCL.DialogsEx, SLT.Controls.VCL.GraphicsEx; const ERR_UNASSISTED_CLASS = 'La Classe d''Assistance %s ne prend pas en charge la classe %s mais la classe %s'; { TDBGridSLTAssistant } //------------------------------------------------------------------------------ constructor TDBGridSLTAssistant.Create(ADBGrid: TDBGrid); begin inherited Create(); FDBGrid := ADBGrid; end; //------------------------------------------------------------------------------ constructor TDBGridSLTAssistant.Create(Sender: TObject); begin inherited Create(); if Assigned(Sender) then begin if Sender is TDBGrid then FDBGrid := TDBGrid(Sender) else raise EDBGridSLTAssistantError.CreateFmt(ERR_UNASSISTED_CLASS, [ClassName(), Sender.ClassName(), TDBGrid.ClassName()]); end else raise EDBGridSLTAssistantError.CreateFmt(ERR_UNASSISTED_CLASS, [ClassName(), '[nil]', TDBGrid.ClassName()]) end; //------------------------------------------------------------------------------ procedure TDBGridSLTAssistant.DrawCheckBox(const ARect: TRect; AChecked: Boolean; AEnabled: Boolean = True; ABackgroundColor: TColor = clNone); var uState: UINT; tbState: TThemedButton; Details: TThemedElementDetails; StyleColor: TColor; Buffer: Vcl.Graphics.TBitmap; BufferRect: TRect; begin if StyleServices.Enabled then begin // Un bug sur DrawElement d'un TThemedButton dans un DBGrid provoque sur les thèmes foncés une perte de la couleur de fond ! // En attendant une meilleure solution, j'utilise un Buffer temporaire pour dessiner le ThemedButton CheckBox Buffer := Vcl.Graphics.TBitmap.Create(); try BufferRect := Rect(0, 0, ARect.Width, ARect.Height); Buffer.SetSize(BufferRect.Width, BufferRect.Height); if ABackgroundColor = clNone then begin // On dessine un fond normal assurant normalement un bon constrate avec la CheckBox Details := StyleServices.GetElementDetails(tgCellNormal); StyleServices.GetElementColor(Details, ecFillColor, StyleColor); end else StyleColor := ABackgroundColor; // Force un fond opaque pour cacher le texte ! Buffer.Canvas.Brush.Color := StyleColor; Buffer.Canvas.Brush.Style := bsSolid; Buffer.Canvas.FillRect(BufferRect); tbState := tbCheckBoxUncheckedNormal; if AChecked then tbState := tbCheckBoxCheckedNormal; if not AEnabled then begin if AChecked then tbState := tbCheckBoxCheckedDisabled else tbState := tbCheckBoxUncheckedDisabled; end; Details := StyleServices.GetElementDetails(tbState); StyleServices.DrawElement(Buffer.Canvas.Handle, Details, BufferRect, BufferRect); // Dessin final DBGrid.Canvas.Draw(ARect.Left, ARect.Top, Buffer); finally Buffer.Free(); end; end else begin uState := DFCS_BUTTONCHECK; if AChecked then uState := uState or DFCS_CHECKED; if not AEnabled then uState := uState or DFCS_INACTIVE; DBGrid.Canvas.FillRect(ARect); DrawFrameControl(DBGrid.Canvas.Handle, ARect, DFC_BUTTON, uState); end; end; //------------------------------------------------------------------------------ procedure TDBGridSLTAssistant.DrawEllipsisButton(const ARect: TRect; ABackgroundColor: TColor = clNone; AColumn: TColumn = nil); var Details: TThemedElementDetails; StyleColor: TColor; Buffer: Vcl.Graphics.TBitmap; BufferRect, ButtonRect: TRect; BufferWidth, ButtonWidth: Integer; W, X, Y: Integer; begin // j'utilise un Buffer temporaire pour dessiner le ThemedButton sur un fond coloré et ses trois points Buffer := Vcl.Graphics.TBitmap.Create(); try ButtonWidth := GetSystemMetrics(SM_CXVSCROLL); BufferWidth := ButtonWidth + 2; BufferRect := Rect(0, 0, BufferWidth, ARect.Height); Buffer.SetSize(BufferRect.Width, BufferRect.Height); if ABackgroundColor = clNone then begin // On dessine un fond normal assurant normalement un bon constrate avec le bouton '...' Details := StyleServices.GetElementDetails(tgCellNormal); StyleServices.GetElementColor(Details, ecFillColor, StyleColor); end else StyleColor := ABackgroundColor; // Force un fond opaque pour cacher le texte ! Buffer.Canvas.Brush.Color := StyleColor; Buffer.Canvas.Brush.Style := bsSolid; Buffer.Canvas.FillRect(BufferRect); ButtonRect := BufferRect; InflateRect(ButtonRect, -1, -1); if StyleServices.Enabled then begin Details := StyleServices.GetElementDetails(tgEllipsisButtonNormal); StyleServices.DrawElement(Buffer.Canvas.Handle, Details, ButtonRect); end else DrawEdge(Buffer.Canvas.Handle, ButtonRect, EDGE_RAISED, BF_RECT or BF_MIDDLE); // Dessine les trois points // Centrage X := BufferRect.Width div 2; Y := BufferRect.Height div 2; W := ButtonWidth shr 3; if W = 0 then W := 1; // Point central PatBlt(Buffer.Canvas.Handle, X, Y, W, W, BLACKNESS); // Point de gauche PatBlt(Buffer.Canvas.Handle, X - (W * 2), Y, W, W, BLACKNESS); // Point de droite PatBlt(Buffer.Canvas.Handle, X + (W * 2), Y, W, W, BLACKNESS); // Dessin final if not DBGrid.UseRightToLeftAlignment and (not Assigned(AColumn) or ((AColumn.Alignment <> taRightJustify) and not (AColumn.Field is TNumericField))) then DBGrid.Canvas.Draw(ARect.Left + ARect.Width - BufferWidth, ARect.Top, Buffer) else DBGrid.Canvas.Draw(ARect.Left, ARect.Top, Buffer); finally Buffer.Free(); end; end; //------------------------------------------------------------------------------ procedure TDBGridSLTAssistant.DrawTextWithBackgroundColor(ABackgroundColor: TColor; const ARect: TRect; AColumn: TColumn; AState: TGridDrawState); var vText: string; vRect: TRect; begin with DBGrid.Canvas do begin // Force un fond opaque pour cacher le texte ! Brush.Style := bsSolid; Brush.Color := ColorToRGB(ABackgroundColor); FillRect(ARect); // TextRect encapsule DraxTextEx et est aussi pénible avec ses paramètres in-out ! vRect := ARect; vText := AColumn.Field.DisplayText; Font.Color := TCanvasSLTAssistant.GetConstratedColor(ABackgroundColor); // Couleur de luminosité inverse : Contraste garanti pour les couleurs claires ou foncées // DT_CENTER Centers text horizontally in the rectangle. // DT_VCENTER Centers text vertically. This value is used only with the DT_SINGLELINE value. if AColumn.Alignment = taLeftJustify then TextRect(vRect, vRect.Left + 2, vRect.Top + 2, vText) else if AColumn.Alignment = taCenter then TextRect(vRect, vText, [tfCenter, tfSingleLine, tfVerticalCenter]) else TextRect(vRect, vText, [tfRight, tfSingleLine, tfVerticalCenter]); if (gdRowSelected in AState) or ((dgRowSelect in DBGrid.Options) and (gdSelected in AState)) then begin // Pour ne pas dessiner les bords de focus entre les colonnes (inspiré des tricheries dans TCustomGrid.DrawCellHighlight) InflateRect(vRect, 1, 0); DrawFocusRect(vRect); end else if gdSelected in AState then DrawFocusRect(vRect); end; end; //------------------------------------------------------------------------------ function TDBGridSLTAssistant.EditButtonInputDatePicker(const Msg: string; AField: TField): Boolean; var Value: TDateTime; begin if not AField.IsNull then Value := AField.AsDateTime else Value := Date(); Result := TSLTMessageDlg.InputDateTime(Msg, Value, idtkDate); if Result then begin // Le AutoEdit ne fait pas effet sur un Ellipsis button ! if not (AField.DataSet.State in [dsEdit, dsInsert]) then AField.DataSet.Edit(); AField.AsDateTime := Value; end; end; //------------------------------------------------------------------------------ function TDBGridSLTAssistant.GetColumnScreenRect(const AColumn: TColumn): TRect; var Col, Row: Integer; begin Col := AColumn.Index; if dgIndicator in DBGrid.Options then Inc(Col); Row := TDBGridHack(DBGrid).Row; Result := TDBGridHack(DBGrid).CellRect(Col, Row); // CellRect ne renvoie pas de coordonnées écran malgré ce que dit l'aide ! Result.TopLeft := DBGrid.ClientToScreen(Result.TopLeft); Result.BottomRight := DBGrid.ClientToScreen(Result.BottomRight); InflateRect(Result, -1, -1); end; //------------------------------------------------------------------------------ function TDBGridSLTAssistant.GetEllipsisButtonScreenRect(const AColumn: TColumn): TRect; var ButtonWidth: Integer; begin Result := GetColumnScreenRect(AColumn); ButtonWidth := GetSystemMetrics(SM_CXVSCROLL); if not DBGrid.UseRightToLeftAlignment and (AColumn.Alignment <> taRightJustify) and not (AColumn.Field is TNumericField) then Result.Left := Result.Right - ButtonWidth else Result.Width := ButtonWidth; end; //------------------------------------------------------------------------------ function TDBGridSLTAssistant.GetThemedBackgroundColor(): TColor; var Details: TThemedElementDetails; begin if StyleServices.Enabled then begin Details := StyleServices.GetElementDetails(tgCellNormal); StyleServices.GetElementColor(Details, ecFillColor, Result); end else Result := clWindow; end; //------------------------------------------------------------------------------ function TDBGridSLTAssistant.ShowCombo(const Msg: string; APickList: TStrings; var APickListIndex: Integer): Boolean; begin Result := TSLTMessageDlg.InputCombo(Msg, APickList, APickListIndex); end; end.