B4J Library Windows Notifications Library

Good evening all,

I created for my needs a library that shows windows notifications and it does not break the code in other platforms (tested in windows 10 & 11, Raspbian Linux and Ubuntu/Debian Linux with X11 - not tested with Mac --> please test and report any problems). It is based on this code by @Daestrum


In order to test it create a new UI project and add a combobox in the Designer. Then replace all the code in Main with the following:

B4X:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private ComboBox1 As ComboBox
    Private ntf As Notifications
    Dim img As Image
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Title = "Trial"
    MainForm.Show
    ntf.Initialize
 
    ComboBox1.Items.AddAll(Array As String("ERROR", "INFO", "NONE", "WARNING"))
End Sub

Sub Button1_Click
    img.Initialize(File.DirAssets,"recipe-rice-icon-16.png")
    'You may pass null
    img = Null
    Dim sMessage As String = "This is a long message of text and I am writting a lot of funny staff and continuing doing this. This is a long message of text and I am writting a"
    Log(sMessage.Length)
    Select Case ComboBox1.SelectedIndex
        Case 0
            ntf.ShowNotification(img, sMessage, "Trial App Message", ntf.IconError)
        Case 1
            ntf.ShowNotification(img, sMessage, "Trial App Message", ntf.IconInfo)
        Case 2
            ntf.ShowNotification(img, sMessage, "Trial App Message", ntf.IconNone)
        Case 3
            ntf.ShowNotification(img, sMessage, "Trial App Message", ntf.IconWarning)
    End Select
 
End Sub
 

Attachments

  • NHNotifications.zip
    6 KB · Views: 449
Last edited:

aminoacid

Well-Known Member
Licensed User
Longtime User
Very nice. Thanks!

I'm trying to replace "ntf.Iconxxxxx" with my own icon. Is that possible? Specifying a filename/path does not appear to work.
 

hatzisn

Expert
Licensed User
Longtime User
Very nice. Thanks!

I'm trying to replace "ntf.Iconxxxxx" with my own icon. Is that possible? Specifying a filename/path does not appear to work

Here is the code of Notifications class:

B4X:
Private Sub Class_Globals
    Private img2 As Image
    Private su As StringUtils
    Private xui As XUI
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    Dim sString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADO0lEQVR42m2Te2hTVxzHv7fJfefepElrk7Qr1ra6bhPrXFWcc2OWDRV8oKB/+EI22earjm6OgqCIYlWYk1KhG/4x/aMIMpyKio+K+ELF96i2a9fRNekjpnncm9x7c2M8OWOjqAd+nNfvfM73HH5fBm9okz5Z4p30wey5wbLSqvw8NBD689nd65eedZyIvprLjJ2UT6tXlmzZuWdWbdUX/kJRYB0FdN2ysxgcTRs3Hvb+crJlZ9Pft88nXwNUzVkWXLF1x8WpE8fVuCQOAufAeJUnOzn0xi0Ylg1Nt/Cga7jzeMvu+u6O9tD/gMLyd5xLm9pu1E1+q05RBMgEEFA41I2TKPz2UAqhhAk9ZSKZMHD3yT93ftu3YVa075FNATPWNn9dP//zVp9PgUv9F6CILD4udeUF4MpAEsl0BppmQksaiEYSuHyh45tbRxoPU8DCHb8/qJ4QmKJ4ZMiKCEnmwPNOTPAIVEHPaBqmYUPXiYpkGlpMR3dP+OGpXYtrGW/FNPfsVdtHS0q8jOx2QXQJEGUeRS4OX80opYDDtwYQITenCSClGdBjGoaHo7mb7c2FjK9yZnXdsm+73B4VoipDkAXwIoegR8T3n1VTQPP5boRGUzDIH5g6ASV1xGMJ3DvZMpHxlL8fqF3UEJIVFwSXBFbgSXAo80rYs7yWApra76P/uY6MYdEwNJ08RcOjM61B+gfT17SGlUK3n5ckcATgYJ0o80k4+OWHFNDw83X0R3RkMzastAEzlUIyFh+88+vGAAVU1zf+6K+saWA5HrwkwsmxKC+W0bLpUwrYcOgy+kc0ZCyLHE6T3sRQb9fB7ov7t1KAk1fH18z77r5aVOJxOFmqosLvRtu2+RSwvvkM/grHYRkmsnYGichQrPPcgam2mej7rxJ5ufjtdZUfrT4kq24nUACedeCnxgV0c8v+0zBJOeeLQo/H7J5rRzfrI0+PkAVzrBe8UlHN+sB7837wlATdTpbFi9wLWkhMQQHsjIX4UDgefnJ2byrS2Ubyo6+ZKa/EwauTpeJ3V8q+ijmcqPqpmdLxQf1539XUyB/Hsmbicf7mN7pxjEkZxsGxJPJuQi5rmSQyZJR7NfMlSNFJupvXYToAAAAASUVORK5CYII="
    Dim b() As Byte = su.DecodeBase64(sString)
    Dim inps As InputStream
    inps.InitializeFromBytesArray(b,0,b.Length)
    img2.Initialize2(inps)
