B4J Question Save and recall rectangle color

bdunkleysmith

Active Member
Licensed User
Longtime User
In an application associated with a previous question I want the user to be able to save the configuration of some their settings, such as the colour of areas of the UI and then be able to recall that configuration.

I have saved the fill color of the particular rectangles to a file using the following code:
B4X:
 Dim tw As TextWriter
tw.Initialize(File.OpenOutput(File.dirapp, "config.ini", False))
Dim clr As String     
Dim joRect As JavaObject = RinScoreRect
clr = joRect.RunMethod("getFill",Null)     
tw.WriteLine(clr)

config.ini contains:

0x000000ff
0x000000ff
0x0c0099ff
0x666666ff
0x666666ff
Rin
0x086600ff
Vis
0x086600ff
0x000000ff

Note that Rin and Vis are not color values, but text values for labels that I can handle OK.

But I can't find the correct method to set the rectangle fill color after reading the values from the file. The basis of the code I've tried is:
B4X:
  Dim tr As TextReader
  tr.Initialize(File.OpenInput(File.dirapp, "config.ini"))
  Dim line As String
  Dim row As Int = 0
  line = tr.readline
  Do While line <> Null
    Select row
        Case 0
              Dim joRect As JavaObject = RinScoreRect           
            joRect.RunMethod("setFill", Array(fx.Colors.From32Bit(line)))

But it throws the following error:

Error occurred on line: 257 (main).
java.lang.NumberFormatException: For input string: "0x000000ff"
at sun.misc.FloatingDecimal.parseHexString(FloatingDecimal.java:2071)
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1870)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at b4j.example.main._btnloadconfig_action(main.java:390)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:563)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:221)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:156)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:93)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:82)
at anywheresoftware.b4a.BA$2.run(BA.java:165)
at com.sun.javafx.application.PlatformImpl.lambda$null$170(PlatformImpl.java:295)
at com.sun.javafx.application.PlatformImpl$$Lambda$48/21665305.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$171(PlatformImpl.java:294)
at com.sun.javafx.application.PlatformImpl$$Lambda$47/17230114.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$36/2180324.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)

What should Array(fx.Colors.From32Bit(line)) be instead so it correctly consumes the color specified as a string in the form 0x000000ff?

Thanks in anticipation of some suggestions.

Bryon
 

Roycefer

Well-Known Member
Licensed User
Longtime User
Try this:
B4X:
Dim bc as ByteConverter    'You need the ByteConverter library
Dim bytes() as Byte = bc.HexToBytes(line.Replace("0x", ""))   'make sure to remove the leading "0x"
Dim col as Int = bytesArrayToInt(bytes)      'creates a 2's complement 32-bit integer from an array of 4 2's complement 8-bit integers (expressed as type Byte)
joRect.RunMethod("setFill", Array(fx.Colors.From32Bit(col)))

Sub byteArrayToInt(bytes() As Byte) As Int
    Dim res As Int = 0
    For j = 0 To 3
        res = res*256 + ((bytes(j)+256) mod 256)
    Next
    Return res   
End Sub
 
Upvote 0

rwblinn

Well-Known Member
Licensed User
Longtime User
Hi,

have tested using this solution. It seems the colors are stored as RGBA.

B4X:
'Set the color for a rectangle from hex string 0xRRGGBBAA
'Example:
'Dim hex As String = "0xffff00ff" 'which is fx.Colors.yellow
'SetRectangleColor(rechtangleMain, hex)
Sub SetRectangleColor(rect As Node, hex As String)
   Dim joRect As JavaObject = rect
   Dim colorPaint As Paint = GetColorFromRGBA(hex)
   joRect.RunMethod("setFill", Array(colorPaint))
End Sub

B4X:
'Get a RGBA Hex String as Color.
'Parameter: Hex String 8 chars length RRGGBBAA; 0x and # are removed.
'Returns Color as Paint
Sub GetColorFromRGBA(hex As String) As Paint
  Dim a, r,g,b As Int
  hex = hex.Replace("0x", "").Replace("#", "")
  a = Bit.ParseInt(hex.SubString2(6,8), 16)
  r = Bit.ParseInt(hex.SubString2(0,2), 16)
  g = Bit.ParseInt(hex.SubString2(2,4), 16)
  b = Bit.ParseInt(hex.SubString2(4,6), 16)
  Return fx.Colors.ARGB(a, r, g, b)
End Sub
 
Last edited:
Upvote 0

bdunkleysmith

Active Member
Licensed User
Longtime User
Thanks Roycefer. I found your solution almost worked, but there were color shifts and in the process of investigating that, realized the color was stored in RGBA format as Rob has said.

The method I used with success was:

B4X:
Dim tr As TextReader
     Dim bc As ByteConverter
     tr.Initialize(File.OpenInput(p, n))
     Dim line As String
     Dim row As Int = 0
     line = tr.readline
     Do While line <> Null
        If js.left(line,2) = "0x" Then
            Dim bytes() As Byte = bc.HexToBytes(js.Mid(line,3,8))
            byteArrayToARGB(bytes)
        End If
        Select row
            Case 0
                Dim joRect As JavaObject = RinScoreRect 
                joRect.RunMethod("setFill", Array(fx.Colors.ARGB(a, r, g, b)))

B4X:
Sub byteArrayToARGB(bytes() As Byte)
    r = Bit.And(0xff, bytes(0))
    g = Bit.And(0xff, bytes(1))
    b = Bit.And(0xff, bytes(2))
    a = Bit.And(0xff, bytes(3))
End Sub

but Rob I think yours is more elegant and I'll amend my code accordingly.

For those interested, this application consumes data from a basketball scoreboard feed and displays the data on a laptop live video streaming the game such that the scoreboard data is superimposed on the game video, which can be seen here:
Thanks again,

Bryon
 
Last edited:
Upvote 0
Top