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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Selecting record from a Grid for use in another form

SitesMasstec

Technical User
Sep 26, 2010
502
BR
Hello collegues!
I have a Form with a Grid populated with just some data from file RESERVAS.DBF:GridSelecao.jpg
When I locate the record I need, I want the form above to desappear and open another Form which has all data from that selected record:

FichaSelecionada.jpg

The field "Localizador" is a unique key for each record in the table.
I tried to put in the Grid (first picture), Column1, Text1, Click event, the commands:
Code:
YLOCALIZA=this.Value
thisform.Release
DO FORM RELRESERVAS
But it presented error...

Isn't this the correct approach to achieve what I want to do?
 
It looks like you are trying to execute the form after you've released it. As far as I know, any lines after releasing the form will not execute.

The cleanest way to handle this is to keep the first form active, but potentially invisible.

For example:

thisform.visible = .f.
do form RELRESERVAS
thisform.visible = .t.
thisform.refresh() && optional, if you think the value of the second form will change things on the first form.

When the RELRESERVAS form ends, it will take you back to the original form with the grid. If that's not what you wanted, I would use another approach.
 
It seems to me that you are over complicating this process. We have a similar behavior on pretty much every maintenance form we have, whcih is a lot but we are using PageFrame with 2 pages(actually, we have more than 2 pages but , anyway). You select the record on the first page that has a grid, then Activate Page 2 that has all those controls and that's all there is to it.
Theoretically, you can call another form using click on the grid record and pass the target value as a parameter to DoForm(), on INIT() assigned it to a form property or public variable , then use a dataset similar to the first form and then use passed parameter to locate a target record. Something like that without a lot of details
 
Another way to do this is to just create a container on the same form. The container has all the controls for the details of the grid row. When you design, just have it down below the grid and invisible. When you click a row in the grid, the code makes the grid invisible (or move it down out of view) and makes the container with the detailed view visible and at the top of the form.

To get back to the grid I just put a command button labeled Exit which does this in reverse: make the container invisible and the grid visible.

I often use this approach but have also used the page frame approach which works very well too.
 
Joe: the form has in the ControlSource for the columns, reservas.localiza, reservas.emissão, etc (RESERVAS.DBF is the Data Environment).
When this form call the 2nd form, it shows error (File already open).
I'm trying to get around this problem.

Igorsandler and Doug: the 2nd form that is called is too big, takes all screen area, has lots of data from 2 tables (RESERVAS.DBF, also used in the 1st form, and PASSAGEIROS.DBF). In fact the second form already uses what you have suggested, Pageframe with 6 pages, in just half part of the form.
 
Joe: the form has in the ControlSource for the columns, reservas.localiza, reservas.emissão, etc (RESERVAS.DBF is the Data Environment).
When this form call the 2nd form, it shows error (File already open).
I'm trying to get around this problem.

Igorsandler and Doug: the 2nd form that is called is too big, takes all screen area, has lots of data from 2 tables (RESERVAS.DBF, also used in the 1st form, and PASSAGEIROS.DBF). In fact the second form already uses what you have suggested, Pageframe with 6 pages, in just half part of the form.
I'm not a fan of data environments because I like the freedom of letting my customers switch directory paths and manage data for entirely different companies, so I open dbf files programmatically before loading forms or in the load event. This gives me freedom of which dbf files to open and when.

That said, I would've assumed that if the files were already open it would ignore it.

Anyhow, I know there are options to either autoopentables on loading or autoclosetables when closing a form, giving you at least some control when you use data environments.

Without a data environment in the form, you would just need to open each table manually in the load event. In my programs, I handle that through a simple PRG that checks to see if the file is already opened, and opens it only if it's not already USED.
 
I agree totally with you, Joe. I also prefer to have the files in a program (PRG), select the records and fields I will use in a form or report, and save then in a Cursor, as I did in the form I am working now:
Code:
SELECT LOCALIZA, EMISSAO, CODAGENTE, NOMAGENTE, NOMECIA, NOMENAV, DATASAIDA, DOCUMENTO ;
  FROM RESERVAS WHERE (EMISSAO>=XQualPDEmissao AND EMISSAO<=XQualUDEmissao) INTO CURSOR curReservas

Then, in the form, Grid, for each field I used the fields in the Cursor: curreservas.localiza, curreservas.emissão, etc (instead of my previous reservas.localiza, reservas.emissão, etc).
 
A problem has arisen:
I have these commands in the colums, headers, for each time the user click on a header, the records are sorted in ascending order.
For example, in the column for the header of LOCALIZA field, I have the comands, in the Click event:
Code:
SET ORDER TO LOCALIZA
thisform.Refresh
GOTO TOP

Well, this was when I was using the table.field (Data Environment), now I am using a Cursor to generate data in the Grid.
How to have the same effect for a Cursor? (to have the records sorted according to the chosen column/field)
 