End Sub

Public Sub getIconError() As String
    Return "ERROR"
End Sub

Public Sub getIconNone() As String
    Return "NONE"
End Sub

Public Sub getIconInfo() As String
    Return "INFO"
End Sub

Public Sub getIconWarning() As String
    Return "WARNING"
End Sub

Public Sub ShowNotification(Image16x16YouMayPassNull As Image, Message As String, Title As String, Icon As String)
    Select Case GetSystemProperty("os.name", "").ToLowerCase.Contains("windows")
        Case True
            If Image16x16YouMayPassNull.IsInitialized = False Then
                asJO(Me).RunMethod("displayTray",Array(img2, Title, Message, Icon))
            Else
                asJO(Me).RunMethod("displayTray",Array(Image16x16YouMayPassNull, Title, Message, Icon))
            End If
        
            Sleep(7600)
            asJO(Me).RunMethod("removeTrayIcon", Null)
        Case False
            wait for (xui.Msgbox2Async(Message, Title, "Ok", "", "", img2)) Msgbox_Result(iRet As Int)
    End Select
End Sub



Private Sub asJO (o As JavaObject) As JavaObject
    Return o
End Sub

#if java
import java.awt.*;
import java.awt.event.*;
import java.awt.TrayIcon.MessageType;
import java.net.MalformedURLException;
import javafx.embed.swing.SwingFXUtils;


SystemTray tray = SystemTray.getSystemTray();
TrayIcon trayIcon;

public void displayTray(javafx.scene.image.Image img,String title,String msg, String icon) throws AWTException, MalformedURLException {

    trayIcon = new TrayIcon(SwingFXUtils.fromFXImage(img, null));
    tray.add(trayIcon);
    //MessageType.(ERROR, INFO, NONE, WARNING)
    switch (icon)
    {
        case "WARNING":
            trayIcon.displayMessage(title,msg,MessageType.WARNING);
            break;
        case "INFO":
            trayIcon.displayMessage(title,msg,MessageType.INFO);
            break;
        case "NONE":
            trayIcon.displayMessage(title,msg,MessageType.NONE);
            break;
        case "ERROR":
            trayIcon.displayMessage(title,msg,MessageType.ERROR);
            break;
    }
 
}

public void removeTrayIcon(){
    tray.remove(trayIcon);
}
#End If


And here is a page which displays a way to create notifications with image:



