how to copy selected data from stringgrid - delphi

i couldn't find the way to copy selected cell data from a stringgrid, i want the selected data string to be copied to Edit box if possible.. many thanks in advance.
im using delphi xe8, firemonkey.
what i tried so far..
Private
A : Array of TValue;
procedure TForm1.Grid1GetValue(Sender: TObject; const Col, Row: Integer; var Value: TValue);
begin
// Gets the value from a cell in the first column
if Col = 0 then
Value := A[Row];
procedure TForm1.Button2Click(Sender: TObject);
begin
A[1] := Edit1.Text;
end;

//i spent hours just to figure it out,waste of TIME;//
Procedure Formx.StringGrid1SellectCell(Sender: TObject; const ACol,Arow: integer; var CanSellect: Boolean);
Var
Val: string;
begin
Val := StringGrid1.Cells[ACol, ARow];
Edit1.Text:= Val;

Related

DBCtrlGrid Drag and Drop

Tried with no success to drag and drop a row to switch positions (using a ClientDataSet in memory)
The specific case is: a ClientDataSet with image file names who will result in an ordered list that will be used to create export to a PDF document where each image is a page (this is why the order is important).
The DbCtrlGrid is used to visualize a thumbnail of the image, and I was trying to use drag-and-drop to exchange their positions, but I couldn't get information about the row where I dropped in the end.
It would help a method to get info about the row where the mouse is over when the OnDragDrop event triggers or any other idea
please
I imagine your q is prompted by the fact that although the TDBCtrlGrid has a
PanelIndex property which tells you which one of the grid's virtual panels
is active (i.e. is the one for the current row in the dataset), this doesn't
change while you've moving the mouse around e.g. during a drag operation. However,
it is not difficult to calculate this yourself, as follows.
The Height and Width of a TDBCtrlGrid are exact multiples of its RowCount and
ColCount. In the simple case of ColCount =1, it is trivially simple
to calculate which Row contains a given Y coordinate within the grid:
function TForm1.PanelIndexFromYPos(Y : Integer) : Integer;
var
PanelHeight : Integer;
begin
PanelHeight := DBCtrlGrid1.ClientHeight div DBCtrlGrid1.RowCount;
Result := Y div PanelHeight;
end;
(obviously this is for the simple case of a single column goVertical orientated grid but would be easy to generalise)
Now, the TBDCtrlGrid's EndDrag (and MouseOver) tells you the Y coordinate of the TPoint where the
drag operation ends, so you can use this PanelIndexFromYPos function to tell you
which row index the user has dropped the dragged row onto. As #KenWhite explained,
you then need to re-order your CDS to reflect the new position the dragged row should be in.
This is easy to do if your CDS has a DisplayIndex field representing what row position
a given record in the CDS and the CDS has an active index on this field. Re-ordering
the CDS's records is a bit of a rigmarole, as will be apparent from the following sample project.
TForm1 = class(TForm)
CDS1: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBCtrlGrid1: TDBCtrlGrid; // Note: DragMode set to dmManual;
DBText1: TDBText; // In the DBCtrlGrid
DBText2: TDBText;
DBText3: TDBText;
edSourceIndex: TEdit;
edDestIndex: TEdit;
btnTest: TButton;
Memo1: TMemo;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure DBCtrlGrid1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure DBCtrlGrid1DragOver(Sender, Source: TObject; X, Y: Integer;
State: TDragState; var Accept: Boolean);
procedure DBCtrlGrid1DragDrop(Sender, Source: TObject; X, Y: Integer);
procedure btnTestClick(Sender: TObject);
private
procedure MoveRow(SourceIndex, DestIndex : Integer);
procedure LogMove(OldValue, NewValue: Integer);
procedure ShowPanelInfo(Y: Integer);
protected
function PanelIndexFromYPos(Y : Integer) : Integer;
public
SourceIndex : Integer; // the DbCtrlGrid PanelIndex of the row being dragged
DestIndex : Integer; // the PanelIndex where the row is dropped
end;
[...]
function TForm1.PanelIndexFromYPos(Y : Integer) : Integer;
var
PanelHeight : Integer;
begin
PanelHeight := DBCtrlGrid1.ClientHeight div DBCtrlGrid1.RowCount;
Result := Y div PanelHeight;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
AField : TField;
begin
// Create the fields for the CDS
AField := TIntegerField.Create(Self);
AField.FieldName := 'ID';
AField.DataSet := CDS1;
// This DisplayIndex field will be used to determine which row number in
// the DBCtrlGrid will occupy, by indexing the CDS on this field
AField := TIntegerField.Create(Self);
AField.FieldName := 'DisplayIndex';
AField.DataSet := CDS1;
AField := TStringField.Create(Self);
AField.FieldName := 'Name';
AField.Size := 20;
AField.DataSet := CDS1;
CDS1.CreateDataSet;
// Add some data which will appear in the grid in reverse-alphabetical order
CDS1.InsertRecord([1, 3, 'A']);
CDS1.InsertRecord([2, 2, 'B']);
CDS1.InsertRecord([3, 1, 'C']);
CDS1.InsertRecord([4, 0, 'D']);
CDS1.IndexFieldNames := 'DisplayIndex';
end;
procedure TForm1.DBCtrlGrid1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then begin
SourceIndex := PanelIndexFromYPos(Y);
DBCtrlGrid1.BeginDrag(False);
end;
end;
procedure TForm1.DBCtrlGrid1DragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
begin
Accept := True;
end;
procedure TForm1.DBCtrlGrid1DragDrop(Sender, Source: TObject; X,
Y: Integer);
begin
ShowPanelInfo(Y);
DestIndex := PanelIndexFromYPos(Y);
MoveRow(SourceIndex, DestIndex);
end;
procedure TForm1.MoveRow(SourceIndex, DestIndex : Integer);
var
BM : TBookMark;
Index : Integer;
procedure SetCDSIndex(Value : Integer);
var
OldValue : Integer;
begin
OldValue := CDS1.FieldByName('DisplayIndex').AsInteger;
CDS1.Edit;
CDS1.FieldByName('DisplayIndex').AsInteger := Value;
CDS1.Post;
LogMove(OldValue, Value);
end;
begin
if SourceIndex = DestIndex then exit;
CDS1.DisableControls;
try
if CDS1.FindKey([SourceIndex]) then begin
BM := CDS1.GetBookmark; // This is to keep track of the dragged row without needing to
// keep track of its (changing) DisplayIndex
if SourceIndex > DestIndex then begin
// i.e. we're moving the dragged row up in the grid
// so starting with the row above it we move the rows upwards
// eventually leaving a gap to drop the dragged row into
Index := SourceIndex - 1;
while Index >= DestIndex do begin
if CDS1.FindKey([Index]) then begin
SetCDSIndex(Index + 1);
end;
Dec(Index);
end;
end
else begin
// i.e. we're moving the dragged row down in the grid
// so starting with the row below it we move the rows upwards
// eventually leaving a gap to drop the dragged row into
Index := SourceIndex + 1;
while Index <= DestIndex do begin
if CDS1.FindKey([Index]) then begin
SetCDSIndex(Index - 1);
end;
Inc(Index);
end;
end;
end;
CDS1.GotoBookMark(BM);
if CDS1.FieldByName('DisplayIndex').AsInteger = SourceIndex then begin
SetCDSIndex(DestIndex);
end;
CDS1.FreeBookmark(BM); // should really have it's own try...finally but hey!
finally
CDS1.EnableControls;
end;
end;
procedure TForm1.LogMove(OldValue, NewValue : Integer);
begin
Memo1.Lines.Add(Format('Name: %s Old: %d New: %d ', [CDS1.FieldByName('Name').AsString, OldValue, NewValue]));
end;
procedure TForm1.ShowPanelInfo(Y : Integer);
begin
Label1.Caption := Format('y: %d panelindex: %d', [Y, PanelIndexFromYPos(Y)]);
end;
procedure TForm1.btnTestClick(Sender: TObject);
begin
// For debugging, to test mving rows without needing to drag/drop
MoveRow(StrToInt(edSourceIndex.Text), StrToInt(edDestIndex.Text));
end;
end.

