delphistringgrid

Delphi stringgrid TAdvsTringgrid function to disable and reenable mouse clicks


Is there a Delphi function to enable or disable mouse clicks for a stringgrid?

I'm using a derivation of stringgrid called Tadvstringgrid which allows coloring cells based on contens

I need to prevent mouse clicks inside a stringgrid while populating control with data from various threads.

Only disabling the control is not enough. If I click in random cells, the info gets screwed up meaning that some strings are placed in the last cell I've clicked.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, Grids, StdCtrls;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}




type
  TThread_populate_stringgrid = class(TThread)

  strict private

f_stringgrid_to_populate:Tstringgrid;
f_name:string;




  protected

    procedure Execute; override;




  public

    constructor Create(a_name:string;a_stringgrid_to_populate:Tstringgrid);




  end;



constructor TThread_populate_stringgrid.Create(a_name:string;a_stringgrid_to_populate:Tstringgrid);
begin
  inherited Create(False);
  freeonterminate:=true;
  priority:=tpNormal ;

f_name:=a_name;
f_stringgrid_to_populate:=a_stringgrid_to_populate;
end;






procedure TThread_populate_stringgrid.Execute;
begin

Synchronize(
procedure
begin



f_stringgrid_to_populate.cells[0,0]:='DATE';
f_stringgrid_to_populate.cells[1,0]:='NAME';
f_stringgrid_to_populate.cells[2,0]:='ADRESS';
f_stringgrid_to_populate.cells[3,0]:='CITY';
f_stringgrid_to_populate.cells[4,0]:='COUNTRY';


f_stringgrid_to_populate.Cols[0].Add(FormatDatetime('dd-mm-yyyy hh:mm:ss', Now));
f_stringgrid_to_populate.Cols[1].Add(f_name);
f_stringgrid_to_populate.Cols[2].Add('58 RED ROAD');
f_stringgrid_to_populate.Cols[3].Add('ENGLAND');
f_stringgrid_to_populate.Cols[3].Add('UK');



end
)
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
TThread_populate_stringgrid.Create('Andrei',form1.StringGrid1);
TThread_populate_stringgrid.Create('Matei',form1.StringGrid1);
TThread_populate_stringgrid.Create('Iulia',form1.StringGrid1);
TThread_populate_stringgrid.Create('Petru',form1.StringGrid1);
TThread_populate_stringgrid.Create('Gheorghe',form1.StringGrid1);
TThread_populate_stringgrid.Create('Tudor',form1.StringGrid1);
TThread_populate_stringgrid.Create('Cineva',form1.StringGrid1);
TThread_populate_stringgrid.Create('Altcine',form1.StringGrid1);
end;

end.

Thank you!


