Welcome To The Home Of The Visual FoxPro Experts  
home. signup. forum. archives. search. google. articles. downloads. faq. members. weblogs. file info. rss.
GRIDS >>  ADD MULTISELECT FUNCTIONALITY TO A GRID CONTROL

  Chris Chamberlain
  Where is Chris Chamberlain?
 GL6 0PN
 United Kingdom
 Chris Chamberlain



If you want to add MultiSelect functionality to a grid that emulates Windows Explorer behaviour, try the following:

1 - Subclass a grid into a suitable class library;
2 - Add 4 new properties to the class:

.lMultiSelect with value of .F.
.nActiveRow with value of 0
.nLastRow with value of 0
.nRecs2Change with value of 0

3 - Add 1 new method:
.mSelectRecords()

4 - Ensure the .RecordSource of the grid is not indexed, so create it from a SELECT - SQL statement. The .RecordSource also requires an additional logical field, selected;
5 - In the .AfterRowColChange() event of the grid, put:

THIS.mSelectRecords()


6 - In the .mSelectRecords() event of the grid, put

LOCAL lcSelected,;
	lcRecordSource

#DEFINE VK_lSHIFT 0x10 && Relocate to a header file
#DEFINE VK_lCONTROL 0x11 && Relocate to a header file
DECLARE INTEGER GetKeyState IN WIN32API INTEGER && Relocate to where WinAPI calls are declared

WITH THIS
	.nActiveRow       = .ACTIVEROW && Assign value to class property
	lcSelected = .RECORDSOURCE + [.selected] && Assign value to local variable
	lcRecordSource = .RECORDSOURCE && Assign value to local variable
	DO CASE
		CASE GetKeyState(VK_lSHIFT)     < 0       ;
				OR GetKeyState(VK_lSHIFT) > 1 && Check for shift key press
			DO CASE
				CASE .nLastRow > .nActiveRow && Last recd below current recd in grid
					.nRecs2Change = .nLastRow - .nActiveRow          && Calculate no of recds to change
					REPLACE (lcSelected) WITH .T. IN (lcRecordSource) && Replace current recd
					FOR i = 1 TO .nRecs2Change
						REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
						SKIP IN (lcRecordSource)
					ENDFOR
				CASE .nLastRow < .nActiveRow && Last recd above current recd in grid
					.nRecs2Change = .nActiveRow - .nLastRow          && Calculate no of recds to change
					REPLACE  (lcSelected) WITH .T. IN (lcRecordSource) && Replace current recd
					GO .nLastRow IN (lcRecordSource) && Goto the last recd
					FOR i = 1 TO .nRecs2Change
						REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
						SKIP IN (lcRecordSource)
					ENDFOR
			ENDCASE

			.lMultiSelect = .T.
		CASE GetKeyState(VK_lCONTROL) < 0 ;
				OR GetKeyState(VK_lCONTROL) > 1 && Check for control key press
			REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
			.lMultiSelect = .T.
		OTHERWISE && Neither shift or ctrl pressed
			DO CASE
				CASE .lMultiSelect
					REPLACE (lcSelected) WITH .F. ;
						ALL IN (lcRecordSource) && Update all recds
				CASE .nLastRow # 0
					TRY
						GO .nLastRow IN (lcRecordSource)
					CATCH
						GO BOTTOM IN (lcRecordSource)
					ENDTRY
					REPLACE (lcSelected) WITH .F. IN (lcRecordSource)
			ENDCASE
			GO .nActiveRow IN (lcRecordSource) && Change new value
			REPLACE (lcSelected) WITH .T. IN (lcRecordSource)
			.lMultiSelect = .F.
	ENDC
	IF RECCOUNT(lcRecordSource) > 0
		DO CASE       && Set colours according to OS
			CASE UPPER(OS(1)) = [WINDOWS 5.00] && Win 2K
				.SETALL([DynamicBackColor],;
					"IIF(&lcSelected, RGB(10,36,106), RGB(255,255,255))",;
					[Column])
			CASE UPPER(OS(1)) = [WINDOWS 5.01] && Win XP
				.SETALL([DynamicBackColor],;
					"IIF(&lcSelected, RGB(49,106,197), RGB(255,255,255))",;
					[Column])
			CASE UPPER(OS(1)) = [WINDOWS 6.00] && Vista
				.SETALL([DynamicBackColor],;
					"IIF(&lcSelected, RGB(51,153,255), RGB(255,255,255))",;
					[Column])
                        CASE UPPER(OS(1)) = [WINDOWS 6.01] && Windows 7
				.SETALL([DynamicBackColor],;
					"IIF(&lcSelected, RGB(51,153,255), RGB(255,255,255))",;
					[Column])
		ENDCASE
		.SETALL([DynamicForeColor],; && All OS
			"IIF(&lcSelected, RGB(255,255,255), RGB(0,0,0))",;
			[Column])
		.nLastRow = .nActiveRow        && Mark current row for next time through
	ENDIF
ENDWITH
************************************************


Left mouse click will select the current record only, shift + click followed by shift + click will select a block of records, and ctrl + click will select individual records, all selected records being highlighted.
Scrolling with the arrow keys does not select records.

You can programmatically determine if there are multiple selected records with:-
IF THISFORM.grid1.lMultiSelect
            *!*       Code
ENDIF

You now have a scope clause available for copying, printing, deleting etc, expressed as:-
REPORT FORM reportname.frx FOR CURSORNAME.selected

FEEDBACK

Biju Thomas @ 12/2/2007 6:45:52 PM
Amazing.

Chong @ 5/31/2008 6:05:57 PM
This is excellent !

Do note that there is no OS detection for Vista. If not added, the selected rows appears "blank" under Vista

Mayur Subbu @ 4/12/2009 2:28:42 PM
Hi Chris,

Tried it out but the selected record blanks out. I am using windows server 2003 and VFP 9 sp2.

Any suggestions

shi yangyang @ 11/10/2009 8:46:22 AM
tried it out but i dunnoe about these area:
WITH THISform
.nActiveRow = 11 && Assign value to class property
lcSelected = .RECORDSOURCE + [.selected] && Assign value to local variable
lcRecordSource = .RECORDSOURCE && Assign value to local variable

Chris Chamberlain @ 11/10/2009 9:06:42 AM
Any suggestions, (shi yangyang)

By changing THIS to THISform you are changing the name of the object, the property values of which you are reassigning.

THIS relates to the grid, THISform relates to the form, so the method will error out as those properties are not properties of the form.

Chris

shi yangyang @ 11/12/2009 7:01:04 AM
Thank you Chris,
Sorry, i still got problem.. Please help me..

.nActiveRow = .ACTIVEROW && Assign value to class property
lcSelected = .RECORDSOURCE + [.selected] && Assign value to local variable
lcRecordSource = .RECORDSOURCE && Assign value to local variable


I have the program error as: Property activerow is not found.
and what should i put at .recordsource?

wait for your reply..
Thank you..

shi yangyang @ 11/12/2009 8:30:30 AM
what shall i replace for .activerow and .recordsource?

Chris Chamberlain @ 11/12/2009 4:58:24 PM
shi

Sounds as though you have not assigned a value to .recordsource, IOW the name of the cursor/table that you wish to view in the grid.

Without a .recordsource, there will be no .activerow.

If you wish to assign the .recordsource of the grid in code, then use something like 'THISFORM.grid1.RecordSource = [MyTableName]', otherwise do it in the property sheet for the grid itself.



Your Name: 
Your Feedback: 

Spam Protection:
Enter the code shown: