Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Advantage/Disadvantage between a BROWSE window or/and a building of a running GRID on a form. 10

Status
Not open for further replies.

german12

Programmer
Nov 12, 2001
563
DE
I have a form with a search-list (incremental search).
Works fine.
I only have to type 1 to 3 letters - and I'm already on the right line - and with one click a browse window opens and shows me detailed results from a table.

This is of course easier to represent than to a GRID on the form.
You can also navigate in a browse window without writing any code oder filling headers etc.

My question:
Can a reduced BROWSE window be shown on the form at the same time if there is still enough space on the form?
Or - can a BROWSE windows can only be displayed on their own - but this means that the BROWSE window must first be closed manually in order to get back to the search list on the form.

I hope this question is not too stupid.
Up to now I always tryed to avoid GRIDS - but may be that this "fear" is exaggerated

I am very interested in your opinion.

Klaus

Peace worldwide - it starts here...
 
In pre-VFP days, people spent way too much time trying to coordinate Browses with screens. We were all delighted when VFP added grids, so we didn't have to do that anymore.

Use a grid.

Tamar
 
Hi Klaus,

I suggest you read the help file about the BROWSE and the DEFINE WINDOW command

Can a reduced BROWSE window be shown on the form at the same time if there is still enough space on the form?

AFAIK - No, it can be only shown in the main VFP Screen, can overlap the form, but CANNOT be shown IN the form

... this means that the BROWSE window must first be closed manually in order to get back to the search list on the form.

No, you may program it in order to CLOSE when it looses focus or after a certain TIMEOUT you specify.

Up to now I always tried to avoid GRIDS - but may be that this "fear" is exaggerated

Well that's your decision but you may want to rethink it - GRIDS are in may ways more powerful than BROWSE

Below a sketch of code how you could address this issue.

Code:
PUBLIC oForm
 
oForm = CREATEOBJECT("clssearch")
oForm.visible = .t.

Read EVENTS

CLOSE ALL

CLEAR ALL 

RETURN 

***********
 
DEFINE CLASS clssearch AS form
 
	Top = 12
	Left = 12
	Height = 474
	Width = 288
	MinWidth = This.Width
	Caption = "Incremental Search"
	WindowState = 0
	AutoCenter = .T.
	Name = "clssearch"
	
	ADD OBJECT cmdBrowse as CommandButton WITH ;
		Top = 12, Left = 12, Height = 24, Autosize = .T., Caption = "Open Browse Window"
		
		PROCEDURE cmdBrowse.Click()
			lcWord = "" 
			
			DEFINE WINDOW wBrowse FROM 1, 1 TO 42, 90 ;
				FONT "Arial", 8 ;
				CLOSE ;
				FLOAT ;
				GROW
				
			SELECT csrWords
			lcWord = ThisForm.List1.List(ThisForm.List1.ListIndex)
			= INDEXSEEK(lcWord, .T., "csrWords")

			BROWSE WINDOW wBrowse ;
				FIELDS cWord :H = "Word", iValOne :H = "Value One", iValTwo :H = "Value Two" ;
				NOEDIT ;
				TIMEOUT 25

			RELEASE WINDOW wBrowse
			
		ENDPROC 

	ADD OBJECT list1 AS listbox WITH ;
		Height = 408 - 12, ;
		Left = 12, ;
		Sorted = .T., ;
		Top = 60, ;
		Width = 264, ;
		Name = "List1", ;
		Anchor = 15, ;
		IncrementalSearch = .T.

	PROCEDURE Load()
		CREATE CURSOR csrWords ( cWord C(35), iValOne I, iValTwo I)
		
		INDEX on cWord TAG tagWord
		SET ORDER to tagWord
	
	ENDPROC 
	
	PROCEDURE Init
		LOCAL lnI, lnY, lnWordLength, lcItem, lnUpper, lLower, liAscii
  
		lnUpper = 90 &&ASCII
		lnLower = 65 &&ASCII
  
		FOR lnI = 1 to 100
			lcItem = ""

			lnWordLength = INT((35) * RAND()) + 1
   
			FOR lnY = 1 TO lnWordLength
				lcItem = lcItem + CHR(INT((lnUpper - lnLower + 1) * RAND( )) + lnLower)
			ENDFOR

			ThisForm.List1.AddItem(lcItem)
			
			INSERT INTO csrWords VALUES (lcItem, RAND() * 5000, RAND() * 1250)

		NEXT   
	ENDPROC
	
	PROCEDURE Destroy()
		ThisForm.Release()
		CLEAR Events
			
	ENDPROC              

 
*!*		PROCEDURE Activate
*!*			thisform.text1.setfocus()

*!*		ENDPROC 

*!*		PROCEDURE list1.interactivechange
*!*			thisform.text1.value = this.value
*!*	    	thisform.text1.refresh()
*!*		ENDPROC
*!*	  
*!*		PROCEDURE text1.interactivechange
*!*			LOCAL nCnt, sSearchFor, nLen

*!*			sSearchFor = ALLTRIM(this.value)
*!*			nLen = LEN(sSearchFor)

*!*			FOR nCnt = 1 TO ThisForm.List1.ListCount
*!*				IF AT(sSearchFor, ALLTRIM(ThisForm.List1.List(nCnt))) > 0
*!*					Thisform.List1.Selected(nCnt) = .t.
*!*					thisform.List1.refresh()
*!*				EXIT &&Found one

*!*			ENDIF 	
*!*		  ENDFOR
*!*		ENDPROC

ENDDEFINE

**********

hth

MarK
 
A browse is a grid within a window. So why do you really want to have a browse window in your form, if you can have a grid. Just because you're more familiar with the BROWSE command, perhaps?



Chriss
 
Chriss
My answer is Yes
But I am willing to relearn and experience the benefits of a Grid

Klaus

Peace worldwide - it starts here...
 
Tamar has it.

If you know the structure and the intent (business object) go for a grid

If you don't know the structure, a browse is good.

Ten points to T!

Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
Klaus, what kind of BROWSE command options do you make use of? The FOR clause is the most often used besides the pure BROWSE.

Is it that you need to set so many grid properties and the columns to get the same? Actually a grid you set to rowsourcetype alias and open up an alias automatically becomes a browse of that alias, without further ado. And a FOR clause is just a SET FILTER of that alias..

There's more to browse, but in the end it is a grid, really.

Do your favorite/most complex BROWSE command, but add NAME browsegrid NOWAIT, and then do
browsegrid.saveasclass('mygrids.vcx','thisgrid')

Open the class in the class designer, use the properties window and set it to "nondefault properties only" and you see which specialties (if any) of the grid and its columns are used. On the grid level mainly you have a column count specific to the fieldcount of the workarea you browsed. And in all the columns you have the controlsource of a field. That's mainly all there is to it.

PS: As I see Mikes adice, I want to add that this method(saveasclass) has pros and cons in comparison with Mikes suggestions. First, saveasclass is not special, it's available for any class/object and I pointed it out as it enables you to inspect what the browse command you used actually set up as a grid and at the same time to show the browse actually is a grid. What's not saved - as it's not actually properties of the grid - is which DBFs are open in which workareas, so to use such a grid class later, you still have to open the table first. Mike's way to drag a table onto a form - especially in the case you drag it from the data environment - ensures that you have that DBF open, when you run the form. As always you can also get help to configure a pure empty grid you put on a form from the form controls toolbar, by a right click on it and using the builder. So there are many ways to get to a populated grid.

SaveAsClass is a simple way to "conserve" an object and its current state, too. So one advantage of the saveasclass method is that you can inspect how you get to the same grid as the browse command you used and more generally how a control or any object is set at the time you save it as a class, so it's also a tool for debugging and inspection of a state something was in at the time of saving it.

Chriss
 
Hi Klaus,

Keep it simple!

Below a sample how to combine a GRID with INCREMENTAL search and COMPUTED columns.

Code:
PUBLIC oForm
 
oForm = CREATEOBJECT("clssearch")
oForm.Show()

Read EVENTS

CLOSE ALL

CLEAR ALL 

RETURN 

***********
 
DEFINE CLASS clssearch AS form
 
	Top = 12
	Left = 12
	Height = 474
	Width = 930
	MinWidth = This.Width
	Caption = "Incremental Search"
	WindowState = 0
	AutoCenter = .T.
	Name = "clssearch"
	Themes = .F.
	
	ADD OBJECT lblName as Label WITH ;
		Left = 12, Top = 12, Caption = "Name to search", FontBold = .T.
	
	ADD OBJECT txtBox as TextBox WITH ;
		Left = 12, Top = 36, Format = "!"
		
		PROCEDURE txtBox.GotFocus()
			This.Value = ""

		ENDPROC 
		
		PROCEDURE txtBox.InteractiveChange
			LOCAL lcSearch
			
			lcSearch = ALLTRIM(This.Value)
			= INDEXSEEK(lcSearch, .T., "csrWords")
			ThisForm.grdValues.Refresh()

		ENDPROC 
			

	ADD OBJECT grdValues AS Grid WITH ;
		Height = 408 - 24, ;
		Width = 930 - 24, ;
		Left = 12, ;
		Top = 72, ;
		Anchor = 15, ;
		ColumnCount = -1, ;
		RowSourceType = 2, ;
		RowSource = "csrWords"
		
		PROCEDURE grdValues.Init()

			WITH This
				.SetAll("FontBold", .T., "Header")
				.SetAll("BackColor", RGB(0, 250, 250), "Header")
			ENDWITH 

			WITH This.Column1
				.Width = 246
				.Header1.Caption = "Name"
			ENDWITH

			WITH This.Column2
				.Width = 150
				.Header1.Caption = "Value One"
			ENDWITH
			
			WITH This.Column3
				.Width = 150
				.Header1.Caption = "Value Two"
			ENDWITH

			WITH This.Column4
				.Width = 150
				.Header1.Caption = "VO + VT"
			ENDWITH

			WITH This.Column5
				.Width = 150
				.Header1.Caption = "VO - VT"
			ENDWITH
		ENDPROC  

	PROCEDURE Load()
		LOCAL lnI, lnY, lnWordLength, lcItem, lnUpper, lnLower

		lnUpper = 90 &&ASCII (Z)
		lnLower = 65 &&ASCII (A)

		CREATE CURSOR csrWords ( cWord C(35), iValOne I, iValTwo I, iValOT I, iValTO I)
		INDEX on cWord TAG tagWord
		SET ORDER to tagWord
  
		FOR lnI = 1 to 1500
			lcItem = ""

			lnWordLength = INT(35 * RAND()) + 1
   
			FOR lnY = 1 TO lnWordLength
				lcItem = lcItem + CHR(INT((lnUpper - lnLower + 1) * RAND()) + lnLower)
			ENDFOR

			INSERT INTO csrWords VALUES (lcItem, RAND() * 5000, RAND() * 1250, 0, 0)
			UPDATE csrWords SET iValOT = iValOne + iValTwo, iValTO = iValOne - iValTwo

		ENDFOR 
	ENDPROC 
	
	PROCEDURE Destroy()
		ThisForm.Release()
		CLEAR Events
			
	ENDPROC              
ENDDEFINE

**********
 
Klaus,

You should definitely take the trouble to learn to use a grid. It gives you everything a Browse gives, plus a lot more. And once you have understood how to use it, it is not at all difficult to program. Browse is useful in the development environment, but the only reason to use it within an application is for backward compatibility with Foxpro 2.x and earlier.

Griff makes the point that you should use Browse If you don't know the structure of the table. But that works for a grid as well.

Deciding to use a grid is a bit like deciding to learn object-oriented programming. You can manage perfectly well without it, but you are not really getting the full benefit of VFP.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Hello,

Tamar is right. 10 points to her.

Grid is part of the form : if form gets resized or moved, the grid will be resized/moved with it without add.programming. Thats a big advantage if user uses 2 monitors.

Grid has "Dynamic propertys" , so it can show for example columns/rows backcolor as green if an anmount is bigger then xxx and/or as red if the amount is less then yyyy. You can use function and make really complex conditions/colours.

If user moves to another row (or col) within the grid, an event is triggered. We use that to show details for the actual record on form after user moves to/selects another row.

Its very easy to have different fonts / attributes for each columns if you like and you can make columns invisible in runtime or change width,...

There are functions from VFP-programmers which automatically show sums/subsums or present data like a treeview or generate a report from grid (including formatting) with a click.

.....


The other tips should help, its realy worth it.

Best regards
tom
 
The VFP grid is probably the single best feature of the development environment.

It is so far ahead of the equivalent in C#... just miles better.

The only place I use Browse over a grid is in my silly little 'on-the-spot' browser
utility that I install on my servers to enable forensic / ad hoc examination of tables.



Regards

Griff
Keep [Smile]ing

There are 10 kinds of people in the world, those who understand binary and those who don't.

I'm trying to cut down on the use of shrieks (exclamation marks), I'm told they are !good for you.

There is no place like G28 X0 Y0 Z0
 
I agree with using a grid instead of BROWSE (at least 95%, anyway). It's way more controllable in my opinion.

Having said that, I'm guilty of using BROWSE in some of my apps where I'm the only user. Instead of a grid, I just add a BROWSE button for a quick & dirty (& lazy) way to locate & change data. Old habit. [upsidedown]

Steve
 
Klaus, could I suggest an easy way for you to get started with grids (apologies if you already know this):

1. Open a form in the Form Designer.

2. Drag a table and drop it onto the form. You can drag it from the form's Data Environment, a VFP Project Manager window, or even Windows Explorer.

3. Save and run the form.

You now have a fully-functioning grid, showing all the data in the table. It's that simple. (But, of course, you will almost certainly want to customise the grid in various ways.)

If you only want to show specific fields in the grid, add the table to the form's Data Environment, then multi-select the fields you're interested in (hold down Ctrl and/or Shift while you select the individual fields). Drag these to the form.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
As the others have said, the grid is the way to go with VFP. The browse is okay for a quick view of a table during development; however, I wrote my own browse application that runs inside VFP to replace the standard BROWSE command which uses grids because I don't like the limitations of BROWSE command. See screen shot:

2023-04-18_13-35-09_onrte6.jpg



Greg
 
Klaus,

My opinion, for what it is worth. Take the time to learn to use the grid. Even if you can get by without it right now, there will likely come a point where a browse window just won't give you the degree of control and options that you really need and a grid will be the solution. Embrace it sooner rather than later. You will be glad you did!

Alec
Santa Barbara, California
 
Let me point out the one thing you can hardly do with a browse: Foreign keys. This aspect means you don't have a nice and human-readable form of foreign keys in your browse windows. And this misleads you into a data design without foreign keys, the actual core concept of relational databases.

Chriss
 
To show what I mean with "hardly":

You can design the data structure with foreign keys and browse data this way, for example - making use of SET RELATION and BROWSE FIELDS:
Code:
Create Database football.dbc
Create Table teams (id int autoinc primary key, teamname c(20))
Insert into teams (teamname) values ('eagles')
Insert into teams (teamname) values ('chiefs')
Use

Create Table games (id int autoinc primary key, hometeam int, awayteam int, scorehome int, scoreguest int)
Insert into games (hometeam, awayteam, scorehome, scoreguest) values (1,2,35,38)
Use

Use teams in 0 alias team1 Order id
Use teams in 0 alias team2 Order id again
Select 0
Use games
Set relation to hometeam into team1
Set relation to awayteam into team2
Browse fields host=team1.teamname, guest=team2.teamname, scorehome, scoreguest

This is not that straight forward, you need to dig into the xBase way of setting relations on one hand and also know about the FIELDS feature of browse capable to show fields of other workareas, on the other hand. So this requires several insights into how Foxpro works. And I bet you most beginners wouldn't go for that but simply have the hometeam and awayteam fields being chars and not have a teams DBF at all.

And even if you go that far, know all that, and do your browse this way, you now have readonly columns host and guest. The solution to that using the grid control instead of the browse is to have comboboxes in the team columns and use the team ids as controlsource to show the team name as a combobox item. and also be able to select a teamname and set the team id through it.

Chriss
 
