NonModal Dialog Demo

Shared Libraries
Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This section is not for asking questions about writing your own macros.
Post Reply
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

NonModal Dialog Demo

Post by fcsw »

This has been tested on:
Win 11 25H2, LibreOffice 25.8.3.2
Ubuntu 24.04.3 LTS, LibreOffice 24.2.7.2

This calls ScriptForge, so it won't work in OO.

This is a demonstration of code that makes it possible to incorporate non-modal dialogs (NMDs) into a project without writing any new code. Since dialogs ordinarily require some code, this makes NMDs available to people who otherwise wouldn't be able to use them. If you decide to incorporate NMDs into your project, you need to know how to create them, open them in dialog design view, rename them, move them from one file to another, etc. In the Base Tutorial section of this forum, I've posted a tutorial on working with dialogs in LibreOffice.

This contains everything needed to add NMDs to an existing project without writing any new code. There are two macros: one for the buttons that open NMDs and one for the buttons that close NMDs There are no limits to the count of NMDs that can be open at the same time, aside from your computer's physical memory.

For this to work, form documents, button controls, and dialogs have to be named in a particular way. The code uses the form doc name and the button name to derive the dialog name so that it knows which dialog to open.

The easiest way to incorporate this into a project is to either use a copy of this demo as the starting point, or to copy the forms and dialogs from an existing project file to a copy of this file. In the first case, if you start with the correct names, or in the second case if you change the names so that the code can find the dialogs, you won't need to do much else.

In addition to a general purpose informational NMD, the demo includes a second type that can be used to type notes relating to a particular form document, store them, and retrieve them later.

For coders, this demonstrates:
  • Use of ScriptForge regular expressions
  • Avoiding some of the pitfalls of window listeners
  • Ensuring that the X in the title bar and the close button cause the same code to run when the dialog closes
  • Using one open procedure for two different types of NMDs
Multiple versions explained in comments below:
Attachments
nonModalDialogDemoVersion4.odb
(30.27 KiB) Downloaded 112 times
Last edited by fcsw on Wed Jan 07, 2026 12:24 am, edited 5 times in total.
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
JPL
Volunteer
Posts: 133
Joined: Fri Mar 30, 2012 3:14 pm

Re: NonModal Dialog Demo

Post by JPL »

fcsw wrote: Thu Nov 27, 2025 12:02 pm Instructions in the odb file.
Where is that file ?
Kubuntu 22.04 / LibO 24.2
Access2Base (LibO).
BaseDocumenter extension (LibO)
ScriptForge (LibO)
Documentation on https://help.libreoffice.org/latest/en- ... bPAR=BASIC
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

Re: NonModal Dialog Demo

Post by fcsw »

I've made several attempts over the past 24 hours to upload the file. It looks like it finally worked.
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
JeJe
Volunteer
Posts: 3134
Joined: Wed Mar 09, 2016 2:40 pm

Re: NonModal Dialog Demo

Post by JeJe »

If you want the dialog's titlebar close to work instead of needing a button

Code: Select all

'in your sub to create the dialog, before the setvisible line
objCurrentDlg.addTopWindowListener(CreateUnoListener("NonModalWindowListener_", "com.sun.star.awt.XTopWindowListener"))

Code: Select all

'in the module
'XTopWindowListener subs
Sub NonModalWindowListener_disposing(ev) 
End Sub
Sub NonModalWindowListener_windowOpened(ev)
End Sub
Sub NonModalWindowListener_windowClosing(ev) 
ev.source.dispose 'if want closeable need this
End Sub
Sub NonModalWindowListener_windowClosed(ev)
End Sub
Sub NonModalWindowListener_windowMinimized(ev)
End Sub
Sub NonModalWindowListener_windowNormalized(ev)
End Sub
Sub NonModalWindowListener_windowActivated(ev)
End Sub
Sub NonModalWindowListener_windowDeactivated(ev)
End Sub
'/XTopWindowListener subs

Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

Re: NonModal Dialog Demo

Post by fcsw »

Thanks for the tip. I made a crash copy of the demo and inserted your code. It worked ... once. After that I couldn't open the dialog again.

Code: Select all

Sub NonModalWindowListener_windowClosing(ev) 
ev.source.dispose 'if want closeable need this
End Sub
This leaves the dialog object in the dictionary. The code won't let you add a second copy of a dialog to the dictionary. So, I tried

Code: Select all

Sub NonModalWindowListener_windowClosing(objEvent As Object) 
	mcrCloseDlg( objEvent )
End Sub
This resulted in a "Object variable not set" error in mcrCloseDlg at this line:

Code: Select all

strDlgName = objEvent.Source.Context.model.Name
Obviously the window listener event has a different source than the button Execute Action event. I replaced the line above with

Code: Select all

