Sunday, July 28, 2013

A neat hack: right clicking a grid's title bar

In Priority, our ERP program, there is a neat function in which enables one to right click the title of a numeric column;  the total of that column is then displayed. I was reminded of this the other day when I sat with the Occupational Psychologist, looking at a list of dockets which had yet to be paid.

After looking into the matter, it turns out that one has to use the grid's OnMouseDown event and not the OnTitleClick event, as one might naively assume. A dbGrid has the useful function MouseCoord which returns on which line the mouse was when it was clicked, and in which column; the title bar of the mouse is row 0. The first line in the code below checks to see that it was the right button which was clicked on the mouse and that the click was on the title bar. Once this has been checked, we can get on with calculating the total of one of the columns. In the form where I used this procedure, columns 4, 5 and 6 - as they appear on the screen - have numerical data. As far as the underlying dataset (qDockets, a clientdataset) is concerned, these are actually fields 3, 4 and 5; the extra screen column (0) would appear to be the row indicator column. Originally I was going to use two case statements, one for choosing which field had to be summed and one for the message at the end, but I realised that I could access the dataset's fields array and save an expensive case statement.

For those that understand these things, I think that the code below is fairly self-explanatory. The "format ('%1.0m')" is a way of getting a number like 1234 to display as 1,234, as well as adding the currency symbol. As the defined width of the string is 1, there will be no extra white space between the number and the equals sign.

procedure TDoDocketsA.grDocketsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var total, old: longint; col: integer; begin if (button= mbRight) and (grDockets.MouseCoord(X,Y).Y = 0) then begin total:= 0; col:= grDockets.MouseCoord(X,Y).x; if col in [4,5,6] then begin old:= qDocketsID.asinteger; with qDockets do try disablecontrols; first; while not eof do begin inc (total, qDockets.fields[col-1].asinteger); next end; finally locate ('id', old, []); // go back to where we were enablecontrols end; hebcontdlg (qDockets.fields[col-1].displaylabel + ' = ' + format ('%1.0m', [total + 0.0])); end end end;
It would be nice to make the above routine as general as possible but that involves knowing which fields are numerical which means traversing the fields array at the beginning of the procedure and checking each field's type. At the moment, I don't know whether I am going to use this routine in other forms so I am not going to generalise it.

No comments: