Delphi Pages Forums  

Go Back   Delphi Pages Forums > Delphi Forum > VCL

Lost Password?

Closed Thread
 
Thread Tools Display Modes
  #1  
Old 03-17-2016, 07:31 AM
ShaunVW ShaunVW is offline
Member
 
Join Date: Feb 2012
Posts: 47
Default Colouring of checkboxes within a stringgrid

Good morning
First off, thank you for all the help in the past, and I'm hoping someone is able to help again.

I have a stringgrid which I have populated with a whole lot of checkboxes.
Depending on the user, different check boxes are available for editing, and to this end I will colour the stringgrid "behind" the check box, and it works fine.

However, I have attempted to make the checkbox have 3 states, undefined, checked and not checked, but with little success (using DFCS_BUTTON3STATE), so what I am thinking to do now, is if the checkbox is undefined (as in the user hasn't specifically yet chosen to check it or uncheck it), I want to colour it another colour, probably gray. How do I do this? I am meaning the area where the check mark goes. This was my initial expectations of the DFCS_BUTTON3STATE.
This is part of my current code showing my attempts to make the undefined checkbox different to the standard checkbox (OnDrawCell)...

Code:
   ChecksStringGrid.Canvas.FillRect(Rect);
   if ChecksStringGrid.Cells[ACol,ARow] = '-1' then
    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_BUTTON3STATE + DFCS_INACTIVE + DFCS_FLAT) //DrawFrameControl draws a frame control as specified
   else if ChecksStringGrid.Cells[ACol,ARow] = '0' then
    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_BUTTONCHECK) //DrawFrameControl draws a frame control as specified
   else if ChecksStringGrid.Cells[ACol,ARow] = '1' then
    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_CHECKED);
This is the current colouring of the stringgrid being done (also OnDrawCell)
Code:
 if (ARow >= 6) then
  ChecksStringGrid.Canvas.Brush.Color := $7979FC //pinksh color
 else
  ChecksStringGrid.Canvas.Brush.Color := ChecksStringGrid.Color; //default colour
Thanks.
  #2  
Old 03-17-2016, 08:42 AM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,305
Default

Can you provide a zipped sample project (dpr,pas,dfm) ???
  #3  
Old 03-17-2016, 09:15 AM
ShaunVW ShaunVW is offline
Member
 
Join Date: Feb 2012
Posts: 47
Default

Ok I've done it, see https://dl.dropboxusercontent.com/u/43503478/Sample.rar
  #4  
Old 03-17-2016, 11:07 AM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,305
Default

DrawFrameControl is somewhat deprecated, since Vista you can use the Themes library.

This will draw a tri-state checkbox as I think you're after:
Code:
uses
  UxTheme;

procedure TForm1.CheckStringGridDrawCell(....)
var
  stateId: Integer;
  h    : HTHEME;
  s    : TSize;
begin
  ...
      h := OpenThemeData(ChecksStringGrid.Handle, 'BUTTON');
      if h <> 0 then
      try
        if (ChecksStringGrid.Cells[ACol,ARow] = '-1') OR (ChecksStringGrid.Cells[ACol,ARow] = '') then
          stateId := CBS_MIXEDNORMAL
        else if ChecksStringGrid.Cells[ACol,ARow] = '0' then
          stateId := CBS_CHECKEDNORMAL
        else if ChecksStringGrid.Cells[ACol,ARow] = '1' then
          stateId := CBS_UNCHECKEDNORMAL;

        GetThemePartSize(h, ChecksStringGrid.Canvas.Handle, BP_CHECKBOX, stateId, nil, TS_DRAW, s);
        DrawThemeBackground(h, ChecksStringGrid.Canvas.Handle, BP_CHECKBOX, stateId, Rect, nil)
      finally
        CloseThemeData(h);
      end;
You can validate that your system is running themes by a simple if-construction on UseThemes
Your old code can go in the else

To draw the tri-state grayed you'll have to do some work yourself. Basically you'll have to draw it completely
To draw a button style control you can use the DrawEdge method. Before this, colors that are set are used.

