I have a TListView on my form. I add some columns in it depending on the input like so:
MyItem := StringListView.Columns.Add;
MyItem.Caption := IntToStr(i);
MyItem.Width := -2;
Afterwards I use the onData event to populate the ListView like this:
procedure TMatrixDictViewerFrame.StringListViewData(Sender: TObject;
Item: TListItem);
var
ItemCaption: string;
ItemText: string;`
begin
ItemCaption := Format('[%d]', [Item.Index]);
ItemText := FItems[Item.Index];
Item.Caption := ItemCaption;
Item.SubItems.Add(ItemText);
end;
It works fine since in the First column I have the Itemcaptions and in the second column I get the Itemtexts. What I couldnt figure out tho is how to populate the ListView depending on the data I get.
For example: I have a matrix A which is a 3x3 Matrix and I want its elements to be shown in this ListView so the first row shows the first 3 row elements, the second row shows the second row three elements and so on. Questions: how can I access the third column? How can I populate the view according to the Index I have (i,j)?
Best regards
The Index property of the list item tells you the row. You are expected to populate the entire row. Like this:
procedure TMatrixDictViewerFrame.StringListViewData(Sender: TObject; Item: TListItem);
begin
// A is a 3x3 matrix, that you obtain by means we don't know
Item.Caption := FloatToStr(A[Item.Index, 0]);
Item.SubItems.Add(FloatToStr(A[Item.Index, 1]));
Item.SubItems.Add(FloatToStr(A[Item.Index, 2]));
end;
Related
When using the OnDblClick event of a TDBGrid, how can i know what column was double clicked ?
This is easy with the OnCellClick as it has a TColumn parameter, but not on OnDblClick.
During TDBGrid.OnDblClick the dataset is positioned to the clicked record and the column can be retrieved with the TDBGrid.SelectedIndex property. If you are interested in the underlying dataset field, you can directly access it with TDBGrid.SelectedField.
The OnDblClick event doesn't give you any information about the click, in particular where the click was performed, let alone which grid cell was clicked on. So, you will have to determine that information manually.
Try this:
Get the current mouse position within the grid, by passing Mouse.CursorPos to TDBGrid.ScreenToClient()
Then, use TDBGrid.MouseCoord() to determine the row/column indexes of the cell that is underneath the mouse.
Then, check if the cell row/column corresponds to a data cell, and if so then use the TDBGrid.SelectedIndex property to index into the TDBGrid.Columns property.
This is basically the same thing that TDBGrid does internally when firing the OnCellClick event, only it does this in response to a MouseUp event, which provides the mouse coordinates within the grid, thus skipping the 1st step above.
For example:
type
TDBGridAccess = class(TDBGrid)
end;
procedure TMyForm1.DBGrid1DblClick(Sender: TObject);
var
TitleOffset: Byte;
Pt: TPoint;
Cell: TGridCoord;
Column: TColumn;
begin
TitleOffset := Ord(dgTitles in DBGrid1.Options);
Pt := DBGrid1.ScreenToClient(Mouse.CursorPos);
Cell := DBGrid1.MouseCoord(Pt.X, Pt.Y);
if (Cell.X >= TDBGridAccess(DBGrid1).IndicatorOffset) and (Cell.Y >= TitleOffset) then
begin
Column := DBGrid1.Columns[DBGrid1.SelectedIndex];
// use Column as needed...
end;
end;
UPDATE: based on #UweRaabe's comments, you should be able to just use TDBGrid.SelectedIndex by itself:
procedure TMyForm1.DBGrid1DblClick(Sender: TObject);
var
Index: Integer;
Column: TColumn;
begin
Index := DBGrid1.SelectedIndex;
if (Index <> -1) then
begin
Column := DBGrid1.Columns[Index];
// use Column as needed...
end;
end;
procedure TFormMain.CaseListMyShares(uri: String);
var
i: Integer;
begin
myShares := obAkasShareApiAdapter.UserShares(uri);
MySharesGrid.RowCount:= Length(myShares) +1;
MySharesGrid.AddCheckBoxColumn(0, false);
MySharesGrid.AutoFitColumns;
for i := 0 to Length(myShares) -1 do
begin
MySharesGrid.Cells[1, i+1]:= myShares[i].patientCase;
MySharesGrid.Cells[2, i+1]:= myShares[i].sharedUser;
MySharesGrid.Cells[3, i+1]:= myShares[i].creationDate;
MySharesGrid.Cells[4, i+1]:= statusText[StrToInt(myShares[i].situation) -1];
end;
end;
I want to create an invisible column to myself. I have to know row's identifier to make some operations with REST API. But end-user does not need to see this identifier on table. How can i create an invisible column ?
myShares[i].identifier which i want to hide on every row. Is that possible ? Using TAG or anything ?
To assign the identifier:
MySharesGrid.Objects[0, i+1] := TObject(myShares[i].identifier)
To access the identifier (e.g. OnClick):
Integer(MySharesGrid.Objects[0, MySharesGrid.Row])
To answer the question, assign its ColWidths to -1, thusly:
StringGrid1.ColWidths[4] := -1;
You can show it again by setting that back to a positive value.
This is not about using a StringGrid to store data, but for the User Interface to show/hide columns - like a Collapse speedbutton in the title, with a corresponding Show All button to restore it.
I'm not sure how i would capture the row selected by a mouse click and then press a button to delete that selected row in a stringGrid in delphi.
procedure DeleteRow(Grid: TStringGrid; ARow: Integer);
var
i: Integer;
begin
for i := ARow to Grid.RowCount - 2 do
Grid.Rows[i].Assign(Grid.Rows[i + 1]);
Grid.RowCount := Grid.RowCount - 1;
end;
procedure TManageUsersForm.RemoveRowButtonClick(Sender: TObject);
var
Recordposition : integer;
begin
UserStringGrid.Options := UserStringGrid.Options + [goEditing];
UserStringGrid.Options := UserStringGrid.Options + [goRowSelect];
end;
So the first procedure is for deleting a row and the second makes sure when a user clicks a cell the whole row is highlighted not just that 1 cell.
The mouse click is the most important part!!
Thank You :)
The mouse click is not the most important part. Users can select a row either by keyboard or mouse, it doesn't matter, you'd just want to delete the current row. In the case of a mouse click, or otherwise, you can get the current row by Row.
procedure DeleteCurrentRow(Grid: TStringGrid);
var
i: Integer;
begin
for i := Grid.Row to Grid.RowCount - 2 do
Grid.Rows[i].Assign(Grid.Rows[i + 1]);
Grid.RowCount := Grid.RowCount - 1;
end;
Call it like;
DeleteCurrentRow(UserStringGrid);
I imagine the problem you might be having is to work out which grid row the user has clicked on. One way is:
procedure TForm1.StringGrid1Click(Sender: TObject);
var
StringGrid : TStringGrid;
Row : Integer;
GridRect : TGridRect;
begin
// The Sender argument to StringGrid1Click is actually the StringGrid itself,
// and the following "as" cast lets you assign it to the StringGrid local variable
// in a "type-safe" way, and access its properties and methods via the temporary variable
StringGrid := Sender as TStringGrid;
// Now we can retrieve the use selection
GridRect := StringGrid.Selection;
// and hence the related GridRect
// btw, the value returned for Row automatically takes account of
// the number of FixedRows, if any, of the grid
Row := GridRect.Top;
Caption := IntToStr(Row);
{ ...}
end;
See the OLH about TGridRect.
Hopefully the above will be sufficient to get you going - you've obvious already got most of the way yourself. Or, you could try the method suggested in the other answer, which is a little more "direct" but this way might be a bit more instructive as a "how to". Your choice ...
I'm using this code to assign values:
combobox1.Text:=form1.listview1.Selected.Caption;
But i'm getting this error: Cannot assign a TListItems to a TComboBox
You can't add a ListView.Items to a ComboBox.Items (as the compiler has told you, one is a TListItems collection and the other is a descendant of TStrings, and they're not type compatible). You can add the caption of a selected ListItem to the ComboBox.Items.
You need to add it to the ComboBox.Items:
ComboBox1.Items.Add(ListView1.Selected.Caption);
If you want to add all selected items, you need to use a loop:
var
Item: TListItem;
begin
Item := ListView1.Selected;
while Item <> nil do
begin
ComboBox1.Items.Add(Item.Caption);
Item := ListView1.GetNextItem(Item, sdAll, [isSelected]);
end;
If you just want to add all items from the ListView to the ComboBox (which seems pretty pointless, as they're already displayed in the ListView):
var
i: Integer;
begin
for i := 0 to ListView1.Items.Count - 1 do
ComboBox1.Items.Add(ListView1.Items[i].Caption);
end;
I have a DevExpress grid where I would like to add an unbound checkbox to be able to select some of the items.
After the selection is made I press a button and I must loop the grid to get all the selected items.
It has to be a checkbox. I have tried with a multiselectable grid, but the users can't work with that.
I have tried all the samples that I have been able to find on the supportsites, but no luck.
I need the unbound approach since it is a multiuser setup and users have been selecting and deselecting for each other.
My question: does anyone have a working sample that shows how this can be done?
I've done this and it was (is!) pretty ugly! Create the grid view with bound columns and add an unbound checkbox column with a field type of boolean.
Basically I handle the OnCellClick of the grid view. I check if the item clicked is the checkbox column - by finding the first unbound column in the view with a checkbox type. Then I toggle its state.
I've set AutoEdit on the dataset to true but Deleting/Editing/Inserting to false and ImmediateEditor is false. Not exactly sure which of those are important.
I think the hardest thing was trying to fathom out the complex hierarchy of grid and view level objects and working out which levels contained which of the needed bits. I'm sure there's a better way of doing it but what we've got now works and I'm not going to touch it again!
This is lifted from my code but modified slightly and not tested as it stands - it also needs a bit more error checking:
procedure TMyForm.ViewCellClick(Sender: TcxCustomGridTableView;
ACellViewInfo: TcxGridTableDataCellViewInfo; AButton: TMouseButton;
AShift: TShiftState; var AHandled: Boolean);
var
col: TcxGridColumn;
begin
// Manually handle the clicking of the checkbox cell - otherwise it seems
// virtually impossible to get the checked count correct.
col := GetViewCheckColumn(Sender);
if (Sender.Controller.FocusedItem = col) then
begin
ToggleRowSelection(TcxCustomGridTableView(TcxGridSite(Sender).GridView), col);
end;
end;
procedure TMyForm.ToggleRowSelection(AView: TcxCustomGridTableView; ACol: TcxGridColumn);
var
rec: TcxCustomGridRecord;
begin
rec := AView.Controller.FocusedRecord;
if (rec = nil) then exit;
if (rec.Values[ACol.Index] = TcxCheckBoxProperties(ACol.Properties).ValueChecked) then
begin
rec.Values[ACol.Index] := TcxCheckBoxProperties(ACol.Properties).ValueUnchecked;
end
else
begin
rec.Values[ACol.Index] := TcxCheckBoxProperties(ACol.Properties).ValueChecked;
end;
end;
function TMyForm.GetViewCheckColumn(AView: TcxCustomGridView): TcxGridColumn;
var
index: integer;
vw: TcxCustomGridTableView;
item: TcxCustomGridTableItem;
begin
// We're looking for an unbound check box column - we'll return the first
// one found.
Assert(AView <> nil);
result := nil;
if (AView is TcxCustomGridTableView) then
begin
vw := TcxCustomGridTableView(AView);
for index := 0 to vw.ItemCount - 1 do
begin
item := vw.Items[index];
if (item.Properties is TcxCustomCheckBoxProperties) then
begin
if (item is TcxGridDBColumn) then
begin
if (TcxGridDBColumn(item).DataBinding.FieldName = '') then
begin
result := TcxGridColumn(item);
break;
end;
end;
end;
end;
end;
end;
I then extended it by checking for a SPACE bar press in the OnKeyUp of the grid and calling ToggleRowSelection and also similar for a double click on a row.
When iterating through the rows you can test if a row is checked using something like the following:
function TMyForm.GetViewIsRowChecked(AView: TcxCustomGridView; ARecord: TcxCustomGridRecord): boolean;
var
col: TcxGridColumn;
begin
result := False;
col := GetViewCheckColumn(AView);
if ((col <> nil) and (ARecord <> nil)) then
begin
result := (ARecord.Values[col.Index] = TcxCheckBoxProperties(col.Properties).ValueChecked);
end;
end;
I think that's it. I've dug it out of a large grid/view helper unit we've built up over a while. Oh, and it's currently working with Delphi 2010 with DXVCL v2011 vol 1.10.
Hope it helps.