Solution

  • Here is the solution that works for me:

    -In the main form place a "ApplicationEvents" component.

    -Go to the Events section of the ApplicationEvents

    -double click on "Onmessage" property and add the following procedure

    procedure TForm1.deactivate_mouse_in_advstringgrid(var Msg: tagMSG;
      var Handled: Boolean);
    
     var
      pnt: TPoint;
      ctrl: TWinControl;
     begin
      if (
      (Msg.message = SB_VERT) OR
      (Msg.message = SB_HORZ) OR
      (Msg.message = WS_HSCROLL) OR
      (Msg.message = WS_VSCROLL) OR
      (Msg.message = WM_VSCROLL) OR
      (Msg.message = WM_MOUSEWHEEL) OR
      (Msg.message = WM_LBUTTONDOWN)   OR
      (Msg.message = WM_LBUTTONUP)   OR
      (Msg.message = WM_LBUTTONDBLCLK)   OR
      (Msg.message = WM_MBUTTONDOWN)   OR
      (Msg.message = WM_MBUTTONUP) OR
      (Msg.message = WM_MBUTTONDBLCLK) OR
      (Msg.message = WM_RBUTTONDOWN) OR
      (Msg.message = WM_RBUTTONUP) OR
      (Msg.message = WM_RBUTTONDBLCLK) OR
      (Msg.message = WM_KEYUP) OR
      (Msg.message = WM_KEYDOWN)
      )
    
      then
      begin
    
        if not GetCursorPos(pnt) then Exit;
        ctrl := FindVCLWindow(pnt);
        if Assigned(CTRL) then
       begin
          if Ctrl is TAdvstringgrid then
             begin
            // Msg.hwnd:=ctrl.Handle;
          //Msg.hwnd := advsg1.Handle;
                if thread_activ>0 then
                   begin
                  Msg.hwnd := 0;
                  Exit;
                    end
                else
                  begin
                  Msg.hwnd:=ctrl.Handle;
                 end;
      end;
      end;
      end;
    end;
    

    If you use a Tadvstringgrid component change this code to "if Ctrl is TAdvstringgrid".

    If you use a Stringgrid change this to "if Ctrl is TStringgrid".

    The above procedure uses a global variable called "thread_activ" that contains the number of active threads. So if there are active threads using the Advstringgrid component the mouse clicks, mouse wheel, scroll bars, and key presses are supressed.

    The thread is stored in a second unit having the following code:

    unit thread_stringgrid;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, Grids, StdCtrls;
    
    
    type
      TThread_populate_stringgrid = class(TThread)
    
      strict private
    
    f_stringgrid_to_populate:Tstringgrid;
    f_name:string;
    
    
      protected
    
        procedure Execute; override;
    
    
    
      public
        CriticalSection: TRTLCriticalSection;
        constructor Create(a_name:string;a_stringgrid_to_populate:Tstringgrid);
      end;
    
    
    
    implementation
    
    {use the unit that holds the global vaiable "thread_activ"}
    uses unit1;
    
    
    
    constructor TThread_populate_stringgrid.Create(a_name:string;a_stringgrid_to_populate:Tstringgrid);
    begin
      inherited Create(False);
      freeonterminate:=true;
      priority:=tpNormal ;
    
    f_name:=a_name;
    f_stringgrid_to_populate:=a_stringgrid_to_populate;
    end;
    
    
    
    procedure TThread_populate_stringgrid.Execute;
    begin
    
    //before the threads starts
    InitializeCriticalSection(CriticalSection);
    
    //in the thread
    EnterCriticalSection(CriticalSection);
    //From now on, you can safely make
    //changes to the variables.
    
    {increment variable from main unit1}
    inc(unit1.thread_activ);
    
    //End of safe block
    LeaveCriticalSection(CriticalSection);
    
    Synchronize(
    procedure
    begin
    
    f_stringgrid_to_populate.cells[0,0]:='DATE';
    f_stringgrid_to_populate.cells[1,0]:='NAME';
    f_stringgrid_to_populate.cells[2,0]:='ADRESS';
    f_stringgrid_to_populate.cells[3,0]:='CITY';
    f_stringgrid_to_populate.cells[4,0]:='COUNTRY';
    
    
    f_stringgrid_to_populate.Cols[0].Add(FormatDatetime('dd-mm-yyyy hh:mm:ss', Now));
    f_stringgrid_to_populate.Cols[1].Add(f_name);
    f_stringgrid_to_populate.Cols[2].Add('58 RED ROAD');
    f_stringgrid_to_populate.Cols[3].Add('ENGLAND');
    f_stringgrid_to_populate.Cols[3].Add('UK');
    
    
    
    end
    );
    
    {eliminate thread counter from global variable "thread_activ"}
     EnterCriticalSection(CriticalSection);
      try
    {decrement variable from main unit1}
    dec(unit1.thread_activ);
    finally
     LeaveCriticalSection(CriticalSection);
     end;
    
    end;
    
    (*
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    TThread_populate_stringgrid.Create('Andrei',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Matei',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Iulia',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Petru',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Gheorghe',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Tudor',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Cineva',form1.StringGrid1);
    TThread_populate_stringgrid.Create('Altcine',form1.StringGrid1);
    end;
    
    *)
    
    (*
    procedure TForm1.GridDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    var
      S: string;
      RectForText: TRect;
    begin
      // Check for your cell here (in this case the cell in column 4 and row 2 will be colored)
      //if (ACol = 1) and (ARow = 1) then
      if ((ACol = 1) and (ARow>0))  then
      begin
        S := form1.StringGrid1.Cells[ACol, ARow];
        if (s='Andrei') then
          begin
        // Fill rectangle with colour
        //form1.StringGrid1.Canvas.Brush.Color := clBlack;
        form1.StringGrid1.Canvas.FillRect(Rect);
        // Next, draw the text in the rectangle
        form1.StringGrid1.Canvas.Font.Color := clGreen;
        RectForText := Rect;
        // Make the rectangle where the text will be displayed a bit smaller than the cell
        // so the text is not "glued" to the grid lines
        InflateRect(RectForText, -2, -2);
        // Edit: using TextRect instead of TextOut to prevent overflowing of text
        form1.StringGrid1.Canvas.TextRect(RectForText, S);
          end;
      end;
    
       // if (ACol = 2) and (ARow = 1) then
         if ((ACol = 2)and (ARow>0)) then
      begin
    
        S := form1.StringGrid1.Cells[ACol, ARow];
        if (s='58 RED ROAD') then
        begin
    
        // Fill rectangle with colour
        //form1.StringGrid1.Canvas.Brush.Color := clwhite;
        form1.StringGrid1.Canvas.FillRect(Rect);
        // Next, draw the text in the rectangle
        form1.StringGrid1.Canvas.Font.Color := clRed;
        RectForText := Rect;
        // Make the rectangle where the text will be displayed a bit smaller than the cell
        // so the text is not "glued" to the grid lines
        InflateRect(RectForText, -2, -2);
        // Edit: using TextRect instead of TextOut to prevent overflowing of text
        form1.StringGrid1.Canvas.TextRect(RectForText, S);
        end
        else
        begin
         // Fill rectangle with colour
        //form1.StringGrid1.Canvas.Brush.Color := clwhite;
        form1.StringGrid1.Canvas.FillRect(Rect);
        // Next, draw the text in the rectangle
        form1.StringGrid1.Canvas.Font.Color := clBlue;
        RectForText := Rect;
        // Make the rectangle where the text will be displayed a bit smaller than the cell
        // so the text is not "glued" to the grid lines
        InflateRect(RectForText, -2, -2);
        // Edit: using TextRect instead of TextOut to prevent overflowing of text
        form1.StringGrid1.Canvas.TextRect(RectForText, S);
        end;
      end;
    
    
         //if (ACol = 3) and (ARow = 1) then
         if ((ACol = 3)and (ARow>0)) then
      begin
        S := form1.StringGrid1.Cells[ACol, ARow];
        if s='Altcine' then
        begin
        // Fill rectangle with colour
        //form1.StringGrid1.Canvas.Brush.Color := clwhite;
        form1.StringGrid1.Canvas.FillRect(Rect);
        // Next, draw the text in the rectangle
        form1.StringGrid1.Canvas.Font.Color := clYellow;
        RectForText := Rect;
        // Make the rectangle where the text will be displayed a bit smaller than the cell
        // so the text is not "glued" to the grid lines
        InflateRect(RectForText, -2, -2);
        // Edit: using TextRect instead of TextOut to prevent overflowing of text
        form1.StringGrid1.Canvas.TextRect(RectForText, S);
        end;
      end;
    
     *)
    
    
    
    end.
    

    I hope that this helps others. Have a great day!