Compare value in the previous cell StringGrid

When I finish entering the value in a cell of the TStringGrid I need to check if it is greater than the value that is in the cell of the previous column, on the same line ... if it inserts otherwise it will delete
in this case the 20% would not be inserted because it is smaller
I tried to make the comparison in this way but it triggers this method every time I type and not when I lose focus
procedure TfrmConfiguraClassificacao.listaFaixasSetEditText(Sender: TObject;
ACol, ARow: Integer; const Value: string);
begin
if Acol=1 then
//check if it is larger
end;
You can validate the cell when the user moves to another cell (OnSelectCell) or when focus shifts to another control (OnExit).
Use the OnSetEditText event to store the last edited cell location.
Something along these lines:
Type
TfrmConfiguraClassificacao = Class(TForm)
...
private
fCol,fRow : Integer;
function CellValidated : Boolean;
...
end;
...
procedure TfrmConfiguraClassificacao.listaFaixasEnter(Sender : TObject);
begin // Initialize edited cell location
fCol := -1;
fRow := -1;
end;
procedure TfrmConfiguraClassificacao.listaFaixasSetEditText(Sender: TObject;
ACol, ARow: Integer; const Value: string);
begin // Save the edited cell location
fCol := ACol;
fRow := ARow;
end;
procedure TfrmConfiguraClassificacao.listaFaixasSelectCell(Sender : TObject;
ACol, ARow: Longint; var CanSelect: Boolean);
begin // Validate edited cell location
CanSelect := CellValidated;
end;
procedure TfrmConfiguraClassificacao.listaFaixasExit(Sender : TObject);
begin // Validate edited cell location
if not CellValidated then
// Handle focus redirection
end;
function TfrmConfiguraClassificacao.CellValidated : Boolean;
begin
Result := True;
if fCol=1 then begin
// if not larger, handle it and set Result to false
end;
end;