Today I cannot do it since it is Good Saturday for Orthodox Christians but you may want to modify my code (derived from @Daestrum 's code) and post your own version of Notifications.

Either way you pass an image but it displays it in small size on the top. The answer might be to use IconNone with your own image.
 
Last edited:

aminoacid

Well-Known Member
Licensed User
Longtime User
Here is the code of Notifications class:

B4X:
Private Sub Class_Globals
    Private img2 As Image
    Private su As StringUtils
    Private xui As XUI
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
    Dim sString As String = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAADO0lEQVR42m2Te2hTVxzHv7fJfefepElrk7Qr1ra6bhPrXFWcc2OWDRV8oKB/+EI22earjm6OgqCIYlWYk1KhG/4x/aMIMpyKio+K+ELF96i2a9fRNekjpnncm9x7c2M8OWOjqAd+nNfvfM73HH5fBm9okz5Z4p30wey5wbLSqvw8NBD689nd65eedZyIvprLjJ2UT6tXlmzZuWdWbdUX/kJRYB0FdN2ysxgcTRs3Hvb+crJlZ9Pft88nXwNUzVkWXLF1x8WpE8fVuCQOAufAeJUnOzn0xi0Ylg1Nt/Cga7jzeMvu+u6O9tD/gMLyd5xLm9pu1E1+q05RBMgEEFA41I2TKPz2UAqhhAk9ZSKZMHD3yT93ftu3YVa075FNATPWNn9dP//zVp9PgUv9F6CILD4udeUF4MpAEsl0BppmQksaiEYSuHyh45tbRxoPU8DCHb8/qJ4QmKJ4ZMiKCEnmwPNOTPAIVEHPaBqmYUPXiYpkGlpMR3dP+OGpXYtrGW/FNPfsVdtHS0q8jOx2QXQJEGUeRS4OX80opYDDtwYQITenCSClGdBjGoaHo7mb7c2FjK9yZnXdsm+73B4VoipDkAXwIoegR8T3n1VTQPP5boRGUzDIH5g6ASV1xGMJ3DvZMpHxlL8fqF3UEJIVFwSXBFbgSXAo80rYs7yWApra76P/uY6MYdEwNJ08RcOjM61B+gfT17SGlUK3n5ckcATgYJ0o80k4+OWHFNDw83X0R3RkMzastAEzlUIyFh+88+vGAAVU1zf+6K+saWA5HrwkwsmxKC+W0bLpUwrYcOgy+kc0ZCyLHE6T3sRQb9fB7ov7t1KAk1fH18z77r5aVOJxOFmqosLvRtu2+RSwvvkM/grHYRkmsnYGichQrPPcgam2mej7rxJ5ufjtdZUfrT4kq24nUACedeCnxgV0c8v+0zBJOeeLQo/H7J5rRzfrI0+PkAVzrBe8UlHN+sB7837wlATdTpbFi9wLWkhMQQHsjIX4UDgefnJ2byrS2Ubyo6+ZKa/EwauTpeJ3V8q+ijmcqPqpmdLxQf1539XUyB/Hsmbicf7mN7pxjEkZxsGxJPJuQi5rmSQyZJR7NfMlSNFJupvXYToAAAAASUVORK5CYII="
    Dim b() As Byte = su.DecodeBase64(sString)
    Dim inps As InputStream
    inps.InitializeFromBytesArray(b,0,b.Length)
    img2.Initialize2(inps)
End Sub

Public Sub getIconError() As String
    Return "ERROR"
End Sub

Public Sub getIconNone() As String
    Return "NONE"
End Sub

Public Sub getIconInfo() As String
    Return "INFO"
End Sub

Public Sub getIconWarning() As String
    Return "WARNING"
End Sub

Public Sub ShowNotification(Image16x16YouMayPassNull As Image, Message As String, Title As String, Icon As String)
    Select Case GetSystemProperty("os.name", "").ToLowerCase.Contains("windows")
        Case True
            If Image16x16YouMayPassNull.IsInitialized = False Then
                asJO(Me).RunMethod("displayTray",Array(img2, Title, Message, Icon))
            Else
                asJO(Me).RunMethod("displayTray",Array(Image16x16YouMayPassNull, Title, Message, Icon))
            End If
       
            Sleep(7600)
            asJO(Me).RunMethod("removeTrayIcon", Null)
        Case False
            wait for (xui.Msgbox2Async(Message, Title, "Ok", "", "", img2)) Msgbox_Result(iRet As Int)
    End Select
End Sub



Private Sub asJO (o As JavaObject) As JavaObject
    Return o
End Sub

#if java
import java.awt.*;
import java.awt.event.*;
import java.awt.TrayIcon.MessageType;
import java.net.MalformedURLException;
import javafx.embed.swing.SwingFXUtils;


SystemTray tray = SystemTray.getSystemTray();
TrayIcon trayIcon;

public void displayTray(javafx.scene.image.Image img,String title,String msg, String icon) throws AWTException, MalformedURLException {

    trayIcon = new TrayIcon(SwingFXUtils.fromFXImage(img, null));
    tray.add(trayIcon);
    //MessageType.(ERROR, INFO, NONE, WARNING)
    switch (icon)
    {
        case "WARNING":
            trayIcon.displayMessage(title,msg,MessageType.WARNING);
            break;
        case "INFO":
            trayIcon.displayMessage(title,msg,MessageType.INFO);
            break;
        case "NONE":
            trayIcon.displayMessage(title,msg,MessageType.NONE);
            break;
        case "ERROR":
            trayIcon.displayMessage(title,msg,MessageType.ERROR);
            break;
    }
 
}

public void removeTrayIcon(){
    tray.remove(trayIcon);
}
#End If


And here is a page which displays a way to create notifications with image:



Today I cannot do it since it is Good Saturday for Orthodox Christians but you may want to modify my code (derived from @Daestrum 's code) and post your own version of Notifications.

Either way you pass an image but it displays it in small size on the top. The answer might be to use IconNone with your own image.

Thank you! I will give it a try. Happy Pascha 🙏
 

aminoacid

Well-Known Member
Licensed User
Longtime User
Just a quick update:

I don't think there is an easy way to do this. When you use "MessageType.NONE" the OS is supposed to use the image assigned to TrayIcon for the notification icon. But I think this only applies to OSs prior to Windows 10, because it does not work in Windows 10 (and I assume 11 also). Had this worked, it would have been the solution. I think in Win10/11, "MessageType.NONE" tells it to display no notification icon (as is apparent) and not default to the TrayIcon.

The TrayIcon should be scaled to 16x16, so thinking that the OS rejects it because of the small size, I tried 32x32, all the way up to 1024x1024 sized icons and did not have any success. Also tried using "trayIcon.setImageAutoSize(true);" to autoscale the Icon but again, that only works for the tray Icon; the notification icon still does not appear.

Not a big deal. I just wanted to see if this was possible. I can live with what we have... Thanks!
 

hatzisn

Expert
Licensed User
Longtime User
Just a quick update:

I don't think there is an easy way to do this. When you use "MessageType.NONE" the OS is supposed to use the image assigned to TrayIcon for the notification icon. But I think this only applies to OSs prior to Windows 10, because it does not work in Windows 10 (and I assume 11 also). Had this worked, it would have been the solution. I think in Win10/11, "MessageType.NONE" tells it to display no notification icon (as is apparent) and not default to the TrayIcon.

The TrayIcon should be scaled to 16x16, so thinking that the OS rejects it because of the small size, I tried 32x32, all the way up to 1024x1024 sized icons and did not have any success. Also tried using "trayIcon.setImageAutoSize(true);" to autoscale the Icon but again, that only works for the tray Icon; the notification icon still does not appear.

Not a big deal. I just wanted to see if this was possible. I can live with what we have... Thanks!

Yes, I noticed it. This behaviour has changed and I do not know who is the one to blame. Is it microsoft and the new Windows 11 or Java 19? It used to work.
 
Top