# Toast Notifications

**URL:** <https://forum.inductiveautomation.com/t/toast-notifications/15522>\
**Category:** Ignition\
**Tags:** vision\
**Created:** [September 30, 2017, 2:49pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522 "2017-09-30T14:49:15Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![cmisztur2](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmisztur2/32/4243_2.png) [@cmisztur2](https://forum.inductiveautomation.com/u/cmisztur2)\
**Post date:** [September 30, 2017, 2:49pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/1 "2017-09-30T14:49:15Z")

</div>

Has anyone worked on creating toast notifications? The idea would be to place a transparent container on top of a window and display templates with a message that would float up and disappear over time. They could be interactive too.

```auto
from com.inductiveautomation.factorypmi.application.components.template import TemplateHolder
from com.inductiveautomation.factorypmi.application.script import PyComponentWrapper
root = system.gui.getParentWindow(event).rootContainer.getComponent('contToasts')
newobj = TemplateHolder()
newobj.initTemplate(root.getAppContext())
newobj.setTemplatePath("toast")
newobj.setName("dynToast")
newobj.getLoadedTemplate().startup()
newobj.getLoadedTemplate().setEnableLayout(1)
root.addComponent(newobj)
PyComponentWrapper(newobj).Message = "Hello from Toast"
#system.gui.moveComponent(newobj, 100,100)
#system.gui.resizeComponent(newobj, 400,400)

system.gui.transform(newobj, newX=0, newY=500, duration=2000)

```

---

<div class="post-metadata">

**Author:** ![zxcslo](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/zxcslo/32/61610_2.png) [@zxcslo](https://forum.inductiveautomation.com/u/zxcslo)\
**Post date:** [September 30, 2017, 3:58pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/2 "2017-09-30T15:58:09Z")

</div>

Can this be somehow ported/used in Ignition?  
[https://github.com/jithurjacob/Windows-10-Toast-Notifications](https://github.com/jithurjacob/Windows-10-Toast-Notifications)

---

<div class="post-metadata">

**Author:** ![cmisztur2](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmisztur2/32/4243_2.png) [@cmisztur2](https://forum.inductiveautomation.com/u/cmisztur2)\
**Post date:** [September 30, 2017, 6:26pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/3 "2017-09-30T18:26:36Z")

</div>

Looks like a bunch of Win32 API in it. I think I’m halfway there with the above code, just not knowing how to deal with the undocumented TemplateHolder I thought I would ask the experts so I don’t have to bang my head for several days.

---

<div class="post-metadata">

**Author:** ![cmisztur2](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmisztur2/32/4243_2.png) [@cmisztur2](https://forum.inductiveautomation.com/u/cmisztur2)\
**Post date:** [September 30, 2017, 8:59pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/4 "2017-09-30T20:59:02Z")

</div>

Ok I’m halfway there. How do I destroy a template holder?

[http://recordit.co/b8FWGAKQSX](http://recordit.co/b8FWGAKQSX)

```auto
from com.inductiveautomation.factorypmi.application.components.template import TemplateHolder
from com.inductiveautomation.factorypmi.application.script import PyComponentWrapper

root = system.gui.getParentWindow(event).rootContainer.getComponent('toasts')
epoch = system.date.toMillis(system.date.now())
holder = TemplateHolder()
holder.initTemplate(root.getAppContext())
holder.setTemplatePath(root.TemplatePath)
holder.setName(str(epoch))
holder.getLoadedTemplate().startup()
holder.getLoadedTemplate().setEnableLayout(1)

root.addComponent(holder)

instance = PyComponentWrapper(holder)
instance.Message = "time is "+ str(epoch)

#TODO: not sure why I have to resize it, but if I don't then the template instance is huge
system.gui.resizeComponent(holder, root.TemplateWidth, root.TemplateHeight)

toastCount = len(root.getComponents())
#TODO: holder.height, instance.height, instance.getHeight() return zero
yOffset = (toastCount * root.TemplateHeight) + (toastCount * root.Padding)
system.gui.moveComponent(holder, 0, root.height - yOffset)

'''
add toast anywhere
	system.util.sendMessage(message,severity)
	toast everywhere

invokeLater(root.DwellMs)
	if isPinned then pass
	transform off screen since fading is a pain in the ass
	remove from toasts
	trigger toasts.y < this.y to transform down
	
toast close
	transform off screen since fading is a pain in the ass
	remove from toasts
	trigger toasts.y < this.y to transform down
	
toast click
	explode toaster ?
	
toast overflow from screen
	do not invokeLater(root.DwellMs) until visible
	
toast unpin
	invokeLater(root.DwellMs)
'''

#system.gui.transform(newobj, newX=newobj.x+400, newY=newobj.y+100, duration=2000, coordSpace=system.gui.COORD_DESIGNER)

```

---

<div class="post-metadata">

**Author:** ![cmisztur2](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmisztur2/32/4243_2.png) [@cmisztur2](https://forum.inductiveautomation.com/u/cmisztur2)\
**Post date:** [October 1, 2017, 3:03am UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/5 "2017-10-01T03:03:39Z")

</div>

Ok, it pretty much works. I will post the code later.

[http://recordit.co/XZGERsclNd](http://recordit.co/XZGERsclNd)

---

<div class="post-metadata">

**Author:** ![Kyle\_Chase](https://avatars.discourse-cdn.com/v4/letter/k/9de0a6/32.png) [@Kyle\_Chase](https://forum.inductiveautomation.com/u/Kyle_Chase)\
**Post date:** [October 2, 2017, 6:00pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/6 "2017-10-02T18:00:49Z")

</div>

Here is my way of doing this. I wrote this when 7.0 came out, so I would expect there are quite a few upgrades.

The benefit of this method is the toast notification will pop up outside of the Ignition window, so if the user is browsing the web, watching porn, etc, this will pop up on top of that.

Call the method with `path.to.createNotifier()`

```auto
notifiers = []
def createNotifier(title="Hello", bodyText="World", time = 5000, bgColor=None, textColor=None):
	from javax.swing import JFrame,JLabel,JTextArea,JButton
	from javax.swing.border import LineBorder
	from java.awt import Dimension,Color,Font
	from java.awt.geom import RoundRectangle2D
	from net.miginfocom.swing import MigLayout
	from com.inductiveautomation.ignition.client.images import PathIcon
	from java.lang import Runnable
	
	if not bgColor:
		bgColor = Color.BLACK
		
	if not textColor:
		textColor = Color.WHITE
		
	frame = JFrame(title)
	frame.setAlwaysOnTop(True)
	frame.setUndecorated(True)
	frame.setMinimumSize(Dimension(300, 50))
	frame.setMaximumSize(Dimension(300, 50))
	frame.setSize(Dimension(300, 50))
	frame.setFocusableWindowState(False)
	frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE)
	frame.setOpacity(0.75)

	pane = frame.getContentPane()
	pane.setLayout(MigLayout("insets 5"))
	pane.setBorder(LineBorder(Color(90, 90, 90)))
	pane.setOpaque(True)
	pane.setBackground(bgColor)

	header = JLabel(title)
	header.setForeground(textColor)
	header.setFont(Font("Dialog", Font.PLAIN, 20))

	body = JTextArea(bodyText)
	body.setForeground(textColor)
	body.setBackground(bgColor)
	body.setFont(Font("Dialog", Font.PLAIN, 16))
	body.setLineWrap(True)
	body.setWrapStyleWord(True)
	body.setEditable(False)
	body.setOpaque(True)

	pane.add(header);
	def closeFrame(evt=None,frame=frame):
		notifiers.remove(frame)
		frame.dispose()
		if len(notifiers):
			orderNotifiers()

	if time <= 0:
		icon = PathIcon(frame,"Builtin/icons/16/delete2.png",16,16,True,True)
		button = JButton(icon,actionPerformed=closeFrame)
		button.setContentAreaFilled(False)
		button.setBorder(None)
		pane.add(button,"dock east,gap 5 5 5 5,alignx center,aligny center")
	
	frame.pack()

	body.setSize(frame.getWidth(), 1)
	pane.add(body, "newline,span,push")

	frame.pack()

	shape = RoundRectangle2D.Float(0.0, 0.0,frame.getWidth(), frame.getHeight(), 15.0, 15.0)
	frame.setShape(shape)

	frame.setVisible(True)

	notifiers.append(frame)

	if time > 0:
		system.util.invokeLater(closeFrame, time)
		
	if len(notifiers):
		orderNotifiers()

def orderNotifiers():
	from java.awt import Toolkit
		
	gc = getApp().getGraphicsConfiguration()
		
	if gc:
		sb = gc.getBounds()
		x = sb.x + sb.width - 10
		y = sb.y + 10
	else:
		ss = Toolkit.getDefaultToolkit().getScreenSize()
		x = ss.width - 10
		y = 10
		
	for f in notifiers:
		f.setLocation(x - f.getWidth(), y)
		y += f.getHeight() + 10
		
def getApp():
	from com.inductiveautomation.factorypmi.application import FPMIApp
	return FPMIApp.getInstance()

```

---

<div class="post-metadata">

**Author:** ![cmisztur2](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cmisztur2/32/4243_2.png) [@cmisztur2](https://forum.inductiveautomation.com/u/cmisztur2)\
**Post date:** [October 2, 2017, 6:29pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/7 "2017-10-02T18:29:37Z")

</div>

very cool, so more of a desktop integration.

---

<div class="post-metadata">

**Author:** ![Mario\_Victoria](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Mario\_Victoria](https://forum.inductiveautomation.com/u/Mario_Victoria)\
**Post date:** [September 16, 2023, 10:55pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/8 "2023-09-16T22:55:24Z")

</div>

Hello, great work Sir, I have a question:

how to you call this from a function script ?

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [September 16, 2023, 11:51pm UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/9 "2023-09-16T23:51:07Z")

</div>

> [@Mario\_Victoria](#):
>
> how to you call this from a function script ?

@cmisztur2 hasn't been seen in about 9 months, but looking at his video and his code, it appears that he is running his code directly from the action performed event handler of a button. The code posted by @Kyle_Chase is set up for a project library script, and the `path.to` portion of the call he posted can be whatever you set it up to be when you put the script in your library.  
**Example**  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/9/2/92e94c34e2cafb0c19c4a70f86afae123a96dc21.png)

If you put the above code in project library script that is unimaginatively called `libraryScripts`, then the call would be `libraryScripts.createNotifier()`.

---

<div class="post-metadata">

**Author:** ![Mario\_Victoria](https://avatars.discourse-cdn.com/v4/letter/m/85f322/32.png) [@Mario\_Victoria](https://forum.inductiveautomation.com/u/Mario_Victoria)\
**Post date:** [September 17, 2023, 12:40am UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/10 "2023-09-17T00:40:19Z")

</div>

For use Kyle\_Chase is necessary to install something in the server.

We are printing over TCP and using message handle on view to pop the messages, but we are having problem to catch the event on Ignition from the function.

But I will check it, thanks for replay 👏🏼

---

<div class="post-metadata">

**Author:** ![justinedwards.jle](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/justinedwards.jle/32/37854_2.png) [@justinedwards.jle](https://forum.inductiveautomation.com/u/justinedwards.jle)\
**Post date:** [September 17, 2023, 2:51am UTC](https://forum.inductiveautomation.com/t/toast-notifications/15522/11 "2023-09-17T02:51:10Z")

</div>

> [@Mario\_Victoria](#):
>
> message handle on view

These scripts were written for Vision, and for multiple reasons, they are not compatible with Perspective. If you're trying to create this functionality in a Perspective environment, you will have to go about it in a different way.
