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!

Is it possible to modify a form generated by a Wizard? 3

Status
Not open for further replies.

plepkowski

Programmer
Jul 22, 2005
17
US
I'm trying to use VFP 6 to bring an old Clipper .dbf into a real window application. I generated a form with the Wizard which has command buttons for navigation, find, print, add, edit, and exit.

1. Can I get rid of the Print button?

2. Can I make certain fields read only?

3. Can I insert (dtos(date())+time()) into a field upon adding or editing a record.

Paul Lepkowski
 
You cold do all of these and much more:

1. If the wizard added navigation buttons for you and add a class for this, you can't edlete PRINT button, but you could make it Unvisible (Visible = .f.) and put some of the other buttons over it and resize the class container

2. Yes. Mark the TextBox and in Properties, under DATA tab set ReadOnly = .t. (or under "Other" tab set Enabled = .f.)


3. Yes, but w/o knowing your code I can't give you proper advise. There where you start editing just put:
Code:
REPLACE MyField WITH TTOC(DATETIME(),1)

TTOC(DATETIME(),1)-> Result format is: yyyymmddhhmmss


Borislav Borissov
VFP9 SP1, SQL Server 2000/2005.
MVP VFP
 
Thanks Borislav.

1. The Wizard stuck in a Print button. Only the container for all the buttons can be selected. I can't select just that button.

2. OK, got it.

3. TTOC(DATETIME(),1) is a little simpler than the Clipper method of REPLACE ODATE WITH DTOC(DATE()) and then REPLACE OTIME WITH TIME(). So I'll merge the old ODATE, OTIME, EDATE, ETIME fields into ORIGINAL and CHANGED.

The problem is how do I get the form to replace the field at the end of an add or edit operation?

In other words if I hit the Add button where do I put the code REPLACE ORIGINAL WITH TTOC(DATETIME(),1) so that the field is written at the end of the add operation?

If I hit the Edit button where do I put REPLACE CHANGED WITH TTOC(DATETIME(),1) to record the time of the Edit operation?
 
Hi Mike,

That article tells me how to add buttons with combo or list boxes. It also says no coding is needed to add a new text box.

What I want to do is remove a button from the existing text box with ten buttons.

Any ideas?

Paul
 
Paul,
I see you are new in VFP :)
All buttons are added in container. When you press and hold Ctrl key and click on that container ALL controls placed in it are available for modifying.
I stop using the wizards after my first attempt to create something with them, so I don't know wher to put that code, but is there button SAVE someewhere? If so try to put it there. If the Click Event of that button doesn't have code in it try to find and learn the code in original Click event of that button. There must be a line like TableUpdate(.......). If you could find that code you could Copy and Paste it in your wizard generated button Click Event. Just before TableUpdate(.......) put your REPLACE .... command.

Borislav Borissov
VFP9 SP1, SQL Server 2000/2005.
MVP VFP
 
Paul,

Sorry if I misunderstood your question.

Like Borislav, I haven't used the wizards for a long time, and so am not completely familiar with them.

However, in general, if you have controls within some sort of container class, it is not possible to remove those controls when the container is on a form (as is the case here).

You can, however, hide any of the controls (that is, make it invisible). So, for example, to get rid of the Print button, select the button in the drop-down list at the top of the properties window. Then scroll down the properties list until you reach the Visible property. Set this to .F.

You won't see any difference in the form designer, but when you run the form, the button will have disappeared.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

My Visual FoxPro site: www.ml-consult.co.uk
 
Borislav and Mike,

OK, I get it. You don't use the wizards. So, I'll try this with the form builder.

When I wrote this for clipper 17 years ago I had to incorporate two fields to show the original date and time of the record and two fields to show the date and time of the most recent edit.

So, I copied the field vars to memvars, edited the memvars with GET READ, then compared the edited memvars to the fields. If none had actually changed I did not REPLACE. If they had changed I REPLACED the changed ones and updated the date time fields of the most recent edit.

How can I do this with a form? That is, can I edit memvars and selectively replace them if they've changed?

Will I need three forms, one to display, one to edit, and one to add new records or can it be done in one?

Paul
 
You CAN work with memvars, but you SHOULDN'T.

When you think about it, copying data to memvars was a form of creating an edit buffer. With VFP, buffering is built in!

Take a look in the help file. You might be surprised how much work you DON'T have to do that you had to do yourself in the past.
 
Dan,

I've been browsing that help file for several days. It is not explicit about when buffering takes place.

Does it happen in every form?

Can I compare the buffered values to the original field values before actually replacing the field values?