If IsNull( gdictOpenDlgs ) Then Exit Sub
	If CBool( InStr( objEvent.Source.implementationName, "Button" ) ) Then
		strDlgName = objEvent.Source.Context.model.Name
	ElseIf CBool( InStr( objEvent.Source.implementationName, "Dialog" ) ) Then
		strDlgName = objEvent.Source.Model.Name
	End If
This works. The X closes the dialog, the dictionary is updated, and the dialog is ready to be opened again.

However, the IsNull test is because the windowClosing event runs twice. If only one dialog has been opened, the first run sets the dictionary variable to null. So my question is, why does the windowClosing event run twice?

Once again, thanks for the tip.
Last edited by floris v on Fri Nov 28, 2025 9:31 pm, edited 1 time in total.
Reason: Added Code tags, floris v
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
JeJe
Volunteer
Posts: 3134
Joined: Wed Mar 09, 2016 2:40 pm

Re: NonModal Dialog Demo

Post by JeJe »

In case its any use, here's my full code for creating a nonmodal dialog, it only works for location=application which isn't what you want, but I've not found a problem with multiple instances of dialogs with it and no need to store a reference anywhere to any created dialogs.

Code: Select all

'CREATE NON-MODAL DIALOG
'your library with this code has to be in MyMacros not in the document or the URI will give an error.

Sub Test
	oParent = ThisComponent.getCurrentController().getFrame().getContainerWindow()
	dlg = CreateNonModalDialog(oparent,"JeTest.Dialog1",true)
	dlg.setpossize 100,100,500,500,15
	dlg.setvisible true
End Sub

Function CreateNonModalDialog(oParent,DialogParam, Closeable as boolean) As Variant
	dim dlg,CWP,sURL As String
	sURL = "vnd.sun.star.script:" & DialogParam & "?location=" & "application"
	CWP = CreateUnoService("com.sun.star.awt.ContainerWindowProvider")
	dlg = CWP.createContainerWindow(sURL, "", oParent, nothing)
	if Closeable then 'if want closeable need this
	dlg.addTopWindowListener(CreateUnoListener("NonModalWindowListener_", "com.sun.star.awt.XTopWindowListener"))
	end if
	CreateNonModalDialog = dlg
End Function

'XTopWindowListener subs
Sub NonModalWindowListener_disposing(ev) 
End Sub
Sub NonModalWindowListener_windowOpened(ev)
End Sub
Sub NonModalWindowListener_windowClosing(ev) 
ev.source.dispose 'if want closeable need this
End Sub
Sub NonModalWindowListener_windowClosed(ev)
End Sub
Sub NonModalWindowListener_windowMinimized(ev)
End Sub
Sub NonModalWindowListener_windowNormalized(ev)
End Sub
Sub NonModalWindowListener_windowActivated(ev)
End Sub
Sub NonModalWindowListener_windowDeactivated(ev)
End Sub
'/XTopWindowListener subs

sub commandclose(ev) 'if window is not closeable you might want a button perhaps to close it
ev.source.context.dispose
end sub


'********************************************************************

Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 3134
Joined: Wed Mar 09, 2016 2:40 pm

Re: NonModal Dialog Demo

Post by JeJe »

Adapting my code to use your GetProcessServiceManager method we can show a document dialog.

Code: Select all

REM  *****  BASIC  *****

'CREATE NON-MODAL DIALOG
'your library with this code has to be in MyMacros not in the document or the URI will give an error.

Sub Test
	oParent = ThisComponent.getCurrentController().getFrame().getContainerWindow()
	dlg = CreateNonModalDialog(oparent,"Standard.Dialog1",true)
	dlg.setpossize 100,100,500,500,15
	dlg.setvisible true
End Sub

Function CreateNonModalDialog(oParent,DialogParam, Closeable as boolean) As Variant
	dim dlg,CWP,sURL As String,objPsm, avarArgs( 0 ) As New com.sun.star.beans.NamedValue
	sURL = "vnd.sun.star.script:" & DialogParam & "?location=document"

	objPsm = GetProcessServiceManager.createInstanceWithArguments( "com.sun.star.awt.DialogProvider2", Array( Thiscomponent ) )
		
	avarArgs( 0 ).Name = "ParentWindow"
	avarArgs( 0 ).Value = thiscomponent.CurrentController.Frame.ContainerWindow

	dlg =objPsm.createDialogWithArguments( sURL, avarArgs)

	if Closeable then 'if want closeable need this
	dlg.addTopWindowListener(CreateUnoListener("NonModalWindowListener_", "com.sun.star.awt.XTopWindowListener"))
	end if
	CreateNonModalDialog = dlg
	
End Function

'XTopWindowListener subs
Sub NonModalWindowListener_disposing(ev) 
End Sub
Sub NonModalWindowListener_windowOpened(ev)
End Sub
Sub NonModalWindowListener_windowClosing(ev) 
ev.source.dispose 'if want closeable need this
End Sub
Sub NonModalWindowListener_windowClosed(ev)
End Sub
Sub NonModalWindowListener_windowMinimized(ev)
End Sub
Sub NonModalWindowListener_windowNormalized(ev)
End Sub
Sub NonModalWindowListener_windowActivated(ev)
End Sub
Sub NonModalWindowListener_windowDeactivated(ev)
End Sub
'/XTopWindowListener subs

sub commandclose(ev) 'if window is not closeable you might want a button perhaps to close it
ev.source.context.dispose
end sub


Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
JeJe
Volunteer
Posts: 3134
Joined: Wed Mar 09, 2016 2:40 pm

Re: NonModal Dialog Demo

Post by JeJe »

Looks like we can replace the named arguments with an empty array and still get the dialog.

Code: Select all

Function CreateNonModalDialog(oParent,DialogParam, Closeable as boolean) As Variant
	dim dlg,sURL As String,objPsm
	sURL = "vnd.sun.star.script:" & DialogParam & "?location=document"

	objPsm = GetProcessServiceManager.createInstanceWithArguments( "com.sun.star.awt.DialogProvider2", Array( Thiscomponent ) )
	
	dlg =objPsm.createDialogWithArguments( sURL, ARRAY())

	if Closeable then 'if want closeable need this
	dlg.addTopWindowListener(CreateUnoListener("NonModalWindowListener_", "com.sun.star.awt.XTopWindowListener"))
	end if
	CreateNonModalDialog = dlg
	
End Function
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

Re: NonModal Dialog Demo

Post by fcsw »

Code: Select all

'your library with this code has to be in MyMacros not in the document or the URI will give an error.
Unfortunately that rules out your last snippets of code. All of my code comes from a larger project that must be distributed as a single odb file. That's too bad because I really don't like global variables. If there were a way to do this with code in the document, I would be very interested.
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
JeJe
Volunteer
Posts: 3134
Joined: Wed Mar 09, 2016 2:40 pm

Re: NonModal Dialog Demo

Post by JeJe »

Sorry - that's a leftover comment from the original code I didn't remove - it no longer applies when using GetProcessServiceManager. Works fine with the code in a document.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

Re: NonModal Dialog Demo

Post by fcsw »

Works fine with the code in a document.
It does! Actually, if you call it from a command button, it needs a little tweaking. This

Code: Select all

Array( ThisComponent )
should be this

Code: Select all

Array( ThisDatabaseDocument )
or this

Code: Select all

Array( ThisComponent.Parent )
Also this

Code: Select all

objPsm.createDialogWithArguments( strDlgCreator, Array() )
causes LO to bring the main window to the front, so that the dialog floats on top of the main window and not the form doc window it was called from. Passing in the arguments as per my original code restores the correct behavior.

I've eliminated the ugly global variable, Ive removed the code that handles the dictionary, and form docs no longer need to call a cleanup macro when they close. I've eliminated a couple of steps for non-coders using this to include NMDs in their projects. Definite improvement!

Thanks.
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
fcsw
Posts: 12
Joined: Sun Aug 31, 2025 8:49 am
Location: Mars

Re: NonModal Dialog Demo

Post by fcsw »

This demo originally used a more complicated approach to managing multiple NMDs. User jeje suggested a simpler way. His approach was clearly superior, but it involves an aspect of UNO programming that I had little experience with. Working out the implementation details hasn't been straightforward, and the upshot is that I'm now on version 4 of the demo. I apologize to everyone who downloaded a previous version, but having undertaken to demonstrate how this is done, I feel obligated to demonstrate the best coding techniques.

Version 3 opened the dialog with the dialog's setVisible method, but closed the dialog with the dispose method from the
dialog's model, even though there is a dispose method at the dialog level. Furthermore, when setVisible executes, it passes program control to the window listener, but when the window listener exits and passes control back to the procedure, the procedure doesn't resume at the point where it passed control, but at a later, seemingly random point. In Version 3, this doesn't cause a problem, but it obviously could cause a problem in different circumstances.

You can open the dialog with the dialogs execute method, and close it with the endExecute method. However, execute passes control to the window listener, which doesn't return control until after the dialog closes. In other words, the open procedure runs until the execute method, and then halts until the close procedure runs, and the rest of the open procedure runs only after the dialog is closed.

In both cases, the solution is to put execute or setVisible( True ) at the end of the open procedure, ensuring that all the code runs before the procedure passes control to the window listener.

You should always follow endExecute or setVisible( False ) with the dispose method. I tried commenting out dispose and watched memory usage creep up when I repeatedly opened and closed dialogs. Dispose removes dialogs from memory so this doesn't happen.

Again, my apologies for multiple versions, but I started with an approach I understood and switched to something I was not completely familiar with. The end result is a better demo, but the process of getting there was messy.
NASA Mars Rover Hacking Project: Martians supplying Earth with bogus scientific data since 1997.
Post Reply