A problem has arisen: ...
I suppose the simplest way would be to create tag indexes when you create the cursor. (But apparently the cursor has to be readwrite.) You could even write one procedure that would work for any column by making the tag name the same as the field name. Then you can reference the this.Parent.ControlSource value of the header to get the name of the field and hence the name of the tag. So you have one procedure you can call from the click event for any header.
My procedure would be something like this. It should work but I didn't test it. (My style standard is that keywords are always lower case, user defined are upper case.)
Code:
procedure SortColumn
    lparameter oHEADER    && pass the header object using "this" in the click event: "do SortColumn with this"
    local mFIELD
    mFIELD = trim(oheader.Parent.ControlSource)    && I usually trim if I'm uncertain whether extra spaces might cause problems.  you might also have to chop off the cursor name if it's part of the control source value as in mFIELD = substr(mFIELD, at('.',mFIELD )+1)

    set order to (mFIELD)
    go recno()    && jiggle things but leave the pointer on the same record (may not be necessary, not sure.) or you could use "go top" depending on what you want.
    oheader.Parent.Parent.Refresh && refresh the grid
return

Or for simplicity if you already have the code in the grid's header, make the indexes the same name as the indexes for the table. Then you don't have to change anything. I just like the idea of not having different code for doing the same thing
 
Doug:
In my program (PRG) that calls the Form (with the Grid presenting the fields), I put this code and it worked fine:

Code:
SELECT LOCALIZA, EMISSAO, CODAGENTE, NOMAGENTE, NOMECIA, NOMENAV, DATASAIDA, DOCUMENTO FROM RESERVAS;
  WHERE (EMISSAO>=XQualPDEmissao AND EMISSAO<=XQualUDEmissao) INTO CURSOR curReservas

INDEX ON LOCALIZA TAG LOCALIZA           && Is this indexing the CURSOR curReservas? (1)
INDEX ON EMISSAO TAG EMISSAO             && Is this indexing the CURSOR curReservas?  (1)
INDEX ON NOMAGENTE TAG NOMAGENTE       && Is this indexing the CURSOR curReservas?  (1)
INDEX ON DATASAIDA TAG DATASAIDA     && Is this indexing the CURSOR curReservas?  (1)
INDEX ON DOCUMENTO TAG DOCUMENTO      && Is this indexing the CURSOR curReservas?  (1)

SELECT RESERVAS            && Is this closing just the table RESERVAS? (2)
USE

It works fine, but I am not sure about itens 1 and 2 (please see notes in the code)
 
1. yes it would be indexing the cursor but you didn't use the readwrite option and the way I found it works is that you can only make one tag index if the cursor is read only. I get an error when I try to do more than one unless I specify "readwrite".
2. Yes, it would just close the table, not the cursor.
 
...

Best would be

Code:
SELECT ... INTO CURSOR curReservas READWRITE

SELECT curReservas

INDEX ON LOCALIZA TAG LOCALIZA           && Is this indexing the CURSOR curReservas? (1)
INDEX ON EMISSAO TAG EMISSAO             && Is this indexing the CURSOR curReservas?  (1)
INDEX ON NOMAGENTE TAG NOMAGENTE       && Is this indexing the CURSOR curReservas?  (1)
INDEX ON DATASAIDA TAG DATASAIDA     && Is this indexing the CURSOR curReservas?  (1)
INDEX ON DOCUMENTO TAG DOCUMENTO      && Is this indexing the CURSOR curReservas?  (1)

USE IN ("RESERVAS")            && Is this closing just the table RESERVAS? (2)

The field "Localizador" is a unique key for each record in the table.

I doubt this. The field seems to be of vartype C with values of different length. If SET EXACT = OFF the following comparison would be true

Code:
X = "12345"
Y = "12345678"
?y=x && TRUE

resulting in an absolute mess when seeking in the dbf - check INDEXSEEK() & al in the helpfile

hth

MarK
 
Last edited:
Mark: Thanks for advise me! Yes, it would be a great mess. So before SEEK I have to insert SET EXACT = ON. Is it correct?

Doug and Mark: About READWRITE, I will not be using it in this Grid, because I am using is just for displaying data. If I click on any of the 5 indexed headers on the Grid, it shows data indexed by the chosen column.
 
So before SEEK I have to insert SET EXACT = ON. Is it correct?

That's an option - better : you SET those values in your main starting program.

But please check the scope of the settings - some of SETtings are global whereas others are scoped to the DATASESSION

MarK
 
Last edited:
SitesMasstec,
I think you mean
SET EXACT ON

SET EXACT = ON

Will generate an error.
You should save the current state first with:
llExact = SET("EXACT")
And if you are changing it's state, you should capture the current state first, SET EXACT ON (do your code) then issue: SET EXACT (llExact)

This way you are maintaining your established state throughout the application that may have been set (or expected) earlier on.
 

Part and Inventory Search

Sponsor

Back
Top