Modal Pop-Up How-To?

So I have been looking all over the forums and even though there are solutions for Modal pop-up windows, it doesn’t look like any of them work for me. I have a variety of pop-up windows that all need to be able to lock out the user from selecting any and all background buttons.

Searched Solutions:

The best example I have found is the 2-State Toggle Button with Confirm. The Confirmation Pop-Up has the exact feature I need to prevent any and all clicks to the background (docked or otherwise). How can I implement this? Custom Jython script in my script library? Any other recommendations?

The auto-logout function (which I cannot find where it exists) is pretty nifty and has some of the same features as well (locks input other than message box and grays-out the background). I also noticed the “Prevent Popup/Docking Overlap” option in Project Properties. I might uncheck that to see what happens.

2 Likes

What about the system.gui.confirm method?

https://docs.inductiveautomation.com/display/DOC/system.gui.confirm

That works if the button only does one thing. I need a pop-up that has 2-3 buttons and associated tags being changed. E.g. Up/Down/Stop, On/Off, Increase1/Increase2/Decrease1/Decrease2, and it gets even more complicated. The goal is to get the pop-up to have the same focus and immutability as that confirm dialog box.

Sadly, the default popup is a sort of internal frame (you can notice it has a different border than the confirm popup). It doesn’t seem to be a real popup, but just some sort of floating component inside the screen that always stays on top.

Perhaps you can try to create a genuine Windows popup like explained here: Single Vision Client on Multiple Monitors

Then it should be possible to set the JFrame always on top as explained here: https://stackoverflow.com/questions/297938/always-on-top-windows-with-java

Though it’s still very much a hack (as further comments explain)

1 Like

Maybe you have tried this, but this generally works for me:

from javax.swing import JOptionPane

pane = JOptionPane()

bAllowCancel = True
strMessage = "Click One to Confirm, Two to Deny or Three to Cancel"
strTitle = "Confirm"
frame = None

btnOpts = JOptionPane.YES_NO_CANCEL_OPTION
msgType = JOptionPane.QUESTION_MESSAGE
icon = None
options = ["One", "Two", "Three"]

idxResult = pane.showOptionDialog(frame, strMessage, strTitle, btnOpts, msgType, icon, options, options[2])

print idxResult

See https://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html

3 Likes

Here is what I came up with, as I have been trying to acompolish the same. I started with the popup with opaque approach you linked. Then on my popup open and close events I set a client tag boolten to indicate a modal is open. In any docked windows, I then used that tag to enable an overlay. Only problem is that I can still click events in the docked windows, thats the last thing to figure out how to disable.

2 Likes

I like that, do you have example code for it?

One rabbit-hole I may try: A client tag called DisableButtons. This tag is set 1 when a pop-up opens and 0 when it gets closed. All buttons on the screen utilize the DisableButtons in it’s Enabled property… Messy, but possible. Another thought is to ignore mouse pushes/clicks if it is outside of the pop-up window’s boundaries. Less messy, but more code (that could be reused).

Just messing around. I combined the opaque pop-up method (below) with the following setLocation code in the script area internalFrameActivated.

from java.awt import Color
event.source.setOpaque(0)

window = system.gui.getParentWindow(event)
window.setLocation(-20,-70)

setLocation fires after I open the window again. Odd. I wonder if there is another event handler I could use instead (I tried internalFrameOpened to same effect)

All containers allow mouse clicks through by default.
Easiest way to disable that is on the container, In the Mouse Clicked Event put “pass” in it.

2 Likes

Alright, who is ready for some hacking?

This might get complicated, but here is how I have achieved this in the past.

As an example, I will use my custom lock screen, attached in this post.

Here is the script.

def lockScreen():
	from javax.swing import SwingUtilities,JFrame		#Import some stuff
	import system.nav
	if system.util.getGlobals().has_key('lockScreen'):	#Check if the screen has been locked before.  This really just saves the set up code
		system.util.getGlobals()["app"].getRootPane().getGlassPane().visible = True				#Make the glass pane visible
		system.util.getGlobals()["lockScreen"].visible = True									#Make the lock screen visible
	else:	
		lockScreen = system.nav.openWindow('Lock Screen')										#Open the lock screen once.  To get a reference to the window
		system.util.getGlobals()["lockScreen"] = lockScreen										#Set a global variable referencing that instance
		app = SwingUtilities.getAncestorOfClass(JFrame, lockScreen)								#Get the app pane
		system.util.getGlobals()["app"] = app													#Set a reference to the app pane
		system.nav.closeWindow('Lock Screen')													#Close the window.  We have a reference now
		lockScreen.setDefaultCloseOperation(lockScreen.DISPOSE_ON_CLOSE)						#Set window close action
		app.getRootPane().getGlassPane().visible = True											#Make the glass pane visible
		app.getRootPane().getGlassPane().add(lockScreen)										#Add the custom  screen to the glass pane
		lockScreen.visible = True																#Make the window visible.

