Reputation: 67
I am trying to customize a TStringGrid
by adding visual objects to cells within the grid. One column needs to contain standard windows push buttons in each row and another column needs to contain a drop down with pre-defined options.
From what I have read the best way to achieve this is to draw the buttons manually in the OnDrawCell
event handler. All of the examples I have found use DrawFrameControl()
which does not draw a themed button like you would expect in Windows 7 or later.
Is there an equivalent function to DrawFrameControl()
that will allow me to draw a themed button and if so can someone please give an example of how I might use it?
I also tried creating a vector of TButtons
and setting the parent of each button to be the StringGrid and placing each button within the relevant cell. This also works but does now allow for scrolling of the grid when there are more cells that can be displayed visible area.
I am using RAD Studio 10.2 C++ builder and using the BCC32C compiler (clang-enhanced). It is a VCL WIN32 application.
Upvotes: 0
Views: 752
Reputation: 67
Just for completeness here is the code I got working in order to draw a Windows Themed button in a TStringGrid cell:
void __fastcall TForm_Controller::StringGrid1DrawCell(TObject *Sender, int ACol,
int ARow, TRect &Rect, TGridDrawState State)
{
TStringGrid *grid;
bool ButtonDown = false, ButtonHot = false, ButtonInFocus = false;
TThemedElementDetails LDetails;
TTextFormatFlags LTextFormat;
TColor LColor, TempColor;
TCustomStyleServices *LStyle;
int XPos, YPos;
TPoint points[3];
grid = (TStringGrid *)Sender;
//a cell with a button ('+' or '-')
if((ACol == 0) && (ARow > 0) && grid->Cells[ACol][ARow].Length())
{
Rect.Left -= 4; //override padding so button fills entire cell
if ((FocusCell.X == ACol) && (FocusCell.Y == ARow))
ButtonHot = true;
if ((CellDown.X == ACol) && (CellDown.Y == ARow))
ButtonDown = true;
LStyle = StyleServices();
if (LStyle->Enabled && LStyle->Available)
{
if (ButtonDown)
LDetails = LStyle->GetElementDetails(tbPushButtonPressed);
else if (ButtonHot)
LDetails = LStyle->GetElementDetails(tbPushButtonHot);
else if (ButtonInFocus)
LDetails = LStyle->GetElementDetails(tbPushButtonDefaulted);
else
LDetails = LStyle->GetElementDetails(tbPushButtonNormal);
LStyle->DrawElement(grid->Canvas->Handle, LDetails, Rect);
if (LStyle->GetElementColor(LDetails, ecTextColor, LColor))
grid->Canvas->Font->Color = LColor;
grid->Canvas->Font->Size = 13;
LTextFormat = (tfCenter);
LStyle->DrawTextA(grid->Canvas->Handle, LDetails, grid->Cells[ACol][ARow], Rect, TTextFormat() << tfCenter << tfVerticalCenter);
}
else //themed drawing not available so revert to old style
DrawButtonFace(grid->Canvas, Rect, 1, bsAutoDetect, true, ButtonDown, ButtonInFocus);
}
}
I then use the OnMouseDown
, OnMouseMove
, OnMouseLeave
and OnMouseUp
events to determine what state the buttons need to be in using 3 TPoint
objects FocusCell
, PrevCell
, CellDown
.
Upvotes: 0
Reputation: 595412
Is there an equivalent function to
DrawFrameControl()
that will allow me to draw a themed button
The Win32 DrawFrameControl()
function is for drawing non-themed UI controls. To draw themed UI controls, you need to use the Win32 Theming functions instead - DrawThemeBackground()
, DrawThemeEdge()
, DrawThemeText()
, etc. These functions are wrapped for you by the VCL's Vcl.Themes
unit. In particular, use the TThemeServices
class, which has various Draw...()
methods that you can use when TThemeServices.Available
and TThemeServices.Enabled
are both true.
I also tried creating a vector of
TButtons
and setting the parent of each button to be the StringGrid and placing each button within the relevant cell. This also works but does now allow for scrolling of the grid when there are more cells that can be displayed visible area.
Correct. You would have to subclass the StringGrid to intercept the scrolling so you can reposition the buttons manually.
Upvotes: 2