Sample on this:
Code:
    // This code will draw a button style rectangle, here you can change your color aswell
    // NB#1: You'll have to draw an inner black square
    // NB#2: you'll have to adjust your Rect here, now it's the complete cell
    DrawEdge(ChecksStringGrid.Canvas.Handle, Rect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
    DrawEdge(ChecksStringGrid.Canvas.Handle, Rect, BDR_RAISEDINNER, BF_TOPLEFT);
As you can see, you'll have to do some stuff yourself, as for the themed code runs without any flaw.
  #5  
Old 03-17-2016, 11:42 AM
ShaunVW ShaunVW is offline
Member
 
Join Date: Feb 2012
Posts: 47
Default

Thanks Norrit, I'm going to have to look up some stuff that you used, I'm not familiar with it.
I was just looking for a different way to colour it gray since I couldn't get the tri-state working, but if this works then that is great.
I will feedback how it goes.
  #6  
Old 03-17-2016, 12:24 PM
ShaunVW ShaunVW is offline
Member
 
Join Date: Feb 2012
Posts: 47
Default

Than you Norrit, that indeed is what I was looking for.
For undefined, it now shows a little black square within the checkbox.
It does seem to overwrite the pink background behind the checkboxes, but that isn't a big deal.
  #7  
Old 03-17-2016, 12:38 PM
Norrit Norrit is offline
Moderator
 
Join Date: Aug 2001
Location: Landgraaf
Posts: 7,305
Default

Here it shows well, I think you stripped to much

This is my test code:
Code:
procedure TForm1.ChecksStringGridDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
var
 txt : String;
 savedAlign: word;
  h    : HTHEME;
  stateId: Integer;
  s    : TSize;
begin
 if (ARow < 8) AND (ARow > 0) then //colour all non-metrology checks
  ChecksStringGrid.Canvas.Brush.Color := $7979FC //reddish color
 else
  ChecksStringGrid.Canvas.Brush.Color := ChecksStringGrid.Color; //default colour

 if (ARow = 0) OR (ACol = 0) then
  ChecksStringGrid.Canvas.Font.Style := [fsBold]
 else
  ChecksStringGrid.Canvas.Font.Style := []; //remove font

 //change to checkboxes
 if (ACol > 0) AND (ARow > 0) AND (ACol <= 12) then
  begin
   ChecksStringGrid.Canvas.FillRect(Rect);

  if UseThemes then
  begin
      h := OpenThemeData(ChecksStringGrid.Handle, 'BUTTON');
      if h <> 0 then
      try
        if (ChecksStringGrid.Cells[ACol,ARow] = '-1') OR (ChecksStringGrid.Cells[ACol,ARow] = '') then
          stateId := CBS_MIXEDNORMAL
        else if ChecksStringGrid.Cells[ACol,ARow] = '0' then
          stateId := CBS_CHECKEDNORMAL
        else if ChecksStringGrid.Cells[ACol,ARow] = '1' then
          stateId := CBS_UNCHECKEDNORMAL;

        GetThemePartSize(h, ChecksStringGrid.Canvas.Handle, BP_CHECKBOX, stateId, nil, TS_DRAW, s);
        DrawThemeBackground(h, ChecksStringGrid.Canvas.Handle, BP_CHECKBOX, stateId, Rect, nil)
      finally
        CloseThemeData(h);
      end;
  end
  else
  begin
   if (ChecksStringGrid.Cells[ACol,ARow] = '-1') OR (ChecksStringGrid.Cells[ACol,ARow] = '') then
   begin
    // This code will draw a button style rectangle, here you can change your color aswell
    // NB#1: You'll have to draw an inner black square
    // NB#2: you'll have to adjust your Rect here, now it's the complete cell
    DrawEdge(ChecksStringGrid.Canvas.Handle, Rect, BDR_RAISEDINNER, BF_BOTTOMRIGHT);
    DrawEdge(ChecksStringGrid.Canvas.Handle, Rect, BDR_RAISEDINNER, BF_TOPLEFT);

//    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_BUTTON3STATE or DFCS_CHECKED) //DrawFrameControl draws a frame control as specified
   end
   else if ChecksStringGrid.Cells[ACol,ARow] = '0' then
    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_BUTTONCHECK) //DrawFrameControl draws a frame control as specified
   else if ChecksStringGrid.Cells[ACol,ARow] = '1' then
    DrawFrameControl(ChecksStringGrid.Canvas.Handle, Rect, DFC_BUTTON, DFCS_CHECKED);
  end;
  end
 else
  ChecksStringGrid.Canvas.TextRect(Rect, Rect.Left+2, Rect.Top+2, ChecksStringGrid.Cells[ACol, ARow]);

 //Center the headings
 if (ARow = 0) then
  begin
   txt := ChecksStringGrid.Cells[ACol, ARow]; // cell contents
   savedAlign := SetTextAlign(ChecksStringGrid.Canvas.Handle, TA_CENTER);
   ChecksStringGrid.Canvas.TextRect(Rect, Rect.Left + (Rect.Right - Rect.Left) div 2, Rect.Top + 2, txt);
   SetTextAlign(ChecksStringGrid.Canvas.Handle, savedAlign);
  end;
end;
Note that it's not 100% dummy proof, if OpenThemeData returns no handle it'll draw nothing. Then your original code should be executed (the else)
Closed Thread

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 07:38 AM.


Powered by vBulletin® Version 3.8.8
Copyright ©2000 - 2018, vBulletin Solutions, Inc.