The main thing you have to change here is the window you open for the lockScreen. This window will open in the glass pane, covering everything else. How you decorate the window is up to you.

This is code I had in FPMI, so from when I was first learning Python. I will see if I can clean it up.

Let me know if you have any questions.
Lock Screen_2017-09-03_2341.proj (12.5 KB)

3 Likes

The simplest way I’ve found to do this is:

  1. Create a modal dialog with opaque background as described here.
  2. Create a Client Boolean tag called ‘modal’.
  3. Create your docked window, then create a container the full size of the docked window and move it to the top of the z-order. Set the container’s Opaque property to false and bind it’s Visibility property to the modal Client tag. In the container’s mouseClicked, mousePressed and mouseReleased’ events enter pass to consume the mouse clicks.
  4. When you open and close your popup make sure you set and clear the modal tag.

This should ensure you can still see all controls under the popup but cannot click on any of them. I also like to put a tint on the popup background and container to focus attention on the popup.

2 Likes

So you want to create a popup window that users can’t click off of and stays above the parent window? Sorry, not really familiar with the term.

Here’s what I came up with:

  1. The first part would be clicking on the popup window and setting the layer above the layer of the parent window. That should keep it on top of the parent until the user closes the window. It won’t filter clicks though, we’ll get to that.

  2. Then turn off close-able so the X doesn’t display at the top. Turn off resizeable, and turn off maximizable.

  3. Then in internal frame deactivated for the popup make it center the window using the script builder (make sure it doesn’t open another instance). Go into the script editor and do. This make the window recenter and refocus if the user clicks off. You probably want to make sure the window always caches.

try:
list(system.gui.getOpenedWindows()).index(‘WINDOWNAME’)
centerthewindow()
except:
“” #If you don’t do this when you close the window but click something else the popup will reopen.

  1. Then on frame activated open a second popup window with a layer higher than the root container but not higher than the popup we want. No titlebar or border, with an invisible transparent root container. This will sponge clicks off of our modal window. You can add a Windows ding with system.util.beep(), if you so wish. (Please don’t.).

  2. For our modal window we want to open and close our invisible window on the InternalFrame ActivatedDeactivated of our modal window.

  3. I would try and do something with binding the name to the root container so you don’t have to change the window name in the scripts every time you want to re-use it.

If you want to Cellophane over the other window or whatever:

You need to make the root container of your click blocker window an opaque color, and then in the visionWindowOpened put this script in.

window = system.gui.getParentWindow(event)
window.setOpaque(0)

Result:

All great suggestions, but I may not have been clear enough. I already have it working for the main window in which the pop-up occurs. What I don’t have is when there is a tabbed navigation and a main window (e.g. Single-Tier Nav, West), I cannot make the pop-up “cover” or disable the clicking of the navigation bar (as my video sort-of shows).

I’ll dig into Kyle_Chase’s example later, but I don’t want to get too deep into Swing as other maintenance users down the line will not be able to fix any issues on-site (KISS methodology).

Ah I see. For my solution I’m thinking getOpenedWindows() and then adding the size of all the docked windows and sizing the transparent blocker window based on that, instead of maximizing the window. In theory it should cover all docked navigation and windows.

I’ll give that a try.

Hi Joe,

You can’t make anything else cover a docked window, but using a container as I described above works and is not too complicated.

That is not totally true. My solution opens in the glass pane, and covers all windows, docked or not, as well as the menu bar.

1 Like

I just tried your code and lockScreen.proj and the timer on the lockScreen window never fires…:thinking:

That seems to be a bug with the timer component. It is enabled on the window, its just not firing for some reason.

Just had need to do this and achieved it using information from this thread as well as others. It “greys out” and prevents clicking on all other windows except docked windows (for me, that’s not a huge drama as the only dock I have is the navigation bar, and I’m fine with the user switching windows behind the scenes; they can’t do anything with them except look)

  1. Set the Layer of the modal popup to 99
  2. Create a popup window called “Focus Mask”. Set it to start maximised, never display title bars or borders, and to a size larger than your largest display (I set mine to 1920x1080). Set the Layer of this window to 98
  3. On the Focus Mask window’s root container, set the visible property to True, and the background colour to be partially opaque
  4. On the Focus Mask Window, add the following script to the VisionWindowOpened trigger:

window=system.gui.getParentWindow(event) window.setOpaque(0)
5 . On the modal popup, use a VisionWindowOpened script to open the “Focus Mask” window, and a VisionWindowClosed script to close the “Focus Mask” window

3 Likes