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!

keep focus on a form 2

Status
Not open for further replies.

Akourou

Programmer
Mar 28, 2019
34
0
0
GR
hello to all

I want to always keep focus on a form when I am editing fields on it.
Not to be able to click anywhere outside of the form unless I save my changes.

is that possible?

thank you
 
Just to add ....

You will need to set that property either (i) at design time or (ii) in the form's Init (before the form appears on the screen). You can't change the property once the form is visible.

In other words, the form will have to be modal the whole time that it is on the screen. You can't make it modal during editing and modeless when the user clicks the Save button. Normally you would expect to close a form once the user has finished editing it.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike surely is right,

I just want to add that it only addresses and only needs to address the second part of your requirements: "Not to be able to click anywhere outside of the form"

Many, including me, consider modal forms a mess. It hinders certain actions to run smoothly, like shutting down an application or Windows. And you might even think: Well, that's good. You can also put data integrity and security high without modal forms by using transactions when it comes to saving changes. And you can be slave to the needs of energy savings or even hardware protection in some cases, when it comes to emergency shutdowns and your app hinders them.

If you work with buffering and transactions, no dbf or cdx file can get corrupted by not focusing on an edit form.

And besides that constraint you also constrain the user to not use other forms to gain an information needed for the current edit. So in the end it may mean users cancel out to be able to exit the form and first gather information, which they will perhaps even note on a paper notepad to have them available when they finally are captured on a modal form.

Modal forms should be scarce and it's a little wink that messageboxes are modal, they are about really short but important interventions of a users workflow to ask importantye/no questions. They can be programmed to do so for unimportant questions, too, and seem nagging, but they really focus on a question with only a few options like yes/no, cancel/ok or sometimes een only confirmation with OK.

There are always exceptions to the rule and I may not question your need for a modal form, but you actually might want something softer. At least as long as there is nothing edited and nothing to be saved first, why should a user not go off elsewhere in other forms? There's no way to switch a form from modal to non-modal, though, this hasto be decided when the form starts, the WindowType is readonly when a form runs.

So what actually happens if a user clicks outside the current form?

This question hints at knowing the event model of forms. Well, the form then loses focus, so thiforrm.Lostfocus is triggered, followed by Thisform.Deactivate.

These events in that order should under some circumstances just be accepted and under other circumstances you could set focus to the last active control in form.deactivate, for example like this:
Code:
o = CREATEOBJECT('activeform')
o.KeepActive=.t. && for sake of demonstration
o.Show()

DEFINE CLASS Activeform as Form
   ADD OBJECT text1 as textbox WITH top=32,left=32
   ADD OBJECT text2 as textbox WITH top=64,left=32

   KeepActive = .f.
   LastActive = .null.
   
   PROCEDURE Paint()
      IF ISNULL(Thisform.LastActive) OR  Thisform.LastActive<> Thisform.ActiveControl
         Thisform.LastActive = Thisform.ActiveControl
      Endif
   Endproc
   
   PROCEDURE Deactivate()
      IF Thisform.KeepActive AND VARTYPE(Thisform.LastActive)='O'
         Thisform.LastActive.SetFocus()
      ENDIF 
   ENDPROC 
ENDDEFINE

Now the KeepActive flag can be set .t. only when there is an urge to keep the focus, otherwise it can be kept at .f. or set back to .f. after that need for modal behavior is gone.

With all that said, the need for modal states should be very rare. An edited record surely does not qualify, if you program data modifications by the standard of transactions.
And even in case you need all changes to directly go into a DBF unbuffered and without transactions, you have never a need for a modal state from the perspective of protecting the changes of data, the work of the user and time spent on it. There is use for both extremes and anything in between, but none of them should need guarding by forbidding to leave the current form.

Also see QueryUnload and usual ways of having an automatic save action to allow unloads when there is an application or even a Windows shutdown.

And take into account changing applcications instead of changing focus to another form of the same application, do not trigger anything, even if your form is modal, it's only application modal, not system modal. And it's good that way, it's in the sense of the parallelism of using multiple things at once - against the odds of people not being able to do multi tasking. They are, even men.

Chriss
 