Yesterday I posted a thank you note for everyone here, but - although I saw it in Tek-Tips under this thread, it wasn't visible today.
I do not know, why.
So - again: Thank you all very much for your great and kind help - I am now also convinced that it is more efficient to work with GRID than with BROWSE - basically all answers say this in unison.
Too bad I can't spend a round of beer on it here -
that would be easy for me
.
Now I need some time to familiarize myself with GRID.
The first question follows immediately.

Klaus

Peace worldwide - it starts here...
 
Mike L.

Thank you for your showing me an easy way for you to get started with grids.
That works with a table in this case named Aktien2.dbf
I can see now a form, and the grid1, which shows me all the fields of dbf Aktien2.dbf
The first field-name of Aktien2.dbf is named Ak2begriff

The question is now for me:
I added a commandbutton on the form and in the CLICK of that commandbutton I coded:
Select DISTINCT(ak2begriff) from aktien2 into cursor mycursor
because I wanted to see another content in the grid.

but then I struggled where the following questionmarks are:

SET FULLPATH on
SELECT distinct(ak2begriff) FROM aktien2 INTO cursor mycursor
thisform.grid1.recordsource = [highlight #EF2929]???[/highlight]
thisform.grid1.recordsourcetype = [highlight #EF2929]????[/highlight]
thisform.Refresh

What hast to be done or to be filled here?
Several trials from my side failed.

Thanks
Klaus





Peace worldwide - it starts here...
 
Hi Klaus,

This is where BROWSE simply creates a new grid initially having no columns that can then simply show what's in the current workarea., but once a grid has its columncount and column onbjects each with a controlsource, that doesn't change simply because you change the recordsource.

So you see a grids intent is not to use the same grid to show different workareas. You design it for one structure and then keep it at that. You can make columns movable, so you can interactively change column order, you can set column visibility to turn on or off columns, but once a column exists from the first recordsource the grid had, it's there until you remove it or until you close the alias that is the grids' source of data.

It's not hard to get to what you want, even if it's not the main intent. You can always get rid of the grid content by simply closing it's workarea. So do
Code:
SELECT (thisform.grid.recordsource)
USE
Thisform.grid1.RecordSource='mycursor'
And you get new columnobjects set to the new structure. The only thing you reuse then is the position and size of the grid.

Think about usual applications that use a grid or a control similar to it. Let's say the file explorer files list. You can have very different lists reorder items, resize their widths, pick columns to show or not show, etc. Well, and the VFP grid offers all that too, interactively. You can move columns, resize their width, you can not set them visible=.f. with the user interface alone, but this possibility can be given to the user.

If you would use this concept of closing workarea and setting a new one, you can't add permanent things to the grid that make it more useful than a browse, but at least you'd use the property of the grid to not be a separate window, but a control with position and size on the form. If that's all you need from the grid, then that's your solution.

A variation to not need to close the previous workarea is to remove columns before setting the new recordsource. This way works:
Code:
Thisform.grid1.resettodefault('columncount')
Thisform.grid1.RecordSource='mycursor'

Interestingly, if you try the simpler Thisform.grid1.columncount=0 setting a new recordsource alias does not trigger the grid to create new columns. You then have to do
Code:
Thisform.grid1.columncount=0
Thisform.grid1.columncount=fcount('mycursor')
Thisform.grid1.RecordSource='mycursor'

In the aspect of using the grid for such interactively changing data sources you waste some of the possibilities of the grid as you throw away the grid substructure and recreate it. But it's just as good as browses with a fixed position inside your form.

Now, if your next button should bring back the full aktien2.dbf, then you better have 2 grids in the form, of course. Keep grid1 to display aktien2.dbf and use something to switch grids. In the simplest case have a pageframe with 2 pages and a grid on each of them and set activepage. If you design a grid with all bells and whistles at design time, with dynamic coloring and code in column controls, you don't want to throw that away just to display something else temporarily. You could always integrate one such "throwaway" grid or even create new grid objects at runtime with thisform.addobject('gridx','grid') and thereby emulate creating browse windows without having the windows. But that's not truly the best use of a grid.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top