Delphi + TeeChart : how can I get checkbox in legend for pie serie values?

I want to allow the user to choose what values are shown in a chart with a pie serie values by displaying a check box in front of each serie's value.
There is an option to display a checkbox near each legend item but it's only working for series, not values in a serie ; and you can only have one serie of values in a single pie.
Does anyone have any idea on how to achieve this?
You could draw your custom legend manually. However, you should do some tricks:
use a dummy series to store the original values and show these values in the legend.
remove the values from the main series that have been clicked in the legend taking care with the indexes and the colors.
Here an example, even with mouse Hover:
uses Series, TeCanvas, Math;
var pieSeries: TPieSeries;
dummySeries: TPieSeries;
itemRect: array of TRect;
itemIndex: Integer;
procedure TForm1.Chart1AfterDraw(Sender: TObject);
var i, tmpH, tmpW: Integer;
tmpR, tmpS: TRect;
begin
with Chart1.Canvas do
begin
AssignFont(Chart1.Legend.Font);
AssignBrush(Chart1.Legend.Brush);
tmpW:=0;
tmpH:=0;
for i:=0 to dummySeries.Count-1 do
begin
tmpW:=Max(TextWidth(dummySeries.LegendString(i, Chart1.Legend.TextStyle)), tmpW);
tmpH:=Max(TextHeight(dummySeries.LegendString(i, Chart1.Legend.TextStyle)), tmpH);
end;
Inc(tmpW, Chart1.Legend.Symbol.Width + TeeCheckBoxSize + 8);
tmpR.Left:=Chart1.Width-tmpW-10;
tmpR.Top:=50;
tmpR.Right:=tmpR.Left+tmpW;
tmpR.Bottom:=tmpR.Top + ((tmpH+4) * dummySeries.Count) + 4;
Rectangle(tmpR);
Inc(tmpR.Left, 4);
tmpS.Left:=tmpR.Left+TeeCheckBoxSize+4;
tmpS.Right:=tmpS.Left+TeeCheckBoxSize;
for i:=0 to dummySeries.Count-1 do
begin
Brush.Color:=OperaPalette[i];
Inc(tmpR.Top, 4);
DrawCheckBox(tmpR.Left, tmpR.Top, not dummySeries.IsNull(i), clNone);
if i=itemIndex then
begin
Pen.Color:=clRed;
Font.Color:=clRed;
end
else
begin
Pen.Color:=Chart1.Legend.Symbol.Pen.Color;
Font.Color:=Chart1.Legend.Font.Color;
end;
tmpS.Top:=tmpR.Top+1;
tmpS.Bottom:=tmpS.Top+TeeCheckBoxSize;
Rectangle(tmpS);
TextOut(tmpS.Right + 2, tmpR.Top, StringReplace(dummySeries.LegendString(i, Chart1.Legend.TextStyle), TeeColumnSeparator, ' ', [rfReplaceAll, rfIgnoreCase]));
itemRect[i]:=Rect(tmpR.Left, tmpS.Top, tmpR.Right, tmpS.Bottom);
Inc(tmpR.Top, tmpH);
end;
end;
end;
procedure TForm1.Chart1Click(Sender: TObject);
var i, j: Integer;
begin
if itemIndex>-1 then
begin
dummySeries.SetNull(itemIndex, not dummySeries.IsNull(itemIndex));
pieSeries.CheckDataSource;
for i:=pieSeries.Count-1 downto 0 do
if pieSeries.IsNull(i) then
pieSeries.Delete(i);
//Fix colors
j:=0;
for i:=0 to dummySeries.Count-1 do
if not dummySeries.IsNull(i) then
begin
pieSeries.ValueColor[j]:=OperaPalette[i];
Inc(j);
end;
end;
end;
procedure TForm1.Chart1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var i, j: Integer;
begin
itemIndex:=-1;
for i:=0 to length(itemRect)-1 do
if PointInRect(itemRect[i], X, Y) then
begin
itemIndex:=i;
break;
end;
if itemIndex>-1 then
begin
if dummySeries.IsNull(itemIndex) then
pieSeries.Selected.HoverIndex:=-1
else
begin
j:=0;
for i:=0 to itemIndex-1 do
if not dummySeries.IsNull(i) then
Inc(j);
pieSeries.Selected.HoverIndex:=j;
end;
end;
Chart1.CancelMouse:=True;
Chart1.Repaint;
end;
procedure TForm1.FormCreate(Sender: TObject);
var i: Integer;
begin
pieSeries:=Chart1.AddSeries(TPieSeries) as TPieSeries;
pieSeries.FillSampleValues;
for i:=0 to pieSeries.Count-1 do
pieSeries.ValueColor[i]:=OperaPalette[i];
dummySeries:=CloneChartSeries(pieSeries) as TPieSeries;
dummySeries.ParentChart:=nil;
pieSeries.DataSource:=dummySeries;
Chart1.Legend.Visible:=False;
Chart1.MarginRight:=20;
SetLength(itemRect, dummySeries.Count);
itemIndex:=-1;
end;

