B4J Library jNotifications - Simple tray notifications (Class)

Discussion in 'B4J Libraries & Classes' started by jmon, Feb 17, 2014.

  1. jmon

    jmon Well-Known Member Licensed User

    Hello,

    This is a class I wrote that creates a simple pop-up notification at the bottom of the screen. It's animated and can be fully customized.

    At the moment, only one position is supported, which is at the bottom right of the screen.

    Features:
    • Set custom text and background colors
    • Set a custom title and message
    • animation, toast style (non linear animation, slowing down)
    • Set custom Icon
    • 2 events can be retrieved, 1) when the user clicks the [X] button, 2) when the user clicks the notification
    • Can set the offset from the border of the screen manually
    Capture2.JPG Capture.JPG

     

    Attached Files:

    Last edited: Jan 15, 2016
  2. jmon

    jmon Well-Known Member Licensed User

    I've updated the class:
    Added new methods:
    • MessageColor
    • TitleColor
     
    Rockefeller Goldman likes this.
  3. Erel

    Erel Administrator Staff Member Licensed User

    Very nice:
    [​IMG]

    It is a bit jumpy when running in Debug mode but works smooth in Release (Debug mode will soon be much faster...).
     
  4. jmon

    jmon Well-Known Member Licensed User

    Thanks. Yes, I noticed too that the debug mode is slower.

    A question not directly related to this notification library, but do you know why the "setSelectedColor" function I wrote doesn't work?
    [Edit] It actually works, but doesn't reflects the shown color in the Main GUI.
     
    Last edited: Feb 17, 2014
    jimmyF and Rockefeller Goldman like this.
  5. Erel

    Erel Administrator Staff Member Licensed User

  6. jmon

    jmon Well-Known Member Licensed User

    I modified the library a bit, with script breaking changes:
    • Renamed the method: "Text" ( and setText) to "Message"
     
  7. jmon

    jmon Well-Known Member Licensed User

    This is a reply to a post in another thread (jSystemTray - Add icons to the system tray (notifications)):
    Yes, with jNotifications, you can have the notification appear above other windows if you comment the line SetOwner (but it won't stay on top always):
    Code:
    frm.Initialize("frm", -1, -1)
    frm.RootPane.LoadLayout(
    "jNotifications")
    'frm.SetOwner(Owner)
    frm.Resizable = False
    frm.SetFormStyle(
    "UNDECORATED")
    This way, everytime you call the Notif.Show method, the window will appear on top of others, because the window is closed everytime it disappears and recreated everytime.

    You will be able to display notifications above other desktop windows even if your main window is in background. Now the issue, is that the jNotification cannot have the "Top most" attribute and will go back to background when another window is focused.

    When you don't set the owner of a window, don't forget to "kill" the notification window in your main module when you close the application by doing so:
    Code:
    Sub MainForm_CloseRequest (EventData As Event)
        Notif.Form.Close
    End Sub
    (Note that this is the reason why I allowed access to the Form method)

    I am currently writing a chat program, and so I needed the notifications to be on top of other windows, even if the chat program was in background. To set the top most attribute, I have to call an external AutoIt script to set the attribute. Currently the jAutoItX doesn't work with all the winxxx functions, but WinSetOnTop(WindowName, WindowText) is what you need.
     
    Theera likes this.
  8. Pascual Pérez

    Pascual Pérez Member Licensed User

    Thank you for the explanation, it adds possibilities.
     
  9. Gaver Powers

    Gaver Powers Member Licensed User

    JMon,

    Thanks for the notification class...

    I downloaded the zip this morning and tried to run on a WinXP system - got the following error in the log when run in debug mode.
    Code:
    Program started.
    An error occurred:
    (Line: 
    192Public Sub setImage(Img As Image)
    java.lang.IndexOutOfBoundsException: index 
    6
    Any suggestions on what I'm doing wrong, or how to fix?

    Thanks again
    G

    UPDATE: It worked in Release mode.

    Also.. was wondering if you could tell me how to set the message color without calling the getSelectedColor() function?

    I tried:
    Code:
    Notif.MessageColor = "oxff0000ff"
    and I'm getting a types do not match error.
     
    Last edited: Feb 25, 2014
  10. jmon

    jmon Well-Known Member Licensed User

    Hi, thanks for your comments. Regarding the color problem, I dont have B4J with me at the moment. I will reply to this question tomorrow when I have B4J. In the meantime, could you try with either:
    Code:
    Notif.MessageColor = fx.colors.rgb(00255)
    'or
    Notif.MessageColor = "#0000FF"
    (I forgot how I implemented it).

    [EDIT]
    Ok, now I see your error. Just remove the quotation marks:
    Code:
    Notif.MessageColor = 0xFF0000FF
    And I think that both example I wrote above work too.

    [EDIT]
    Note that it's not ox (OH-X), it's 0x (zero-X)
     
    Last edited: Feb 25, 2014
  11. jmon

    jmon Well-Known Member Licensed User

    Ok, so I tried with B4J today, and this is the answer to set the color of the message or the title:
    Code:
    Notif.MessageColor = fx.Colors.RGB(00255)
     
    Gaver Powers likes this.
  12. jmon

    jmon Well-Known Member Licensed User

    For those having the same issue, here is the way I do it (Until the next update of javaFx which should add the possibility to put the window on top):
    • First, comment the line
      Code:
      'frm.SetOwner(Owner)
    • Add a title to the Form in the jNotification:
      Code:
      frm.Title = "My Notification."
    • I wrote an AutoIt Script that sets the window on top using the command line (Note that the next code is AutoIt and not B4J!) (I don't post the AutoIt file, you will have to do it yourself, because autoit files are often flagged as malware by antivirus programs, I don't want anyone blaming me for that :):
    • Code:
      #NoTrayIcon
      If $CmdLine[0] < 2 Then Exit 0
      Switch $CmdLine[1]
          
      Case "setWindowOnTop"
              
      If $CmdLine[0] < 3 Then Exit 0
              
      If WinWait($CmdLine[2], ""5000) = 0 Then Exit 0
              
      If WinSetOnTop($CmdLine[2], "", $CmdLine[3]) = 1 Then
                  
      Exit 1
              
      Else
                  
      Exit 0
              EndIf
      EndSwitch
      Exit 0
    • Compile the script, then name it setWindowOnTop.exe and put it in your ../Objects folder.
    • Then in the jNotification Class in B4J, paste this function (note that you will need to load the jShell library):
      Code:
      Private Sub setWindowOnTopAsync(sTitle As String)
          
      Dim sArgs(3As String
          sArgs(
      0) = "setWindowOnTop"
          sArgs(
      1) = sTitle
          sArgs(
      2) = "1"
          
      Dim jShell As Shell
          jShell.Initialize(
      "jShell_setWinOnTop"File.Combine(File.DirApp, "setWindowOnTop.exe"), sArgs)
          jShell.Run(
      5000)
      End Sub
    • Note: If you want to remove the ontop attribute on the window, just change the args(2) to = "0"
    • Then add this code to the Sub Show of the jNotification library:
      Code:
      CallSubDelayed2(Me, "setWindowOnTopAsync", frm.Title)
    With this method, every time the jNotification is called, a new window is created and set on top each time. I know that this trick isn't full B4J or Java, but that the only way I found.
     
  13. Pascual Pérez

    Pascual Pérez Member Licensed User

    Thank you jmon, i'm using another similar alternative, the tool nircmd, calling nircmd.exe win settopmost "my notification".
    I hope next JavaFX will bring this possibility, for portability sake.
     
    jmon likes this.
  14. jmon

    jmon Well-Known Member Licensed User

    That's it, I just found that the new version of JavaFX 8u20 has the possibility to set the window on top:
    http://java.dzone.com/articles/javafx-8u20-days-future-past . I've tested it and it works very well.
     
    Pascual Pérez, Sytek and Erel like this.
  15. JTmartins

    JTmartins Active Member Licensed User

    Hello,

    How do we set the Notif.BackColor without using the getSelectedColor() ?

    I've tryed the Notif.BackColor = fx.Colors.RGB(0, 0, 255), but it does not work (works ok for title & message).

    I've noticed is a Paint object, but although I've tryed to play with it, no success was achieved.

    Thanks

    PS- Also an easy method to show notification always on top would be super.
     
  16. JTmartins

    JTmartins Active Member Licensed User

    Notif.Back Color solved as

    Code:
    Notif.BackColor=getSelectedColor (fx.Colors.RGB(61,121,204))
    and changed Sub getSelectedColor as

    Code:
    Public Sub getSelectedColor(color As JavaObjectAs Paint
        
    Dim jo As JavaObject
        jo=color
        
    Return jo
    End Sub
    The AlwaysOnTop autoIT method seems to work Fine, but only in release mode. As during debug mode it does not come on top. I can live with that. :)
     
    Last edited: Nov 17, 2014
  17. JTmartins

    JTmartins Active Member Licensed User

    Question

    How do we make the notify window actually disapear ? Beacuse It pops up, stays there for the amount of time defined then goes down, but as I'm using aero in windows 7, I still see it under the taskbar transparency.

    I can catch and close it by pressing the X with

    Code:
    Sub Notif_Closed
        Notif.Form .Close
    End Sub
    but I would like to close it, after the animation has finished going down as there is no warranty the the user will press the X button.

    Many thanks
     
    Last edited: Nov 18, 2014
  18. jmon

    jmon Well-Known Member Licensed User

    Good

    If you use Javafx 8u20 +, you can use "setWindowOnTop", here : http://www.basic4ppc.com/android/fo...indow-top-most-solved-jfx8.37319/#post-289599

    You should modify the "Animation_Tick" sub:
    Code:
    Private Sub Animation_Tick
        
    If ANIM_TYPE = ANIM_SHOWING AND Not(TOAST_AT_FINAL_POS) Then
            
    Dim Target As Float = MainScreen.MaxY - yOffset - frm.Height
            
    If frm.WindowTop > Target Then
                
    Dim Distance As Float = (frm.WindowTop - Target)
                frm.WindowTop = frm.WindowTop - ((Distance / 
    100) * ANIM_SPEED)
            
    Else
                TOAST_AT_FINAL_POS = 
    True
                TOAST_IS_VISIBLE = 
    True
                TimerAnim.Enabled = 
    False
                
    Log("Toast is Visible")
            
    End If
        
    Else If ANIM_TYPE = ANIM_HIDING AND Not(TOAST_AT_FINAL_POS) Then
            
    Dim Target As Float = MainScreen.MaxY + 100
            
    If frm.WindowTop < Target Then
                
    Dim Distance As Float = (Target - frm.WindowTop)
                frm.WindowTop = frm.WindowTop + ((Distance / 
    100) * ANIM_SPEED * 2)
            
    Else
                TOAST_AT_FINAL_POS = 
    True
                TOAST_IS_VISIBLE = 
    False
                TimerAnim.Enabled = 
    False
                TimerDuration.Enabled = 
    False
                
    Log("Toast is hidden")
                
    If TOAST_HIDE_THEN_SHOW Then
                    TOAST_HIDE_THEN_SHOW = 
    False
                    Show
                
    End If   
            
    End If       
        
    End If
    End Sub
    Actually, just modifying this line is enough:
    Code:
    Dim Target As Float = MainScreen.MaxY + 100
    It will move the window 100px lower. If it's not enough, increase the number.

    I hope that helps.
    Jmon.
     
  19. jmon

    jmon Well-Known Member Licensed User

    This is an update of my autoit script that I posted above. That deals with the Window Aero problem mentioned above, where Windows adds window borders automatically:

    Note that the following code is AUTOIT language, not B4J!
    Code:
    #NoTrayIcon
    #include <WinAPI.au3>

    If $CmdLine[0] < 2 Then Exit 0

    Switch $CmdLine[1]
        
    Case "setWindowOnTop"
            
    If $CmdLine[0] < 3 Then Exit 0
            
    If WinWait($CmdLine[2], ""5000) = 0 Then Exit 0
            
    If setPopUpAttributes($CmdLine[2], "") = True Then
                
    Exit 1
            
    Else
                
    Exit 0
            EndIf
    EndSwitch

    Exit 0

    Func setPopUpAttributes($Title, $Text)
        Local $sizeWindow, $sizeClient, $borderWidth, $titleHeight, $rgn
        ;Set on top:
        WinSetOnTop($Title, $Text, 
    1)
        ;Crop 
    to client area:
        $sizeWindow = WinGetPos($Title, $Text)
        
    If @error Then Return False
        $sizeClient = WinGetClientSize($Title, $Text)
        
    If @error Then Return False
        $borderWidth = ($sizeWindow[
    2] - $sizeClient[0]) / 2
        $titleHeight = ($sizeWindow[
    3] - $sizeClient[1]) - $borderWidth
        $rgn = _WinAPI_CreateRectRgn($borderWidth, $titleHeight , $sizeClient[
    0] + $borderWidth, $sizeClient[1] + $titleHeight)
        
    If $rgn = 0 Then Return False
        _WinAPI_SetWindowRgn(WinGetHandle($Title), $rgn, 
    True)
        
    Return True
    EndFunc
    This function will "Crop" the window to the client area, and cropping out the borders.

    Now you won't need to call this anymore:
    Code:
    frm.SetFormStyle("UNDECORATED")
     
  20. JTmartins

    JTmartins Active Member Licensed User

    Many thanks Jmon.

    Will try as soon as I can.
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice