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!
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!