TextArea Focus & Insertion Point?

I am constructing a desktop support app for an electronic instrument that I manufacture. In addition to a GUI to the instrument, I have an old-style ASCII terminal. The terminal has two modes. One is a dual window (TextArea) in which text to be sent to the instrument is entered in one area, while responses from the instrument appear in the other area. A single window mode has both outgoing and incoming text in the same textarea.

In both cases, I am having problems maintaining focus on the area that is to be typed into. The operator will do something else (click a button to change something, for example), then it is necessary to click in the outgoing window to give it focus, again. Often, the user (me, in this case) will forget this fact, and start typing but nothing happening. How can I insure that whenever the terminal window is front, the outgoing textarea has focus?

Insertion point is another issue. I cannot allow the insertion point to be within existing text since the instrument cannot handle edits of previously received text. Is there a way to keep the insertion point at the end of typed-in text?

For completeness, this terminal window has a few buttons (connect/disconnect, clear screen, and such), a help button to display help text, and a config button that opens a modal dialog in which things like the font size for the textareas can be set.

Many thanks
Jim Wagner, Oregon Research Electronics

Hi Jim,

In your outgoing text area add event handler FocusReceived with the following code

me.SelectionStart = me.Text.Length

and event handler SelectionChanged with the following code

If me.SelectionStart < me.Text.Length Then
  me.SelectionStart = me.Text.Length
End If

To return focus add

TextArea1.SetFocus

where TextArea1 is your control name to the ends of your button pressed event handlers.

HTH
Wayne

Will try those. Thank you!

Jim

Hello, Wayne -

Things are not quite working. The terminal opens in Single Window mode. The output field visibility is set to false and the enabled property is set to false.

Then I click a button to open a config dialog, and set it to Dual Screen. Closing that dialog then makes the output field enabled, visible, and gives it focus. The output field has no text since it was previously not visible or enabled. In the field’s ReceivedFocus event, I set the SelectionStart property to Text.Length but the insertion point remains in the TextArea (what was visible when the window opened), remains flashing, and there is none, at all, in the output field. If I turn on the TextArea ReadOnly attribute, the flashing insertion point goes away but there is still nothing in the output field. So, the issue seems to be getting the output field to receive typed text. Perhaps there are problems with calling order for the various parameters? Clicking the output field to try to transfer focus results in some sort of endless loop (in debug mode) with FocusReceived event. BUT, if I remove the breakpoint in that event handler, focus and insertion point DO get shifted to the output field with a click in that field. So, it is still a matter of the automatic insertion point change when it becomes a Dual Window system.

Thanks for your help.
Jim

Hey James, I am trying to follow along but I am a bit slow, ha! Have you thought about using a listbox for the chat instead? That might help you manage the “chat” better than the text area. It should also help with the focus. This way the user always types at the end of the chat and you don’t have to worry about setting the cursor at the end of the text. Even for the dual window you could have two listboxes. You could add a column for timestamps and such.

I could be way off base here, I apologize if I understood something wrong.

Hello, Ezekiel -

ListBox is an interesting idea, BUT I don’t think that will solve the focus problem. In the dual screen version, the output screen looses focus and the user has to click it to bring it back into focus. That is undesirable behavior and I don’t think that would change with ListBox. Pretty clearly, I am doing something wrong in my code because it works in some conditions, but not others. The challenge, now, seems to be finding it as there seem to be times when the output screen does not even accept focus when I try to set it. I think I am going to have to do a major rewrite of that window, and be more careful about what is done when.

Thanks for your suggestion!
Jim

loses

So why not subclass the controls so that when the action of the control is done, it sends focus back to the desired control?

This would probably be easiest done with some sort of messaging mechanism where the window itself is the subscriber and all of the controls that need to send focus back would be the publishers. For example, if the thing were a button, the last thing you’d do after the Pushed event would be to send a message that told the window to reset the focus.

I can make an example if that would help

I like the publisher/subscriber idea. It would solve a number of sticky points in my application. But not sure how that would solve the focus problem. It is certain to be a coding problem because one mode works properly but another does not. And, clicking the TextField gives it focus while a software SetFocus command does not (no ReceiveFocus event in the problematic mode). I think I need to rewrite that and pay more attention to the Focus control procedure from the very start.

Is the publisher/subscriber thing built into Xojo or does it have to be implemented in code?

Thanks
Jim

It has to be implemented in code.

It consists of:

  1. An interface containing a single method with two parameters. Name as String and data as variant. Let’s call it Subscriber.
  2. A module
    1. Method: Subscribe(obj as Subscriber) which adds the subscriber to an array.
    2. Method: Send(name as string, data as variant) which loops through the array, calling the method on each
    3. Method: Remove(obj as Subscriber) which removes obj from the array

Now usually I also do a little more decoupling by doing a few things:

  1. Make the subscriber array hold WeakRefs and then deal with all the casting necessary there, but it means you won’t leak subscribers
  2. Make a second array to hold messages() as Pair, to which I add messages and then use a timer to periodically (10-100ms) send any messages that have been queued, removing them as you go since new ones could be added while you loop.

It’s important not to get yourself into a messaging loop though, it’s easy to lock up your app if a subscriber is sending messages and processing them.

The timer version might solve that simply by breaking away from the initial events.

Thanks for that process outline. I will give it a try.

Jim