Paul
 
Paul,

If you are still using the wizard, you don't have to do anything special about buffering. The wizard-generated form does it all for you.

If you have switched to the form builder, you will need to set the form's BufferMode property. The setting depends on whether you want optimistic or pessimistic locking. If you are unsure of the difference ... well, I won't try to explain it here. I'd suggest you use pessimistic for the time being. You can always alter it later.

Yes, you can compare the buffered values with the original values. When you look at a field in the table, you will see the buffered value. To get the original value, use the OLDVAL() function.

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

My Visual FoxPro site: www.ml-consult.co.uk
 
Just a comment.

As mentioned above, forms built by the Wizard incorporate a number of Classes which work 'behind the scenes' to support accomplishing tasks.

Most of the time these classes are very beneficial to getting your work done. But it/when you want to modify the form, you may find the classes getting in the way of making your desired modifications work.

Admittedly, I am prejudiced. Like both Borislav and Mike, I have not used Wizards to build my forms for a very long time. By building forms 'by hand' you get to choose what goes into it -- controls, classes, data environment, etc. And you are also aware of what might need to change/go-away if a modification is required.

My recommendation is to not waste too much time trying to figure out how to modify a Wizard built form.
Instead spend the time learning to build your form 'by-hand'. Not only will you get the form the way you want it to be, but you will also understand many VFP things much better and it will be of immense help in your next project.

Just my two cents worth.

Good Luck,
JRB-Bldr
 
Mike,

>Yes, you can compare the buffered values with the original values. When you look at a field in the table, you will see the buffered value. To get the original value, use the OLDVAL() function.

Did you mean that when you look at the form you are looking at the buffer? If so, how do you compare that value with the field value before you let the form replace the field? How do you prevent the replacement if no change has been made?

Since this is a single user application with no network involved why is a lock needed?

Paul
 
>Since this is a single user application with no network involved why is a lock needed?

Since the advent of Windows, there is no such thing as a single-user system. You can run two instances very easily and be two users on the same system all on one machine.

My clients do it regularly. <g> (And yes, I know how to disable it, be we have reasons not to.)

>Did you mean that when you look at the form you are looking at the buffer? If so, how do you compare that value with the field value before you let the form replace the field? How do you prevent the replacement if no change has been made?

At any point when buffering is turned on, your controls that are bound to fields ONLY edit the buffer. They never edit the field value directly.

Therefore, any time before the buffer is committed you can compare table.field with Oldval("table.field") to find out if there is a difference. If you don't want to keep the change, just call Tablerevert(). The buffer is discarded.

If there's no change, why worry about it?
 
Tamar,

doesn't the Form Builder use the wizard classes, too?

Yes, it does. But, more to the point, it doesn't enable buffering.

Paul,

Did you mean that when you look at the form you are looking at the buffer?

Yes.

Suppose you have a form with a control called txtName, and this is "bound to" the Name field in the Customer table (that is, its ControlSource is "customer.name"). The form is buffered.

Anytime you reference Customer.Name anywhere in the form, you will be seeing the contents of the buffer. If you executed "? Customer.Name", you would display the value in the buffer, and if you did "REPLACE Customer.Name WITH 'Paul'", the replace would operate on the buffered value.

When you issue TABLEUPDATE(), the buffered value will get written to the physical file. If you decide you don't want to do that after all, you call TABLEREVERT(), in which case the buffered value will be lost, and the buffered fields will revert to their original values.

Since this is a single user application with no network involved why is a lock needed?

