José Eduardo
José Eduardo

Reputation: 333

DBGrid: how to prevent a row from being selected?

I have a grid of entries the user will click on to multi-select for a process. Some of the entries will be invalid based upon values of the first selected row.

I know about DBGrid.SelectedRows.CurrentRowSelected, but I cannot find a suitable place for checking my conditions to set it to True or False.

Something like this:

var
  bm: TBookmark;
  CachedIdentity: String;
  CanSelect: Boolean;
begin
  with dgbSkypeConversations do
  begin
    if SelectedRows.Count > 0 then
    begin
      DataSource.DataSet.DisableControls;
      bm := DataSource.DataSet.GetBookmark;
      CachedIdentity := DataSource.DataSet.FieldByName('identity').AsString;
      DataSource.DataSet.GotoBookmark(SelectedRows[0]);
      CanSelect := DataSource.DataSet.FieldByName('identity').AsString <> CachedIdentity;
      DataSource.DataSet.GotoBookmark(bm);
      DataSource.DataSet.FreeBookmark(bm);
      SelectedRows.CurrentRowSelected := CanSelect; 
      DataSource.DataSet.EnableControls;
    end;
  end
end;

I have tried the OnMouseDown events in Application.OnMessage and of the DBGrid and the Form, but they do not work, and there is no TBookmarkList.BeforeInsertItem event. What can I do or must I change?

Upvotes: 3

Views: 6158

Answers (2)

moskito-x
moskito-x

Reputation: 11968

I would not make it so complicated.
If the comparison always takes place on the first selection.
The code I use here has hardcoded Value.
No jump around to bookmarks.

// first selection----------------------------- 
if DBGrid1.SelectedRows.Count = 1 then begin
   CachedIdentity := 'Sonnenbrille'; // Sunglasses
 //CachedIdentity := DataSource.DataSet.FieldByName('identity').AsString;
   Exit;
end;

Do the comparison

if DBGrid1.SelectedRows.CurrentRowSelected then begin
 //if CachedIdentity <> DataSource.DataSet.FieldByName('identity').AsString
   if Pos(LookingFor,DBGrid1.DataSource.DataSet.FieldByName('haupttxt').AsString)=0
   then  DBGrid1.SelectedRows.CurrentRowSelected := False;
   ShowMessage(IntToStr(DBGrid1.SelectedRows.Count));
end;

We can see two are selected so
ShowMessage(IntToStr(DBGrid1.SelectedRows.Count));

shows 2

enter image description here

Now we want to select the line

SPORTLICH, ELEGANTE GUCCI SONNENBRILLE

We know a simple Pos() Sonnenbrille to find SONNENBRILLE Pos() will be = 0, so a selection-will not take place.

enter image description here

ShowMessage(IntToStr(DBGrid1.SelectedRows.Count));

shows 2 too

CODE:

var
CachedIdentity : string;

procedure TForm2.canSelectedV1;
begin
    // first selection----------------------------- 
if DBGrid1.SelectedRows.Count = 1 then begin
   CachedIdentity := 'Sonnenbrille'; // Sunglasses
 //CachedIdentity := DataSource.DataSet.FieldByName('identity').AsString;
   Exit;
end;
if DBGrid1.SelectedRows.CurrentRowSelected then
 begin
 //if CachedIdentity <> DataSource.DataSet.FieldByName('identity').AsString
   if Pos(LookingFor,DBGrid1.DataSource.DataSet.FieldByName('haupttxt').AsString)=0
   then  DBGrid1.SelectedRows.CurrentRowSelected := False;
   ShowMessage(IntToStr(DBGrid1.SelectedRows.Count));
 end;
end;

procedure TForm2.DBGrid1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
canSelectedV1;
end;

procedure TForm2.DBGrid1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
canSelectedV1;
end;

end.

Upvotes: 1

MartynA
MartynA

Reputation: 30745

If you look at the source of TCustomDBGrid.MouseDown you'll see how it works out which dataset row (if any) the Mousedown event occurred on. You'll also see the line which leads to the Selection state of the current row being toggled:

  if ssCtrl in Shift then
    CurrentRowSelected := not CurrentRowSelected

With that in mind, set up an OnMouseUp event for your grid and put a breakpoint in it.

You should then notice that because of what goes on in the grid's MouseDown event, by the time your OnMouseUp event is called, the current row of the grid's dataset has moved to the clicked datarow (see note below). So, at that point you can check whether the current row meets the criteria by which you want to allow the user to select it, and deselect it if it doesn't. I think that answers your specific "how to prevent a row from being selected?"

As a user that deselecting behaviour would annoy me somewhat, so you should probably give the user some indication of why the row has been deselected.

Note: Obviously, the fact that the grid's Mousedown will result in a call to the dataset's MoveBy means that the dataset's OnScroll event has been fired. Depending on exactly what you want to do, the OnScroll event might be the place to check whether the current datarow meets your selection criteria and, if it doesn't, begin the process of de-selecting it there. In any case, the fact that the dataset should have already be on the datarow where the DBGrid.MouseDown event was called should save you the trouble of identifying it in your MouseUp.

Hopefully that will be enough to get you going ...

Upvotes: 2

Related Questions