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

Entering fractions (quarters and halves) into a text box. 1

Status
Not open for further replies.

AndrewMozley

Programmer
Oct 15, 2005
621
GB
There is a data entry form with a grid. One of the columns contains a textbox (30 chars). Usually whatever the user enters is saved in a column of the Recordsource cursor. The user enters a description into this textbox which might include a number of hours.

For example : “Editing chapter 2. 3 1/2 hrs 12-Nov-2021”

Can this be converted at the time of data entry so that the fractional numbers of hours, entered as fractional quantities : 1/2, 1/4, 3/4 are converted into the the single characters : ½ , ¼, ¾? Have other users had the need to do this, and how have they achieved the result?

In the example above it would be good if the resultant textbox contained this value :

Code:
Mygrid.column2.text1.value = “Editing chapter 2. 3½ hrs  12-Nov-2021”

Thanks. Andrew Mozley
 
You have the characters of the Ansi codepage (whichever exactly you use), see for yourself what it has:

So you could use STRTRAN() to convert 1/4, 1/2, and 3/4.

Code:
text=STRTRAN(text,'1/4',chr(0xBC))
text=STRTRAN(text,'1/2',chr(0xBD))
text=STRTRAN(text,'3/4',chr(0xBE))

If this is about time capturing I'd rather program something that has a list of active tasks like "Editing chapter 2" and a button next to it that defaults to "START" and turns to "STOP" when started. Then you could capture datetimes and easily determine the differences, as you can subtrct two datetimes to get the seconds betweeen them. From there it's easy to get minutes (60 seconds), hours (60 minutes) or quarter hours (well, 15 minutes), isn't it?

So the time interval will just result from the clicks. For reporting time latr than realtime you could allow entering times.

Chriss
 
A couple of other options:

- Educate your users in the use of Alt+Number Pad. For example, they can key Alt+171 to get ½, or Alt+172 to get ¼. Less work for you, but probably not so popular with your users.

- Provide a small row of buttons next to the text box. Label each button with the relevant fracion (using CHR() in the Caption property). In the Click event, porgrammatically insert the character in question into the text box's Value at the SetStart location. This is a bit trickier to program but probably easier for your users.

- Or both of the above.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you Chriss. STRTRAN() is indeed the function which replaces a substring within a character string, and I would use that. The requirement isn’t particularly to do with capturing time. It is just that when a description is being entered into a textbox (as part of an invoice line), the user might enter fractions; these could be times as per my example, but they could be weights, distances &c.

And thank you Mike L. What I am really interested in doing is making this adjustment ‘on-the-fly’; so that as soon as the characters have been entered, they appear in the textbox to the user. Your suggestion of having buttons near the text box is interesting, although I imagine that I might have to be careful not to trigger any VALID() event that the textbox might have, and return to the textbox when the button has been processed. Also, the textbox is one cell in a grid which is being used for data entry, which may be a few rows down the screen.

What I thought might be useful, is to emulate the way that Microsoft Word works: This effect is triggered (e.g.) when you enter these five characters consecutively. Space, “1”, “/”, “4”, Space.

In this event Word replaces the string “1/4” with the single character ¼. If you don’t want that at the time you can immediately press the backspace key, and the string reverts to “1/4”. And it remains like that unless you re-enter that whole character sequence.

I suppose that to get this effect one would need to include code in the Keypress() event of the text box. I will try this out.

But if anyone has done something like this before it would be good to hear from them.

Thanks again. Andrew Mozley
 
Andrew,

You say you want to do this on the fly, as the characters are being typed. That makes sense. In that case, you are right that it is the Keypress event that you should be trapping. Or, better still, use the InteractiveChange, given that Keypress also fires when the user moves the insertion point, or does a copy or cut, and in other cases as well.

But be careful. It's not enough to do the substitution on the last three characters entered so far in the string. The user might finish typing the text, then edit an earlier part of the string, entering at that point "1" "/" "4" for example. So you would have to do the substitution as the point indicated by SelStart. And then you would also have to trap Backspace (or perhaps Ctrl+Z?) to override the substitution.

It would be a bit tricky, but a good solution from the user's point of view.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Andrew said:
I suppose that to get this effect one would need to include code in the Keypress() event of the text box. I will try this out.