I will agree with Chris that the modal mode is not very convenient.
I would need to switch to modeless mode once the save button is clicked.

I will describe a bit more my concern / problem.

This is the way I work with forms for editing dbf data and correct me if it seems wrong or old-fashioned etc.
My forms have variables, so i fill in the data in variables.
Once the save button is clicked, record fields are replaced with the data from the variables.
Same thing goes when i click next or previous record button, data from records are copied to the variables of the form.

Because there are relations between tables, sometimes when I scroll records in a table, current record position is changing in another table.
So I might skip to a record in a form and automatically there is a record skip in a different form that displays data of a different table that is related.

Now, what if I am in edit mode in that other form? all data that was edited is replaced by data from the record skip. and then if I press save button it is a mess...

So I want to be able to stay only in that form as long as I am editing.
 
Akourou, what you are doing is not the ideal approach, but it is not so terrible either. The idea of using variables as intermediaries when updating a table - that was quite common in pre-Visual Foxpro days, but now there are better ways.

Nowadays the preferred approach is to use buffering. You would set a buffer mode for the form, and give each of the controls a ContrlSource which links directly to the corresponding field in the underlying table. The user edits the data as usual, including validation etc.

Then, in the Save button, you issue a TABLEUPDATE(). The effect is to copy the data from the individua controls into the table. In other words, it commits the data. You also have a Cancel (or Revert) button. This issues a TABLEREVERT(), the effect of which is to cancel the user's edits and put things back to the way they were before.

I have oversimplified this explanation, but I hope it will give you the general idea. I suggest you read up on the above functions - and on buffering in general - in the VFP help file.

Now, all of the above is a different question than the choice between modal and modeless. In general, you should avoid modal forms as much as possible, but there are sometimes cases where they are appropriate. I don't know enough about your application to know what would be best in your case.

But to take the particular point you raised: if the user clicks through to another record while editing the current record. The way to deal with that is to disable the record navigation controls while the form is being edited. It would work like this:

Start by making all the editable controls read-only. Give the form an Edit button. When that button is clicked, change the read-only status to read-write. And then disable the record navigation controls. When the user clicks Save or Cancel, do the reverse of all that.

That is the way I have always handled this situation, and I suspect many other developers do the same.

I hope this al makes sense.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I agree with Mike, to use variables as temporary storage is the legacy way also known as SCATTER/GATHER method. That is now done with buffering. Take a look at the concept, there are several modes of buffering and locking data in combinations.

Even when you only had variables, you could have separate sets of variables for separate forms. In VFP you now also have SCATTER NAME, so you can have a record object, or several. So if you consider a transition but want a fast immediate solution re the problem of multiple forms moving record pointers, one ingredient in a recipe that solves that could be multiple record variables you maintain. Besides that, forms scoped to have a private data session will not interfere with other forms, which can have pros and cons.

One thing that would seem to solve that is form sets, but you better stay with separate forms, you can manage which ones should have private and which ones should share a data session and that way form a set working in the same session. It seems more work than to rely on formsets doing that, but you have more freedom to use forms in either situation.

So I'd recommend looking into buffering and private data sessions, the data environment class you can define separate from forms and combine them, and last not least correct scoping of data, properties, variables to prevent side effects just because of form activation.

If two forms use the same tables with the same relations between them for easy data navigation and display of the right detail records, then private datasessions help that this can work without forms influencing each other.

So here are your ingredients in short:
Buffers. Each workarea can buffer changes, no variables are necessary for that matter anymore
Datasessions. You don't have only 15 workareas, you also have more than one datasession, you can have the same set of tables with same relations open in muliple datasessions and record pointers become independent in forms with each their own private datasession, so things are less brittle and better enccapsulated.
SCATTER/GATHER improvements. Even if you stick to using variables for a while, the main improvement here is scattering to an object or objectvariable that will have fields as properties SCATTER NAME form1record generates form1record.field1,2,3,4etc and in form2 SCATTER NAME form2record separates these records in variables which would already solve the influence problem before starting with private data sessions and buffering.

Scattering and gathering to and from objects has another good use case to me: Passing a record with one parameter, no matter if forms share a datasession or not, becomes an easy way to have interform communication.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top