Squall_FF8 1 Posted yesterday at 10:55 AM (edited) Hey guys, I have a tDBGrid that I try to paint the selected row similar to the picture bellow. May you advise/share a snippet of how to do it? dgRowSelect is false! Edited yesterday at 11:04 AM by Squall_FF8 Share this post Link to post
Softacom | Company 9 Posted 9 hours ago There is no easy way to do it. Problem is that this feature is not supported "by design" in TDBGrid. Main issue is in this part of TCustomDBGrid.DrawCell: Value := ''; OldActive := FDataLink.ActiveRecord; try FDataLink.ActiveRecord := ARow; //<-- after this line, current cell is at current row anyway if Assigned(DrawColumn.Field) then Value := DrawColumn.Field.DisplayText; if HighlightCell(ACol, ARow, Value, AState) and DefaultDrawing then DrawCellHighlight(ARect, AState, ACol, ARow); if not Enabled then Font.Color := clGrayText; if FDefaultDrawing then WriteText(Canvas, ARect, 3, 2, Value, DrawColumn.Alignment, (DrawColumn.BidiMode = bdRightToLeft) and UseRightToLeftAlignmentForField(DrawColumn.Field, DrawColumn.Alignment)); if Columns.State = csDefault then DrawDataCell(ARect, DrawColumn.Field, AState); //<-- here we have event DrawColumnCell(ARect, ACol, DrawColumn, AState); //<-- here we have event finally FDataLink.ActiveRecord := OldActive; //<-- after this code, active row at right place again end; So when you try to check active row in event it's always return true. right way to check if current cell is in active row it's: if OldActive = FDataLink.ActiveRecord then but OldActive it's local variable so you don't have access to it. Only way to deal with it - it's make own descendant of TCustomDBGrid and reimplement DrawCell method. 1 Share this post Link to post
Squall_FF8 1 Posted 5 hours ago 3 hours ago, Softacom | Company said: There is no easy way to do it. Problem is that this feature is not supported "by design" in TDBGrid. So that is why I couldn't find the answer in my google search ... For me the problem is twofold: - Row/Col are private - no Row info in DrawColumnCell if we had that (which is quite reasonable for me), it is a matter of simple comparison. BYW Let say I implement a descendant and call it TMyGrid, is there an easy way to replace the TDBGrid in existing project? I tried to manually replace "Grid: TDBGrid;" in the source but it didnt work Share this post Link to post
Cristian Peța 111 Posted 5 hours ago 7 minutes ago, Squall_FF8 said: I tried to manually replace "Grid: TDBGrid;" in the source but it didnt work Have you replaced in both sources? .pas and .dfm? Share this post Link to post
Squall_FF8 1 Posted 5 hours ago (edited) 25 minutes ago, Cristian Peța said: Have you replaced in both sources? .pas and .dfm? Only in the .pas. I cant find in Delhi12 how to view the .dfm as text EDIT: found it and it works, Thanks!!! Edited 5 hours ago by Squall_FF8 Share this post Link to post
Cristian Peța 111 Posted 5 hours ago (edited) 3 minutes ago, Squall_FF8 said: how to view the .dfm as text Right-click on the form and in contextual menu select "View as text" EDIT: or Alt-F12 to switch between. Edited 5 hours ago by Cristian Peța Share this post Link to post
Softacom | Company 9 Posted 5 hours ago (edited) Yes, it’s not so hard to replace component. You need to follow next steps: 1. Create package with your new component and install it into Delphi (don’t forget to make package DesingnTime and make register procedure). We need it to make designer works. 2. Replace text ': TDBGrid'#13#10 with ': TMyGrid'#13#10 in *.dfm files 3. Replace text ': TDBGrid;'#13#10 with ': TMyGrid;'#13#10 in *.pas files 4. We need to add your pas-file with new type into interface uses section to let compiler find you new class. You can do it in a few ways, but I suggest, replace text ‘Vcl.DBGrids’ with ‘Vcl.DBGrids, MyNewGrid’ in *.pas files 5. If your project not single exe-file and use own bpl-files with this new grid, than you need to add new package into requires section. 6. If your project cannot compile after all this steps – maybe you will need to add path for this new pas-file into “search path” section in options of your project Edited 4 hours ago by Softacom | Company 1 Share this post Link to post
Squall_FF8 1 Posted 4 hours ago 8 minutes ago, Softacom | Company said: 2. Replace text ‘: TDBGrid#13#10’ with ‘: TMyGrid#13#10’ in *.dfm files 3. Replace text ‘: TDBGrid;#13#10’ with ‘: TMyGrid;#13#10’ in *.pas files That part is quite hacky ... When I change in the form and try to go back to pas, I get error in the IDE. The project compiles and works well, but I need to save first, close the project and then open it again Share this post Link to post
Softacom | Company 9 Posted 4 hours ago 1 minute ago, Squall_FF8 said: That part is quite hacky ... When I change in the form and try to go back to pas, I get error in the IDE. The project compiles and works well, but I need to save first, close the project and then open it again Yes, all text replaces must be done in same time (for IDE). That's why you need to do replace with some other tools, not in IDE it's self. You can use Notepad++ for example. Just don't forget adopt syntax of replacing for this tool (for example #13 in Delphi, in Notepad++ it's /n) Share this post Link to post
Cristian Peța 111 Posted 3 hours ago 56 minutes ago, Squall_FF8 said: That part is quite hacky ... When I change in the form and try to go back to pas, I get error in the IDE. First in pas then in dfm Share this post Link to post
aehimself 403 Posted 3 hours ago (edited) I'm using this code for alternating colors: Procedure TDBGrid.DrawColumnCell(Const Rect: TRect; DataCol: Integer; Column: TColumn; State: TGridDrawState); Var dataset: TDataSet; {$IFDEF HIDECOLLINESIFEMPTY} colline: Boolean; {$ENDIF} editcolor: TColor; hidefocus: Boolean; Begin dataset := Self.DataSource.DataSet; // This method is only being called on DATA cells, which only happens if there is a dataset connected. Therefore, no // need to perform an assigned check here. {$IFDEF HIDECOLLINESIFEMPTY} colline := True; {$ENDIF} hidefocus := Not (csDesigning In Self.ComponentState) And (gdSelected In State) And Not Self.Focused; If (dgMultiSelect In Self.Options) And (Self.SelectedRows.CurrentRowSelected) Then Begin End Else If dataset.IsEmpty Then Begin {$IFDEF HIDECOLLINESIFEMPTY} colline := False; {$ENDIF} editcolor := TStyleManager.ActiveStyle.GetStyleColor(scEdit); Self.Canvas.Brush.Color := editcolor; Self.Canvas.Font.Color := editcolor; End Else // This code imitates the highlight of the whole row even if RowSelect is disabled. Note that it needs MultiSelect to be enabled! // If Not (gdSelected In State) And grid.SelectedRows.CurrentRowSelected Then // grid.Canvas.Brush.Color := clHighLight // Else If (dataset.RecNo Mod 2 = 0) And ((State = []) Or hidefocus) Then Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scButtonDisabled) Else If (dataset.RecNo Mod 2 = 1) And hidefocus Then Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scEdit); If hidefocus Then Self.Canvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scCategoryButtonsGradientBase); {$IFDEF HIDECOLLINESIFEMPTY} If HIDECOLLINESIFEMPTY And colline And Not (dgColLines In Self.Options) Then Self.Options := Self.Options + [dgColLines] Else If HIDECOLLINESIFEMPTY And Not colline And (dgColLines In Self.Options) Then Self.Options := Self.Options - [dgColLines]; {$ENDIF} inherited; Self.DefaultDrawColumnCell(Rect, DataCol, Column, State); End; Supports VCL styles and works fine for a couple of years now. I used the "lazy" technique. Save this as uDBGrid.pas, add is to the uses clause of your form and in the declaration change "grdMyDBGrid: TDBGrid;" to "grdMyDBGrid: uDBGrid.TDBGrid". Since the class name is the same no modification in the dfm is necessary. Drawback is, it only works runtime. And it's hacky. Edited 3 hours ago by aehimself 1 Share this post Link to post
Squall_FF8 1 Posted 1 hour ago (edited) 2 hours ago, aehimself said: // This code imitates the highlight of the whole row even if RowSelect is disabled. Note that it needs MultiSelect to be enabled! // If Not (gdSelected In State) And grid.SelectedRows.CurrentRowSelected Then // grid.Canvas.Brush.Color := clHighLight Woah, you saved the day!!! I tried it and it works! That trick actually doesn't require to make a new class, install components, do hacky things!. It is enough in your app to write a handler for OnDrawColumnCell !!! Event the handler is almost the same: if not (gdSelected in State) and Grid.SelectedRows.CurrentRowSelected then Grid.Canvas.Brush.Color := TColor($FFFFA0) Edited 1 hour ago by Squall_FF8 Share this post Link to post
Squall_FF8 1 Posted 1 hour ago 3 hours ago, Softacom | Company said: Yes, it’s not so hard to replace component. You need to follow next steps: 1. Create package with your new component and install it into Delphi (don’t forget to make package DesingnTime and make register procedure). We need it to make designer works. 2. Replace text ': TDBGrid'#13#10 with ': TMyGrid'#13#10 in *.dfm files 3. Replace text ': TDBGrid;'#13#10 with ': TMyGrid;'#13#10 in *.pas files 4. We need to add your pas-file with new type into interface uses section to let compiler find you new class. You can do it in a few ways, but I suggest, replace text ‘Vcl.DBGrids’ with ‘Vcl.DBGrids, MyNewGrid’ in *.pas files 5. If your project not single exe-file and use own bpl-files with this new grid, than you need to add new package into requires section. 6. If your project cannot compile after all this steps – maybe you will need to add path for this new pas-file into “search path” section in options of your project Thank you very much for the solid advice! For completeness and people with the same problem, the solution is is simple: type TDBHackGrid = class(TDBGrid) public property Col; property Row; end; Then in your app you just compare: if Row = HackGrid.DataSource.RecNo then // code for coloring the row Share this post Link to post