Yes, but catch the case someone enters 1/24 then this would be translated to ½4.
So maybe extend the strtran to only replace "1/4 ", "1/2 " and "3/4 " with leading and trailing spaces.

Or how about introducing a "command interface" and require "1/4_" etc. So a user wanting this has to enter the 1/4 with underscore to trigger the string translation, otherwise 1/4 remains.
This could be handy in a case you have a mix of quotients for which a special character exists and others, for which not, then it's also bad style to have some in the usual and some in the special format.

The code could be extended to have other easy replacements for special chars, eg ^2_ could be replaced by superscript 2, chr(0xB2).

Chriss
 
Or, you could have the user highlight the characters in question, and then hit a designated key to perform the substitution. So, they type a chunk of text. They then highlight, say "1/4", and hit the relevant key. You would trap the key; look at the part of the string indicated by SelStart and SelLength, and perform the substitution on it.

A little bit more difficult from the user's point of view, perhaps, but it would avoid any problems of the textbox losing focus, and it would make it easier to implement an Undo (backspace of Ctrl-Z) feature.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Thank you for your replies. This is now the code for my grdmain.column1.text1.keypress().

Code:
LPARAMETERS nKeyCode, nShiftAltCtrl
LOCAL lStart, lFirst, lMiddle, lLast

* December 2021.  Cope with conversion of " 1/4 " to " ¼ " &c
* SelStart is the value of the cursor position _before_ the key was processed.
lStart = This.Selstart + 1

IF lStart >= 5
   lFirst  = SUBSTR(This.value, 1, lStart - 5)
   lMiddle = SUBSTR(This.value, lStart -4, 5)
   lLast  =  SUBSTR(This.value, lStart + 1)
   IF lMiddle = " 1/4 "
      This.Value = lFirst + " ¼ " + lLast
      ENDIF
   IF lMiddle = " 1/2 "
      This.Value = lFirst + " ½ " + lLast
      ENDIF
   IF lMiddle = " 3/4 "
      This.Value = lFirst + " ¾ " + lLast
      ENDIF
   ENDIF 
RETURN DODEFAULT()

There are probably refinements needed; as Mike suggests, I probably need to cater for backspace, but this is not a major problem.

This code doesn’t completely emulate Microsoft Word, where a backspace immediately after entering (say) “ 1/2 “ reverts to normal characters. But it is fairly close.

And I now realise that with the Arial font that I am using, these binary fractions come out pretty small, but there you go!

Andrew
 
Andrew said:
SelStart is the value of the cursor position _before_ the key was processed.
Yes, that's because Keypress can be used to suppress the effect of the latest keypress with NODEFAULT.

If you want the values after the last keypress, use the InteractiveChange event, instead.

And why so complicated, when you can just do
Code:
Local Newvalue
Newvalue=STRTRAN(This.Value,' 1/4 ',Chr(0xBC))
Newvalue=STRTRAN(Newvalue,' 1/2 ',Chr(0xBD))
Newvalue=STRTRAN(Newvalue,' 3/4 ',Chr(0xBE))
If not This.value==Newvalue
   This.value = Newvalue
Endif

It also catches the case somone pastes in text containing the strings.

Chriss
 
Thank you for your suggestion. The amended version :

Code:
Local Newvalue
Newvalue=STRTRAN(This.Value,' 1/4 ',Chr(0xBC))
Newvalue=STRTRAN(Newvalue,' 1/2 ',Chr(0xBD))
Newvalue=STRTRAN(Newvalue,' 3/4 ',Chr(0xBE))
If not This.value==Newvalue
   This.value = Newvalue
Endif
does indeed automatically convert the textbox to use single character fractions.

The original, more complicated, version gives the option of letting the user over-ride the default behaviour and reverting to the longer form of such a fractional expression - by typing the fraction again. He might want to do this if (for example) he had written a date expression, or maybe just prefers the long form.

But there may be better ways of writing this code!

Andrew
 
Andrew,

Maybe something like this:

Code:
Local Newvalue
THIS.SavedVal = This.Value
  &&SavedVal is a custom property of the textbox

Newvalue=STRTRAN(This.Value,' 1/4 ',Chr(0xBC))
Newvalue=STRTRAN(Newvalue,' 1/2 ',Chr(0xBD))
Newvalue=STRTRAN(Newvalue,' 3/4 ',Chr(0xBE))
This.value = Newvalue