Read mutiple values from ini file into TCombobox

I have an ini file which contains the following:
[Colours]
1 = Red
2 = Blue
3 = Green
4 = Yellow
In my app I have a TComboBox which I would like to populate with the colours in the ini file.
Does anyone know how I'd go about this?
Thanks,
You can get a list of names in a section by using TIniFile.ReadSection() and then iterate to get the values:
procedure TForm1.LoadFile(const AFilename: String);
var
I: TIniFile;
L: TStringList;
X: Integer;
N: String;
V: String;
begin
I:= TIniFile.Create(AFilename);
try
L:= TStringList.Create;
try
ComboBox1.Items.Clear;
I.ReadSection('Colours', L);
for X := 0 to L.Count-1 do begin
N:= L[X]; //The Name
V:= I.ReadString('Colours', N, ''); //The Value
ComboBox1.Items.Add(V);
end;
finally
L.Free;
end;
finally
I.Free;
end;
end;
As an alternative, you could also dump the name/value pairs within the section into a single TStringList and read each value using the string list's built-in capabilities...
procedure TForm1.LoadFile(const AFilename: String);
var
I: TIniFile;
L: TStringList;
X: Integer;
N: String;
V: String;
begin
I:= TIniFile.Create(AFilename);
try
L:= TStringList.Create;
try
ComboBox1.Items.Clear;
I.ReadSectionValues('Colours', L);
for X := 0 to L.Count-1 do begin
N:= L.Names[X]; //The Name
V:= L.Values[N]; //The Value
ComboBox1.Items.Add(V);
end;
finally
L.Free;
end;
finally
I.Free;
end;
end;
On a side-note, Ini files do not have spaces on either side of the = sign, unless of course you want that space as part of the actual name or value.
try this, without reading the file twice:
uses IniFiles;
procedure TForm1.Button1Click(Sender: TObject);
var
lIni : TIniFile;
i: Integer;
begin
lIni := TIniFile.Create('c:\MyFile.ini');
try
lIni.ReadSectionValues('Colours', ComboBox1.Items);
for i := 0 to ComboBox1.Items.Count - 1 do
ComboBox1.Items[i] := ComboBox1.Items.ValueFromIndex[i];
finally
FreeAndNil(lIni);
end;
end;

