Chesso
asked on
Better TStringGrid.
Ok I don't mind the standard TStringGrid as is for the most part but what I really could use is one that can have a column type with CheckBox's in it (I have found some but they treat every cell that contains one with the same value from the others as if they all have the same checkbox and just move it when focus is moved).
I need a seperate checkbox with seperate values for every row.....
Better cosmetic options would be nice too :) but not essential at all. Preferably freeware if anyone knows of any.
So far I have tried XStringGrid, jgStrGrd, TMS Components Grids(Though not freeware), NextGrid and probably more.
I use Delphi 7.
I need a seperate checkbox with seperate values for every row.....
Better cosmetic options would be nice too :) but not essential at all. Preferably freeware if anyone knows of any.
So far I have tried XStringGrid, jgStrGrd, TMS Components Grids(Though not freeware), NextGrid and probably more.
I use Delphi 7.
There are a lot of StringGrids that can cover your needs:
http://www.torry.net/pages.php?id=114
http://www.torry.net/pages.php?id=114
ASKER
I have used all the ones on torry that work for D7, they either don't do it or I can't figure out how lol.
I haven't tried the first suggestion yet as I haven't had enough time lately to really sit down and try anything like that.
I haven't tried the first suggestion yet as I haven't had enough time lately to really sit down and try anything like that.
Chesso, did you not like this post that I made on DelphiPages:
http://www.delphipages.com/threads/thread.cfm?ID=166998&G=166991
You state: "I was using another StringGrid component, but couldn't get it
working too well or rather not the way I wanted it to."
If you let us in on what stringgrid component you ARE using, maybe we can help
better.
http://www.delphipages.com/threads/thread.cfm?ID=166998&G=166991
You state: "I was using another StringGrid component, but couldn't get it
working too well or rather not the way I wanted it to."
If you let us in on what stringgrid component you ARE using, maybe we can help
better.
ASKER
Oh yes that one, turns out it wasn't any good.
Like you would add the new StringGrid onto your form and then you could add a EditEditor and CheckBoxEditor components.
With the EditEditor values of cells are all reatedt uniquely but with the CheckBox editor set to a column the same value applies to all cells which is good for me i'm afraid.
If you still want the name I can take a look for you later.
Like you would add the new StringGrid onto your form and then you could add a EditEditor and CheckBoxEditor components.
With the EditEditor values of cells are all reatedt uniquely but with the CheckBox editor set to a column the same value applies to all cells which is good for me i'm afraid.
If you still want the name I can take a look for you later.
ASKER
Sorry i've had a bit to drunk tonight haha, I meant "treated instead of rearedt" and "isn't instead of is".
Oh my a sign I have had too much I think.
Oh my a sign I have had too much I think.
Yes, it would be better for you to post the one you are using. It is apparent that it differs from the standard
TStringGrid enough that normal modifications don't work correctly.
TStringGrid enough that normal modifications don't work correctly.
A better stringgrid you could obtain by playing with the default one. Learn some of the steps here:
http://delphi.about.com/od/vclusing/l/aa072203a.htm
The page also includes screenshots of what the stringGrid will look like.
Regards
http://delphi.about.com/od/vclusing/l/aa072203a.htm
The page also includes screenshots of what the stringGrid will look like.
Regards
ASKER
Sorry for such a late reply.
I was using XStringGrid which appears to have everything I need and more, most of the additional editors like ComboBox work fine and treat each cell with seperate values but with the CheckBox, changing one cell changes the state of all cells.
If only that were fixed it would be perfect.
I was using XStringGrid which appears to have everything I need and more, most of the additional editors like ComboBox work fine and treat each cell with seperate values but with the CheckBox, changing one cell changes the state of all cells.
If only that were fixed it would be perfect.
ASKER
Iv'e increased the points by 100. Gotta get this thing going heh heh.
ASKER
Umm so no one then?
been on vacation, will try to get back to it on Fri.
ASKER
Ahh ok, kool thanks for the help :)
I took a look at the XStringgrid and the checkbox editor is not what you want for that stringgrid.
I have modified the code previously posted on DP to work like you want. It will store the value
in the stringgrid but "draw" the checkbox either checked or unchecked. The values stored
are 1 for checked and 0 for unchecked.
You only have to modify the code to use the column you want to have checkboxes.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OleCtrls, SHDocVw, StdCtrls, Grids, XStringGrid, CECheckbox;
type
TForm1 = class(TForm)
StringGrid1: TXStringGrid;
procedure StringGrid1DrawCell(Sender : TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure StringGrid1KeyPress(Sender : TObject; var Key: Char);
procedure StringGrid1SelectCell(Send er: TObject; ACol, ARow: Integer;
var CanSelect: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure StringGrid1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
FCheck, FNoCheck: TBitmap;
procedure ToggleCheckbox(acol, arow: Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TGridCracker = Class( TStringgrid );
procedure TForm1.StringGrid1DrawCell (Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
Grid: TStringGrid;
begin
if not (gdFixed in State) and (ACol = 1) then
begin
Grid := Sender as TStringGrid;
with Grid.Canvas do
begin
Brush.color := $F7F7F7;
// checkboxes look better on a non-white background
FillRect(Rect);
// listbox state is encoded by the Objects property
if Assigned(Grid.Objects[ACol , ARow]) then
begin
Draw((Rect.Right + Rect.Left - FCheck.Width) div 2,
(Rect.Bottom + Rect.Top - FCheck.Height) div 2,
FCheck);
end
else
begin
Draw((Rect.Right + Rect.Left - FNoCheck.Width) div 2,
(Rect.Bottom + Rect.Top - FNoCheck.Height) div 2,
FNoCheck)
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
bmp: TBitmap;
begin
FCheck := TBitmap.Create;
FNoCheck := TBitmap.Create;
bmp := TBitmap.create;
try
bmp.Handle := LoadBitmap(0, PChar(OBM_CHECKBOXES));
// bmp now has a 4x3 bitmap of divers state images
// used by checkboxes and radiobuttons
with FNoCheck do
begin
// the first subimage is the unchecked box
width := bmp.Width div 4;
height := bmp.Height div 3;
Canvas.CopyRect(Canvas.Cli pRect, bmp.Canvas, Canvas.ClipRect);
end;
with FCheck do
begin
// the second subimage is the checked box
width := bmp.Width div 4;
height := bmp.Height div 3;
Canvas.CopyRect(
Canvas.ClipRect,
bmp.Canvas,
Rect(width, 0, 2*width, height));
end;
finally
bmp.Free
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FNoCheck.Free;
FCheck.Free;
end;
procedure TForm1.StringGrid1Click(Se nder: TObject);
var
pt: TPoint;
Grid: TStringGrid;
ACol, ARow: Integer;
begin
GetCursorPos( pt );
Grid := Sender as TStringgrid;
pt:= Grid.ScreenToClient(pt);
Grid.MouseToCell(pt.x, pt.y, ACol, ARow);
If (ACol = 1) and (ARow >= Grid.FixedRows) then
begin
// click landed in a checkbox cell
ToggleCheckbox(ACol, ARow);
end;
ShowMessage(StringGrid1.Ce lls[ACol, ARow]);
end;
procedure TForm1.ToggleCheckbox(ACol , ARow: Integer);
begin
if ACol = 1 then
begin
with TGridCracker(StringGrid1) do
begin
if Assigned(Objects[ACol, ARow]) then
begin
Objects[ACol, ARow] := nil;
end
else
begin
Objects[ACol, ARow] := Pointer(1);
end;
InvalidateCell(ACol, ARow);
end;
StringGrid1.Cells[ACol, ARow] := IntToStr(Ord(Assigned(Stri ngGrid1.Ob jects[ACol , ARow])));
end;
end;
procedure TForm1.StringGrid1SelectCe ll(Sender: TObject; ACol,
ARow: Integer; var CanSelect: Boolean);
begin
with Sender as TStringgrid do
begin
if aCol = 1 then
begin
Options := Options - [ goediting ];
end
else
begin
Options := Options + [ goediting ];
end;
end;
end;
procedure TForm1.StringGrid1KeyPress (Sender: TObject; var Key: Char);
begin
// Toggle if spacebar is hit.
if Key = #32 then
begin
with Sender as TstringGrid do
begin
if Col = 1 then
begin
ToggleCheckbox(Col, Row);
Key := #0;
ShowMessage(StringGrid1.Ce lls[Col, Row]);
end;
end;
end;
end;
end.
I have modified the code previously posted on DP to work like you want. It will store the value
in the stringgrid but "draw" the checkbox either checked or unchecked. The values stored
are 1 for checked and 0 for unchecked.
You only have to modify the code to use the column you want to have checkboxes.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, OleCtrls, SHDocVw, StdCtrls, Grids, XStringGrid, CECheckbox;
type
TForm1 = class(TForm)
StringGrid1: TXStringGrid;
procedure StringGrid1DrawCell(Sender
Rect: TRect; State: TGridDrawState);
procedure StringGrid1KeyPress(Sender
procedure StringGrid1SelectCell(Send
var CanSelect: Boolean);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure StringGrid1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
FCheck, FNoCheck: TBitmap;
procedure ToggleCheckbox(acol, arow: Integer);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
TGridCracker = Class( TStringgrid );
procedure TForm1.StringGrid1DrawCell
Rect: TRect; State: TGridDrawState);
var
Grid: TStringGrid;
begin
if not (gdFixed in State) and (ACol = 1) then
begin
Grid := Sender as TStringGrid;
with Grid.Canvas do
begin
Brush.color := $F7F7F7;
// checkboxes look better on a non-white background
FillRect(Rect);
// listbox state is encoded by the Objects property
if Assigned(Grid.Objects[ACol
begin
Draw((Rect.Right + Rect.Left - FCheck.Width) div 2,
(Rect.Bottom + Rect.Top - FCheck.Height) div 2,
FCheck);
end
else
begin
Draw((Rect.Right + Rect.Left - FNoCheck.Width) div 2,
(Rect.Bottom + Rect.Top - FNoCheck.Height) div 2,
FNoCheck)
end;
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
bmp: TBitmap;
begin
FCheck := TBitmap.Create;
FNoCheck := TBitmap.Create;
bmp := TBitmap.create;
try
bmp.Handle := LoadBitmap(0, PChar(OBM_CHECKBOXES));
// bmp now has a 4x3 bitmap of divers state images
// used by checkboxes and radiobuttons
with FNoCheck do
begin
// the first subimage is the unchecked box
width := bmp.Width div 4;
height := bmp.Height div 3;
Canvas.CopyRect(Canvas.Cli
end;
with FCheck do
begin
// the second subimage is the checked box
width := bmp.Width div 4;
height := bmp.Height div 3;
Canvas.CopyRect(
Canvas.ClipRect,
bmp.Canvas,
Rect(width, 0, 2*width, height));
end;
finally
bmp.Free
end;
end;
procedure TForm1.FormDestroy(Sender:
begin
FNoCheck.Free;
FCheck.Free;
end;
procedure TForm1.StringGrid1Click(Se
var
pt: TPoint;
Grid: TStringGrid;
ACol, ARow: Integer;
begin
GetCursorPos( pt );
Grid := Sender as TStringgrid;
pt:= Grid.ScreenToClient(pt);
Grid.MouseToCell(pt.x, pt.y, ACol, ARow);
If (ACol = 1) and (ARow >= Grid.FixedRows) then
begin
// click landed in a checkbox cell
ToggleCheckbox(ACol, ARow);
end;
ShowMessage(StringGrid1.Ce
end;
procedure TForm1.ToggleCheckbox(ACol
begin
if ACol = 1 then
begin
with TGridCracker(StringGrid1) do
begin
if Assigned(Objects[ACol, ARow]) then
begin
Objects[ACol, ARow] := nil;
end
else
begin
Objects[ACol, ARow] := Pointer(1);
end;
InvalidateCell(ACol, ARow);
end;
StringGrid1.Cells[ACol, ARow] := IntToStr(Ord(Assigned(Stri
end;
end;
procedure TForm1.StringGrid1SelectCe
ARow: Integer; var CanSelect: Boolean);
begin
with Sender as TStringgrid do
begin
if aCol = 1 then
begin
Options := Options - [ goediting ];
end
else
begin
Options := Options + [ goediting ];
end;
end;
end;
procedure TForm1.StringGrid1KeyPress
begin
// Toggle if spacebar is hit.
if Key = #32 then
begin
with Sender as TstringGrid do
begin
if Col = 1 then
begin
ToggleCheckbox(Col, Row);
Key := #0;
ShowMessage(StringGrid1.Ce
end;
end;
end;
end;
end.
Lol, I wish I had thought of something like that.....
Russell
Russell
LOL, Russell, it is modification of the post I made on DP. I don't care if he selects your response.
E.
E.
E, Im just laughing because now that I saw your post on DP (which I hadn't when I offered the code), the code we both offered is based on the same idea. And in both cases, the asker of this question hasn't addressed either of the code samples. Go figure..
Russell
The grid supports a checkbox editor but it does not store a different value for each cell in the column.
Or so that is what I gathered. My change, outlined above, would allow him to have a different value
per cell, which is what he needed.
I have not looked at the demo for XStringGrid, but the author told me it included the CheckBox editor and
that it worked. I may take a look later today.
Or so that is what I gathered. My change, outlined above, would allow him to have a different value
per cell, which is what he needed.
I have not looked at the demo for XStringGrid, but the author told me it included the CheckBox editor and
that it worked. I may take a look later today.
Yours is shorter and mine is based upon some old Peter Below code from D2, I believe.
Kind of funny that a lot of those hacks still work all the way to D2006, huh?
How many VB "hacks" from VB2 or VB3 do you think would still work on VB6?
Kind of funny that a lot of those hacks still work all the way to D2006, huh?
How many VB "hacks" from VB2 or VB3 do you think would still work on VB6?
Chesso,
I took a closer look at the demo supplied with XStringGrid and I think I have what you want.
Make these changes to the Demo and you'll see what I mean.
procedure TDemoForm.CheckBoxCellEdit or1SetStat e(
Sender: TCheckBoxCellEditor);
begin
if xg.Cells[xg.Col, xg.Row] = 'b' then
Sender.State := cbChecked
else
Sender.State := cbUnchecked;
end;
procedure TDemoForm.CheckBoxCellEdit or1SetText (Sender: TCheckBoxCellEditor;
var Value: String);
begin
if Sender.State = cbChecked then
Value := 'b'
else
Value := '';
end;
procedure TDemoForm.xgCellProps(Send er: TObject; Canvas: TCanvas;
var Alignment: TAlignment; var CellText: String; AState: TGridDrawState;
Row, Col: Integer);
begin
if (col <> 3) and (col <> 4) and (row mod 2 = 1) and not(gdSelected in AState) then
Canvas.Brush.Color := clGray;
if (col = 9) and (row > 0) then
begin
Canvas.Font.Name := 'Marlett';
Canvas.Font.Size := 11;
end;
end;
Now, to get the state of the checkbox in the cell, use the following code. It gets the
state of the currently selected checkbox cell:
case CheckBoxCellEditor1.State of
cbChecked: ShowMessage('Checked');
cbUnchecked: ShowMessage('Unchecked');
end;
Or if you want to check the state of any cell, use this:
if Length(Trim(xg.Cells[9,2]) ) > 0 then
ShowMessage('Checked')
else
ShowMessage('Unchecked');
I took a closer look at the demo supplied with XStringGrid and I think I have what you want.
Make these changes to the Demo and you'll see what I mean.
procedure TDemoForm.CheckBoxCellEdit
Sender: TCheckBoxCellEditor);
begin
if xg.Cells[xg.Col, xg.Row] = 'b' then
Sender.State := cbChecked
else
Sender.State := cbUnchecked;
end;
procedure TDemoForm.CheckBoxCellEdit
var Value: String);
begin
if Sender.State = cbChecked then
Value := 'b'
else
Value := '';
end;
procedure TDemoForm.xgCellProps(Send
var Alignment: TAlignment; var CellText: String; AState: TGridDrawState;
Row, Col: Integer);
begin
if (col <> 3) and (col <> 4) and (row mod 2 = 1) and not(gdSelected in AState) then
Canvas.Brush.Color := clGray;
if (col = 9) and (row > 0) then
begin
Canvas.Font.Name := 'Marlett';
Canvas.Font.Size := 11;
end;
end;
Now, to get the state of the checkbox in the cell, use the following code. It gets the
state of the currently selected checkbox cell:
case CheckBoxCellEditor1.State of
cbChecked: ShowMessage('Checked');
cbUnchecked: ShowMessage('Unchecked');
end;
Or if you want to check the state of any cell, use this:
if Length(Trim(xg.Cells[9,2])
ShowMessage('Checked')
else
ShowMessage('Unchecked');
I will say, however, that I do not like the way he draws his checkboxes as I think they should
have the "flat" look like the OBM_CHECKBOXES. Using DrawFrameControl kaes the 3D checkbox and
it just doesn't look quite as clean, IMHO. The Caption property in the CheckBoxCellEditor is text that
shows next to the checkbox like a regular checkbox. I do not think it would be needed and set it to
blank in the demo.
have the "flat" look like the OBM_CHECKBOXES. Using DrawFrameControl kaes the 3D checkbox and
it just doesn't look quite as clean, IMHO. The Caption property in the CheckBoxCellEditor is text that
shows next to the checkbox like a regular checkbox. I do not think it would be needed and set it to
blank in the demo.
To add flat checkboxes, add a CreateParams procedure to the TCheckBoxInplace class and
add this code:
procedure TCheckBoxInplace.CreatePar ams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
Style := Style or BS_FLAT;
end;
add this code:
procedure TCheckBoxInplace.CreatePar
begin
inherited CreateParams(Params);
with Params do
Style := Style or BS_FLAT;
end;
ASKER
Wow hey, quite a bit of activity since I last checked lol.
I only checked last night and bam so much going on here now haha. I'll give your suggestions a try and see what happens when I can, Iv'e been a bit reluctant to crack open Delphi of late as I caught the flu from my sister for the second time in a row and am constantly rushing for tissues lol.
I only checked last night and bam so much going on here now haha. I'll give your suggestions a try and see what happens when I can, Iv'e been a bit reluctant to crack open Delphi of late as I caught the flu from my sister for the second time in a row and am constantly rushing for tissues lol.
ASKER
Uhh I see, I have tried your example code to replace in the Demo with the CheckBoxCellEditor component.
I completely forgot about the Demo and had only tried this component as is from scratch on a new application.
I can see that all cells are treated differently in the demo but this behaviour did not go down in a new application, do you know why???
I haven't had a look too much through the demo source yet but I figured it would handle that sort of thing on it's own, the other editors seem to.
I completely forgot about the Demo and had only tried this component as is from scratch on a new application.
I can see that all cells are treated differently in the demo but this behaviour did not go down in a new application, do you know why???
I haven't had a look too much through the demo source yet but I figured it would handle that sort of thing on it's own, the other editors seem to.
ASKER
Triple post... ouch, well anyway I upped the points another 120 :)
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Well I have no idea about the flat check boxes but I got it to work eventually. But this leaves me with another problem.... I thought this had a save/load feature but it doesn't seem to, could be a problem for Check/Combo Box columns.
save/load of what?
ASKER
Ahh don't worry Iv'e figured it out, it's pretty simple (silly me) seen as it all has text values anyway to define check/combo box values.
Thanks alot for all the help :)
Thanks alot for all the help :)
ASKER
Oh btw if you have the time, how exactly do I make the checkbox's flat? I'm not sure what to do with the example you provided me with.
[quote]add a CreateParams procedure to the TCheckBoxInplace class[/quote]
How much of that don't you understand? Find the TCheckBoxInplace class in
CECheckbox.pas and just add a CreateParams procedure with the code above.
How much of that don't you understand? Find the TCheckBoxInplace class in
CECheckbox.pas and just add a CreateParams procedure with the code above.
ASKER
Ahhh yep I see, got it. Thanks for all the help.
If you don't mind the string grid, there is a cheap (free) alternative to do what you want. By using owner drawing for the columns you wish displayed as a checkbox, you can easily handle the displaying and editing (toggle on / off) for each row.
The example below displays the second (editable) column as a checkbox, and allows for doubleclick, space key, enter key to toggle the check state. Internally, the field is set to either 'T' or blank. I kept it simple just to show the basics, but don't hestitate to ask if you have questions.
Regards,
Russell
----
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Grids;
type
TForm1 = class(TForm)
StringGrid1: TStringGrid;
procedure StringGrid1DrawCell(Sender
procedure StringGrid1SelectCell(Send
procedure StringGrid1DblClick(Sender
procedure StringGrid1KeyPress(Sender
private
// Private declarations
public
// Public declarations
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.StringGrid1DrawCell
var Checked: Boolean;
begin
if (ACol = 2) and (ARow > 0) then
begin
InflateRect(Rect, -2, -2);
if (StringGrid1.Cells[ACol, ARow] = 'T') then
Checked:=True
else
Checked:=False;
with StringGrid1.Canvas do
begin
FillRect(Rect);
if Checked then
DrawFrameControl(Handle, Rect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_ADJUSTRECT or DFCS_CHECKED or DFCS_FLAT)
else
DrawFrameControl(Handle, Rect, DFC_BUTTON, DFCS_BUTTONCHECK or DFCS_ADJUSTRECT or DFCS_FLAT);
end;
end;
end;
procedure TForm1.StringGrid1SelectCe
begin
if (ACol = 2) then
StringGrid1.Options:=Strin
else
StringGrid1.Options:=Strin
end;
procedure TForm1.StringGrid1DblClick
begin
if (StringGrid1.Col = 2) then
begin
if (StringGrid1.Cells[StringG
StringGrid1.Cells[StringGr
else
StringGrid1.Cells[StringGr
end;
end;
procedure TForm1.StringGrid1KeyPress
begin
if (Key in [#13, #32]) and (StringGrid1.Col = 2) then
begin
Key:=#0;
if (StringGrid1.Cells[StringG
StringGrid1.Cells[StringGr
else
StringGrid1.Cells[StringGr
end;
end;
end.
---- dfm ----
object Form1: TForm1
Left = 296
Top = 114
Width = 656
Height = 297
Caption = 'Form1'
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object StringGrid1: TStringGrid
Left = 12
Top = 8
Width = 557
Height = 201
ColCount = 10
DefaultRowHeight = 18
Options = [goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goRowSizing, goColSizing, goEditing]
TabOrder = 0
OnDblClick = StringGrid1DblClick
OnDrawCell = StringGrid1DrawCell
OnKeyPress = StringGrid1KeyPress
OnSelectCell = StringGrid1SelectCell
end
end