Page 1 of 2

Am I using EditorGadget() correctly to display a character?

Posted: Sat Jul 11, 2020 2:21 am
by Jimbob81
Hello PureBasic users. I'm requesting help with EditorGadget()

I've created a small terminal program to receive characters from the serial port. While the program works as required, I do have a quirk with the display of text that I can't seem to fix.
I've created a GUI window with EditorGadget() and call a procedure in my main loop to update its contents if a byte has been received via a serial routine.
From what I understand, EditorGadget() really only works with a line of text (a string) rather than an individual character. Is this correct?

Code: Select all


; if uart_byte contains a character then read EditorGadget() contents, append uart_byte to the contents and display it in EditorGadget() again.
Procedure updateUART()
  If uart_byte <> 0
    SetGadgetText(#uartOutput, GetGadgetText(#uartOutput) + Chr(uart_byte))
  EndIf
EndProcedure 
So as you may see from the above code snippet, I've done what feels like a hack to read the existing text inside the text box then add the new character and print it all out in the text box again.

Is there a better way to add individual characters/bytes to a GUI text window?
Should I be using a different Gadget?

One of the downsides to the above code is once the text box is full and beyond the scroll area, the cursor always remains at the top of the text ie. the first character. If I scroll down to the last character to read the text and a new character arrives then the cursor and text shoot back to the start again... quite annoying.
Does anyone have a fix for this?

The other downside is while I built my app on a Linux platform and it visually looks to update the text box smoothly, the same cannot be said for the code on the Windows platform (XP, Win7 and Win8). The text box (EditorGadget) flashes the text quite horribly as it adds a new character. Almost as though its clearing the text box window between a read of the text box content and writing of the new content.
Anyone have a fix for this?

I'd like to keep the app cross platform and avoid OS specific API's if possible.
I'm coding with Purebasic 5.62 (x64) on Debian Linux 9 with LXDE desktop

Any suggestions would be much appreciated. Thanks.

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 9:18 am
by infratec
Try this:

Code: Select all

EnableExplicit

Procedure Update(Gadget.i, Byte.a)
  
  Protected Text$, Count.i, Line$
  
  
  If Byte <> #CR And (Byte < '0' Or Byte > 'z')
    Byte = '.'
  EndIf
  
  Text$ = GetGadgetText(Gadget)
  Count = CountString(Text$, #CR$)
  
  Line$ = GetGadgetItemText(Gadget, Count)
  Line$ + Chr(Byte)
  SetGadgetItemText(Gadget, Count, Line$)
  
EndProcedure


Define Event.i, Byte.a

If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  LoadFont(0, "Consolas", 11)
  
  
  EditorGadget(0, 8, 8, 306, 133)
  SetGadgetFont(0, FontID(0))
  SetActiveGadget(0)
  
  AddWindowTimer(0, 1, 250)
  
  Repeat
    Event = WaitWindowEvent()
    Select Event
      Case #PB_Event_Timer
        Select EventTimer()
          Case 1
            Byte = Random(127)
            Update(0, Byte)
        EndSelect
    EndSelect
  Until Event = #PB_Event_CloseWindow
EndIf
May be it works.

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 12:43 pm
by davebar
It's unclear why you feel it is necessary to read the contents of the editor gadget. You can simply add a string containing one or more characters to the existing content, but you must increment the gadget item index count on each SetGadgetItemText. Here is my crude adaptation of infratec's example:

*** CORRECTED CODE ***

Code: Select all

EnableExplicit

Define Event.i, uart_byte.a, Count.i

If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
  LoadFont(0, "Consolas", 11)
  EditorGadget(0, 8, 8, 306, 133, #PB_Editor_WordWrap)
  ; The #PB_Editor_WordWrap is important for your editor gadget
  SetGadgetFont(0, FontID(0))
  SetActiveGadget(0)
  AddWindowTimer(0, 1, 100)
 
  Repeat
    Event = WaitWindowEvent()
    Select Event
    	; Here a simple timer is used to trigger the event.
    	; Your case might be a com port event	
      Case #PB_Event_Timer
        Select EventTimer()
        	Case 1
        	uart_byte = Random(127,33) ; This just fakes your uart byte value
          	SetGadgetItemText(0, Count, Chr(uart_byte)))
          	Count + 1 ; Move the gadget item index count forward
        EndSelect
    EndSelect
  Until Event = #PB_Event_CloseWindow
EndIf
Hopefully this will help.
Dave

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 1:38 pm
by infratec
@davebar

You didn't read the help of the EditorGadget() :wink:
You set the line number and not the character.

But your code works on 'accident'.

In your example you can simply use:

Code: Select all

SetGadgetItemText(0, 2147483647, Chr(uart_byte))
It will always append to the last character.
Count is not needed, But if it is used, it represents the line number.

I tried -1, but that results in location 0.

You found a working trick (on windows), but it does not work like you thought :mrgreen:

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 7:09 pm
by davebar
You didn't read the help of the EditorGadget()
Yes I have, MANY times.
The EditorGadget help says:
SetGadgetItemText(): Set the specified line text.
but the SetGadgetItemText() help says:
Item | The item to use. The first item in the gadget has index 0.
It's strange that BY (not ON) accident I have used this in several industrial control programs and never once has it failed to produce the required result.
Over the years I have read pretty much every bit of PB documentation available. I would be grateful if you could point me to the documentation that explains what the value 2147483647 represents and why it should be used in this situation.
Care to share your "working Windows trick"?
Regards
Dave

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 9:56 pm
by infratec
The german help says:
SetGadgetItemText(): (Über)Schreibt die angegebene Textzeile.
Which means: (over)write the given textline.

And not character.

Since -1 was not working, I choose the maximum positive value for an integer (which is the type of the parameter)

May be the german help is wrong.

But a small test:

Code: Select all

EnableExplicit


Define Event.i

If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
  LoadFont(0, "Consolas", 11)
 
 
  EditorGadget(0, 8, 8, 306, 133)
  SetGadgetFont(0, FontID(0))
  SetActiveGadget(0)
  
  SetGadgetText(0, "+++++++++++++++++++++")
  
  SetGadgetItemText(0, 5, "-")
 
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
Shows a s output :
-+++++++++++++++++++++
And not
+++++-++++++++++++++++
So I think the german help is right.

Short test:

Code: Select all

EnableExplicit


Define Event.i, Line$

If OpenWindow(0, 0, 0, 322, 150, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
 
  LoadFont(0, "Consolas", 11)
 
 
  EditorGadget(0, 8, 8, 306, 133)
  SetGadgetFont(0, FontID(0))
  SetActiveGadget(0)
  
  For Event = 0 To 9
    Line$ + "+++" + #CRLF$
  Next Event
  SetGadgetText(0, Line$)
  
  SetGadgetItemText(0, 5, "---")
 
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
Result (as expected)
+++
+++
+++
+++
+++
---
+++
+++
+++
+++
So may be the english help is not correct.
But line means line and not character.

And thanks for the grammatical correction of on and by.
But I think if you write in german I'm gonna have to correct more things :wink:

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 10:36 pm
by RASHAD
Hi
$8000 : Line limit for the EditorGadget()
2147483647 = $7FFFFFFF
That is the text limit for the EditorGadget()

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 11:32 pm
by Jimbob81
@infratec
Thanks for your reply. Your code works on Linux and Windows

@davebar
Thanks also for your reply. Interestingly your example works fine on Windows but NOT Linux...? Linux displays one character and the cursor is left flashing after that character. Debugging the code I can see both the count and uart_byte values changing but SetGadgetItemText(0, Count, Chr(uart_byte)) is not writing to the EditorGadget() object - very weird!
Infratec's line of code SetGadgetItemText(0, 2147483647, Chr(uart_byte)) somehow works on Windows to but not Linux... I don't understand why 2147483647 has any importance but increment its value by 1 sets the index to 0 .

**edit** Just dawned on me, its the 32bit boundary.
Playing around with the code I can change the index value to anything below the 32bit boundary and the EditorGadget will behave as expected (on Windows) until the line number matches the index value, then it will persistently stay on that line. Example: try setting SetGadgetItemText() index to 1, 5 and 7 (with WordWrap ON) then without WordWrap

I have to read back the EditorGadget() contents and append to it to see any update/change with Linux... Guess this is also why Infratec's code works on both platforms too.

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 11:45 pm
by Olli
Little remark :
infratec wrote:

Code: Select all

Text$ = GetGadgetText(Gadget)
Count = CountString(Text$, #CR$)
It seems that this code can be simplifyed with :

Code: Select all

Count = CountGadgetItems(Gadget)
Excepted InsertGadgetItem() which misses, we can do lots of things with EditorGadget().

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sat Jul 11, 2020 11:55 pm
by Jimbob81
@RASHAD
Didn't see your reply till after my last post but yep 2147483647 being the line limit makes sense now.

@infratec and @davebar
I think their might be a discrepancy between the English and German help as I too was confused.

English help:
SetGadgetItemText(): Set the specified line text. ==> Yup this makes sense but...
SetGadgetItemText(#Gadget, Item, Text$ [, Column]) Item: The item to use. The first item in the gadget has index 0. ==> This suggests indexing a location on a string of text...

AddGadgetItem(): Add a text line. ==> Yup this makes sense too... but...
AddGadgetItem(#Gadget, Position, Text$ [, ImageID [, Flags]]) Position: The item index where the new item should be inserted. To add the item at the start, use an index of 0. To add this item to the end of the current item list, use a value of -1. Remember that when you add an item that all current items which come after the new one will have their positions increased by 1. ==> This also suggests indexing a location on a string of text... both say nothing about index referring to a WHOLE LINE of text. Infratec's examples above prove this is the case.

I think the help description can be interpreted differently and could do with a grammar change. The use of "Item" and "Position" keywords refer to the same thing but are yet used interchangeably - should be one keyword for both ie. "Line_Position" which spells out what and where pretty easily.

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sun Jul 12, 2020 1:21 am
by Jimbob81
So it looks like there's a few ways to add a character at a time to EditorGadget()
Some behave different to others on different OS platforms... I've only been successful if I read the contents back, add a character and send the new data to EditorGadget() again with Linux - Windows just seems to except the new character and moves on....

So I've taken a different approach to EditorGadget() to understand why sending a character needs what I feel are hacks to make it work.
I'm trying what I believe is a logical approach that a beginner/newbie would expect adding characters to EditorGadget() to work. I've chosen statements that by their name alone should suggest what they do and be correct....

Tasks...
1) Setup a window with an EditorGadget()
2) Add a common word to the EditorGadget() made up of its characters (because I want to test how characters are received in EditorGadget() ).
3) View the result then live happily ever after.... but no....

Code: Select all

EnableExplicit

Define Event.i, String$

If OpenWindow(0, 0, 0, 320, 170, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  EditorGadget(0, 8, 8, 300, 150)
 
  AddGadgetItem(0, -1, "H")   ;Add a character 
  AddGadgetItem(0, -1, "e")   ;at a time
  AddGadgetItem(0, -1, "l")   ;to the EditorGadget()
  AddGadgetItem(0, -1, "l")   ;widget using "Position" -1
  AddGadgetItem(0, -1, "o")   ;which should add to end of list......?
  
  String$ = GetGadgetText(0)  ;Read back what is written to the EditorGadget()
  ShowMemoryViewer(@string$, 50)  ;Display 50 characters because there's more to String$ than expected!!!
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf
The above code I chose AddGadgetItem() because I want to add (as the name suggests - remember logical and newbie) plus the EditorGadget() example uses that statement and SetGadget(xxx)Text() help statements suggest changing the text content (I want to add not change - remember logical and newbie)

With tasks 1 and 2 completed, I moved on to task 3 - view the result.... Wait, where did the carriage return and line feeds come from? I didn't ask for those and why didn't the -1 "Position" work? Notice that Linux gives LF where Windows gives CF+LF (but that's an OS thing) also there's a NULL string termination character after every LF yet if you read back EditorGadget() with GetGadgetText() everything is put into one string not multiple string for each line as the NULL termination character might suggest.

So with all my ramblings above I'm left wondering why a CF+LF or LF is added for me. Why not simplify AddGadgetItem() to add a character as its name suggests (note its Add Gadget Item not Add Gadget Items (the s is important)) and if a CF or LF is needed then a simple Chr(13) or Chr(10) could be used in place of the character.

Am I way off the plot here?

**edit**
Can I modify the EditorGadget() to work how I want? Is it a builtin module/library in PureBasic or part of the PureBasic source code on GitHub for the IDE/debugger/form designer?

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sun Jul 12, 2020 4:56 am
by idle
does this help, use a static variable to hold the string so you can append the text

Code: Select all

EnableExplicit

Define Event.i, String$

Procedure UpdateLine(gadget.i,char.s,line=1,clear=0) 
  Static str.s 
  If clear 
    str=""
  EndIf   
  str+char
  SetGadgetItemText(gadget,line,Str) 
EndProcedure   

If OpenWindow(0, 0, 0, 320, 170, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  EditorGadget(0, 8, 8, 300, 150)
  AddGadgetItem(0,0,"Output")  
  AddGadgetItem(0,1,"")   ; add a blank line to editor to display chars as they come 
  UpdateLine(0,"H")
  UpdateLine(0,"e")
  UpdateLine(0,"l")
  UpdateLine(0,"l")
  UpdateLine(0,"o")
  
  String$ = GetGadgetItemText(0,1)  ;Read back what is written to the EditorGadget()
  ShowMemoryViewer(@string$, StringByteLength(String$))  ;Display 50 characters because there's more to String$ than expected!!!
  CallDebugger 
  
  UpdateLine(0,"Again",1,1)
  
  String$ = GetGadgetItemText(0,1)  ;Read back what is written to the EditorGadget()
  ShowMemoryViewer(@string$, StringByteLength(String$)) 
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sun Jul 12, 2020 6:38 am
by Jimbob81
idle wrote:does this help, use a static variable to hold the string so you can append the text
Yes and no. Yes in the fact that I could dump a whole line of text into the EditorGadget() but the no side is the source of input to the variable isn't consistent and there is no consistent delimiter (carriage return/line feed) in which to close the variable and send to the gadget. Serial input is the source. A person, computer program or microcontroller sending data...

On a side note with your example, it never displays lines 18 to 23 (Hello) on my Linux EditorGadget() output yet I can trace through, watch the str variable and see the "Hello" word being created. It does eliminate the extra CR+LF's though. :)

So my output of the EditorGadget() is:
Output
Again

Thanks for your post.

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sun Jul 12, 2020 6:02 pm
by idle
you didn't see it update as it was queuing the events, so you only saw the result

Code: Select all

EnableExplicit

Define Event.i, String$, len.i, ct.i, pos.i 

String$ = "Hello again " + #LF$
len = Len(String$)+1

Procedure UpdateLine(gadget.i,char.s,line=1,clear=0) 
  Static str.s 
  If clear 
    str=""
  EndIf   
  str+char
  SetGadgetItemText(gadget,line,Str) 
EndProcedure   

If OpenWindow(0, 0, 0, 320, 170, "EditorGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  EditorGadget(0, 8, 8, 300, 150)
  AddGadgetItem(0,0,"Output")  
  AddGadgetItem(0,1,"")   ; add a blank line to editor to display chars as they come 

  Repeat
    Event = WaitWindowEvent(250)
    If event = 0 
      pos = ct%len+1
      If pos < len 
        UpdateLine(0,Mid(string$,pos,1),CountGadgetItems(0)-1) 
      Else 
        UpdateLine(0,Mid(string$,pos,1),CountGadgetItems(0)-1,1) 
      EndIf   
      ct+1
    EndIf   
  Until Event = #PB_Event_CloseWindow
EndIf

Re: Am I using EditorGadget() correctly to display a charact

Posted: Sun Jul 12, 2020 9:08 pm
by kenmo
As someone who has also written a UART serial monitor in PureBasic... I highly recommend you use the ScintillaGadget instead of the EditorGadget!

It gives you total control over appending and inserting text, adjusting the cursor or not, scrolling the view, text styling, etc. Also fully cross-platform.

With a few tweaks to the font, hiding the margin, etc., you can make it look almost exactly like the EditorGadget, if you want.