Delphi: How to make cells' texts in TStringGrid center aligned?

It seems something obvious to have. I want the texts to be in the center of the cells, but for some reason I can't find it in properties. How can I do this?
There's no property to center the text in TStringGrid, but you can do that at DrawCell event as:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
S: string;
SavedAlign: word;
begin
if ACol = 1 then begin // ACol is zero based
S := StringGrid1.Cells[ACol, ARow]; // cell contents
SavedAlign := SetTextAlign(StringGrid1.Canvas.Handle, TA_CENTER);
StringGrid1.Canvas.TextRect(Rect,
Rect.Left + (Rect.Right - Rect.Left) div 2, Rect.Top + 2, S);
SetTextAlign(StringGrid1.Canvas.Handle, SavedAlign);
end;
end;
The code I posted from here
UPDATE:
to center text while writing in the cell, add this code to GetEditText Event:
procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: string);
var
S : String;
I: Integer;
IE : TInplaceEdit ;
begin
for I := 0 to StringGrid1.ControlCount - 1 do
if StringGrid1.Controls[i].ClassName = 'TInplaceEdit' then
begin
IE := TInplaceEdit(StringGrid1.Controls[i]);
ie.Alignment := taCenter
end;
end;
This one is a much better solution that the others and on them there was a mistype on procedures TStringGrid.SetCellsAlignment and TStringGrid.SetCellsAlignment the (-1 < Index) compare was correct, but then and else parts were swapped... The correct version (this one) will show that when index is bigger than -1 it will overwrite value stored else it will add a new entry, the others will do just the oposite bringing a list out of index message, thanks for detecting such.
I have also make able to be all in another separated unit, so here it is (hope now it is correct and thanks for detecting such mistypes):
unit AlignedTStringGrid;
interface
uses Windows,SysUtils,Classes,Grids;
type
TStringGrid=class(Grids.TStringGrid)
private
FCellsAlignment:TStringList;
FColsDefaultAlignment:TStringList;
function GetCellsAlignment(ACol,ARow:Integer):TAlignment;
procedure SetCellsAlignment(ACol,ARow:Integer;const Alignment:TAlignment);
function GetColsDefaultAlignment(ACol:Integer):TAlignment;
procedure SetColsDefaultAlignment(ACol:Integer;const Alignment:TAlignment);
protected
procedure DrawCell(ACol,ARow:Longint;ARect:TRect;AState:TGridDrawState);override;
public
constructor Create(AOwner:TComponent);override;
destructor Destroy;override;
property CellsAlignment[ACol,ARow:Integer]:TAlignment read GetCellsAlignment write SetCellsAlignment;
property ColsDefaultAlignment[ACol:Integer]:TAlignment read GetColsDefaultAlignment write SetColsDefaultAlignment;
end;
implementation
constructor TStringGrid.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FCellsAlignment:=TStringList.Create;
FCellsAlignment.CaseSensitive:=True;
FCellsAlignment.Sorted:=True;
FCellsAlignment.Duplicates:=dupIgnore;
FColsDefaultAlignment:=TStringList.Create;
FColsDefaultAlignment.CaseSensitive:=True;
FColsDefaultAlignment.Sorted:=True;
FColsDefaultAlignment.Duplicates:=dupIgnore;
end;
destructor TStringGrid.Destroy;
begin
FCellsAlignment.Free;
FColsDefaultAlignment.Free;
inherited Destroy;
end;
procedure TStringGrid.SetCellsAlignment(ACol,ARow: Integer; const Alignment: TAlignment);
var
Index:Integer;
begin
if (-1 < Index) then begin
FCellsAlignment.Objects[Index]:= TObject(Alignment);
end else begin
FCellsAlignment.AddObject(IntToStr(ACol) + '-' + IntToStr(ARow), TObject(Alignment));
end;
end;
function TStringGrid.GetCellsAlignment(ACol,ARow: Integer): TAlignment;
var
Index:Integer;
begin
Index:= FCellsAlignment.IndexOf(IntToStr(ACol)+'-'+IntToStr(ARow));
if (-1 < Index) then begin
GetCellsAlignment:= TAlignment(FCellsAlignment.Objects[Index]);
end else begin
GetCellsAlignment:= ColsDefaultAlignment[ACol];
end;
end;
procedure TStringGrid.SetColsDefaultAlignment(ACol: Integer; const Alignment: TAlignment);
var
Index:Integer;
begin
Index:= FColsDefaultAlignment.IndexOf(IntToStr(ACol));
if (-1 < Index) then begin
FColsDefaultAlignment.Objects[Index]:= TObject(Alignment);
end else begin
FColsDefaultAlignment.AddObject(IntToStr(ACol), TObject(Alignment));
end;
end;
function TStringGrid.GetColsDefaultAlignment(ACol:Integer):TAlignment;
var
Index:Integer;
begin
Index:= FColsDefaultAlignment.IndexOf(IntToStr(ACol));
if (-1 < Index) then begin
GetColsDefaultAlignment:= TAlignment(FColsDefaultAlignment.Objects[Index]);
end else begin
GetColsDefaultAlignment:=taLeftJustify;
end;
end;
procedure TStringGrid.DrawCell(ACol,ARow:Longint;ARect:TRect;AState:TGridDrawState);
var
Old_DefaultDrawing:Boolean;
begin
if DefaultDrawing then begin
case CellsAlignment[ACol,ARow] of
taLeftJustify: begin
Canvas.TextRect(ARect,ARect.Left+2,ARect.Top+2,Cells[ACol,ARow]);
end;
taRightJustify: begin
Canvas.TextRect(ARect,ARect.Right -2 -Canvas.TextWidth(Cells[ACol,ARow]), ARect.Top+2,Cells[ACol,ARow]);
end;
taCenter: begin
Canvas.TextRect(ARect,(ARect.Left+ARect.Right-Canvas.TextWidth(Cells[ACol,ARow]))div 2,ARect.Top+2,Cells[ACol,ARow]);
end;
end;
end;
Old_DefaultDrawing:= DefaultDrawing;
DefaultDrawing:=False;
inherited DrawCell(ACol,ARow,ARect,AState);
DefaultDrawing:= Old_DefaultDrawing;
end;
end.
This is a whole unit, save it to a file called AlignedTStringGrid.pas.
Then on any form you have a TStringGrid add ,AlignedTStringGrid at the end of the interface uses clause.
Note: The same can be done for rows, but for now I do not know how to mix both (cols and rows) because of how to select priority, if anyone is very interested on it let me know.
P.D.: The same idea is possible to be done for TEdit, just search on stackoverflow.com for TEdit.CreateParams or read post How to set textalignment in TEdit control

Resources