If that is truly the case (bearing in mind Dan's caveat), then you should still use buffering, but the choice between optimistic and pessimistic is no longer so important (I guess optimistic might be very slightly faster).

I would add that I totally agree with JRB-Bld's advice. The wizards and the form builder have their place, but the ideal way to create a form is to do it "by hand".

Mike


__________________________________
Mike Lewis (Edinburgh, Scotland)

My Visual FoxPro site: www.ml-consult.co.uk
 
OK, I think I've got it! Thanks Mike and Dan. If I'd been doing this job under CICS with DB2 handling the data it would have taken about 20 minutes.

I've been playing with the form designer. When I try to use a text box to provide my menu commands I get a weird box with a blue title on the top. I like the look of the command buttons that the wizard produced. I do I get something like them?

How do you call the form in edit and add mode so fields can be entered?

How do you make the form revert to display only when the menu is waiting for a choice?

In Add mode where do I stick the code to time stamp a record after typing in all the fields?

In Edit mode where do I stick the code to compare the buffers to the fields, decide whether to call TABLEUPDATE() or TABLEREVERT(), whether or not to time stamp the update field, then call either update or revert?

Paul
 
That's a lot of questions. Let me tackle some.

<< When I try to use a text box to provide my menu commands I get a weird box with a blue title on the top. >>

I don't understanding what you're doing, but the way to build a menu with VFP is using the Menu Designer. CREATE MENU at the Command Window or File | New | Menu.

<< I like the look of the command buttons that the wizard produced. I do I get something like them? >>

Which kind of buttons did you choose in the Wizard? Also, which style of form?

<<How do you call the form in edit and add mode so fields can be entered? How do you make the form revert to display only when the menu is waiting for a choice?
>>

First, think hard about whether you really want modes in your form. That is, consider how the user will use this form. If the most common thing the user will do is add new records, open the form ready for a new record. If the most common thing is editing existing data, open looking at data and ready for the user to find the right record. It's really rare to have a case where the most common action is for the user to look at data without changing it, so consider leaving out a "display only" mode unless accidental changes are really dangerous.

If you follow this advice, the form is always in edit mode and the only distinction is whether you're editing a new record or an existing record. Add a form property (Form | New Property) to let you keep track of that--call it, say, lAdding. Set it appropriately.

To open the form ready to add, issue APPEND BLANK in the Init event. To open ready to edit, don't.

In the Save code, check lAdding to figure out whether you follow TableUpdate() with another APPEND BLANK or not.

There's a little more work to do here, like setting up a button to switch from Add to Edit, but this should give you the idea.

<< In Add mode where do I stick the code to time stamp a record after typing in all the fields? >>

The best way to do this is to set up a default value for the timestamp field with a value of DATETIME(), so it happens automatically whenever you add a record. If, for some reason, that won't work for you (like you're not using a database container), in the Save code, check lAdding and do a REPLACE before issuing TableUpdate().

<<In Edit mode where do I stick the code to compare the buffers to the fields, decide whether to call TABLEUPDATE() or TABLEREVERT(), whether or not to time stamp the update field, then call either update or revert?>>

Presumably, there'll be a Save button. The button's Click should call a form-level method (Form | New Method), which I'd call Save. Put the code in this custom Save method.

Tamar
 
Just to add to what everybody else has given you, the forms that the wizard creates are not all that user friendly. Lets assume that you create that wizard based form over a table that has 1,000,000 records and your user wants to get to a record located somewhere near the middle. That user could spend a fair amount of time clicking the "Next" button. The old "VCR" style buttons were quite appropriate back in the days of tape drives. Go to the beginning of the tape, go to the end of the tape, go to the next record or the previous record.

We don't really need to limit ourselves to this kind of navigation. You can create your own form class using a "Candidate List" that will provide better navigation and you would be able to create a simple form in about 20 min.

A candidate list has a textbox into which the user enters some sort of search text; a dropdown combo that allows the user to select the type of search to perform; a command button that tells VFP to perform the search and a listbox or grid in which the search results are displayed. For example, the user enters "Murph" into the text box, selects "Surname" as the type of search and then clicks the "Find" button. The SearchType dropdown is based on a table that has a memo field containing an SQL command
<code>
SELECT nCustID, cSurname-([, ]+;
cFirstName)-([ ]+;
cMiddleName) ;
AS cCustName ;
FROM Customer ;
WHERE LIKE(ALLTRIM(UPPER(;
This.Parent.SearchText.Value))+[*],;
cSurname) ;
INTO CURSOR csrResults
</code>
In your SearchMethod, you simply
<code>
lcSQLCmd = SearchTypes.mSearchCmd
&lcSQLCmd
</code>
You then use the csrResults to populate your grid or listbox.

When the user clicks on a row in the grid or listbox, you can populate the remainder of the form with a simple
<code>
SEEK(csrResults.CustID,[Customer],[CustNameTag])
</code>

This is not only faster for the user, it is also faster for you. Once you create your base FileMaintForm class, you add the appropriate table(s) and then drag the fields onto the form. Better yet, when your user comes to you asking for a new way to look up customers, all you have to do is add a new record to your search table - no recompile, no rollout of a new EXE.

Oh yes, and you remember that million record table, the record that your user is looking for is my customer record - located in the middle of the table. He enters "Murphy" selects the "Surname" search and then scrolls through the 30 or 40 "Murphy" records that he has. Much faster!

Give it some thought - and then dump the wizard. You CAN do better yourself.
 
Sorry about that - forgot to use UPPER(cSurname) in the where condition - couldn't figure out how to edit the post once I found the error.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top