Then, when you trap the Undo key (probably Ctrl-Z)

Code:
this.Value = this.SavedVal

I suggest Ctrl-Z for the Undo rather than Backspace because they may well want to use Backspace for its normal purpose.

Also, I repeat my suggestion of doing the first chunk of the above code in the InteractiveChange rather than the Keypress, because the Keypress will fire much more often, such as when they move the cursor. Also, the Keypress won't trap attempts to paste text into the control via a menu option.

However, the trapping of the Undo key should be done in the Keypress.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Sorry, the above is not quite what I intended. Better something like this:

Code:
Local Newvalue
Newvalue=STRTRAN(This.Value,' 1/4 ',Chr(0xBC))
Newvalue=STRTRAN(Newvalue,' 1/2 ',Chr(0xBD))
Newvalue=STRTRAN(Newvalue,' 3/4 ',Chr(0xBE))
If not This.value==Newvalue
  THIS.SavedVal = This.Value
  This.value = Newvalue
Endif

The rest of it would be as above.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Mike – I hope I have not misunderstood your replies! I take your point about the Interactivechange() method.

But I only want to deal with any substring affected by the latest keypress.

That is why my rather cumbersome code parses textbox.value into the string at the beginning, the 5-character string up to the character most recently entered, and the rest of textbox.value (which is often empty).

Suppose that the user had entered “Take 4 1/2 oz of flour;”, and I have corrected it to “Take 4 ½ oz of flour;”; but the user has then edited it to revert to the first version “Take 4 1/2 oz . . “.

If he subsequently keys in “ and add a cup of milk.”, I want textbox.value to be :

Code:
“Take 4 1/2  oz of flour; and add a cup of milk.”

So I want later key-presses only to affect the string which has just been entered. I only want to correct the user once!

Grateful for your guidance.
 
I understood your keypress was only acting on the latest input (what's simpler with interactivechange as itdoesn't need prediction). I also saw it as an absolute implementation, CTRL-Z won't undo the replacement as far as I see.

Latest input is not as easy even with InteractiveChange. As user can click anywhere into the text and change SelStart, the last characters can be spread throughout the text. But i any way, you can act local oriented by Selstart, as you do. What's simpler is that you don't need to assume start to be Selstart+1. It could even be Selstart-1 with a backspace.

I just tested the usual undo behavior in textboxes. CTRL+Z replaces the current value with the value that was in the textbox when you entered it, also for unbound textboxes. So covering the undo mode like Mike Lewis suggests, would be an improvement in general, I just don't see it working. CTRL+Z is handled outside of Keypress, at least when the Sysmenu covers CTRL+Z as hotkey and maps it to default Windows behavior.

Chriss
 
Chris / Andrew,

I was only using Ctrl+Z as an example of an Undo key. I chose it because it is the key combo that is used in Word to override an auto-correction. I hadn't realised that you can't trap it in a Keypress.

So forget about Ctrl+Z (or,rather, retain it in its native behaviour, as a menu / hotkey option to undo an entire edit). Choose a different combo for undoing the fraction substitution. But I also take the point that you only want to undo the latest keypress.

It clearly needs a bit more thought.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
It's not wrong to use CTRL+Z, and also CTRL+Y, in combination with a cursor storing multiple values of an undo/redo history. But the _med_edit menu or at leat the menu items of it for undo/redo have to be undefined for it to work.

VFP uses CTRL+R for redo, while most Windows applications use CTRL+Y for it.

If you SET SYSMENU TO you can trap CTRL+Z in keypress, it has nKeycode=26 and nShiftAltCtrl=2, CTRL+Y for redo has nKeycode=25, and the same nShiftAltCtrl=2.
Implementing this history isn't as trivial as you might think. For example, after you skip back with a few CTRL+Z, when you then write something new that has to override the history from that point forward, ie the redo history is deleted once you create a new timeline. A bit like time travel problems.

I think it's managable, as the edit won't go much further than entering 100 chars, perhaps 1000. That's nothing for a cursor. The records only need a memo field and an int for the Selstart textcursor position to un- and redo the textbox states including the move of the textcursor.

It's your choice to introduce other hotkeys, but CTRL+Z is a very commonly known hotkey, that even works in image editing software and walks through a history (journal) of image states.

Chriss
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top