[Solved] [Python] Display Calc chart in dialog

Creating a macro - Writing a Script - Using the API (OpenOffice Basic, Python, BeanShell, JavaScript)
Post Reply
kiloran
Posts: 36
Joined: Sun Oct 14, 2012 2:06 pm

[Solved] [Python] Display Calc chart in dialog

Post by kiloran »

I have a chart in a calc spreadsheet and I'd like to display the chart in a dialog box using a Python macro.

I'm comfortable with Python, and have no problem using Python to create the dialog window with radio buttons, listboxes, imageboxes and whatever, but I'm completely stumped with how to get a chart into the dialog.

Can anyone point me in the right direction?
Last edited by kiloran on Tue Jun 16, 2020 8:55 pm, edited 1 time in total.
--kiloran
LibreOffice 6 on Windows 10 and Linux Mint
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: [Python] Display Calc chart in dialog

Post by Villeroy »

A Basic module which generates a dialog showing a push button and 2 documents side by side.

Code: Select all

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

global component1
global component2

Sub Main
	component1 = Null
	component2 = Null
	
   ' Get an AWT toolkit.
   ' OOo's AWT, not a Java AWT.
   oAwtToolkit = CreateUnoService( "com.sun.star.awt.Toolkit" )
   
   ' Create a top level window.
   oWindow = CreateTopWindow( oAwtToolkit, 100, 200, 800, 700 )
   
   ' Create a sub-window.
   oSubWindow = CreateSubWindow( oAwtToolkit, oWindow, 100, 200, 300, 400 )
   
   ' Create a sub-window.
   oSubWindow2 = CreateSubWindow( oAwtToolkit, oWindow, 450, 200, 300, 400 )
   
   ' Create a Window Listener
   oTopWindowListener = CreateUnoListener( "TopWindowListener_","com.sun.star.awt.XTopWindowListener" )
   
   oWindow.addTopWindowListener(oTopWindowListener)
   
   ' At this point, you should check out the interfaces
   '  and all of the methods that they give you for
   '  manipulating this new oWindow.
   ' See comment in CreateTopWindow() below.
   
   ' Change the background color of the window to baby blue.
   oWindow.setBackground( RGB( 240, 240, 255 ) )
   
   ' At this point, if you stop the program, you will have a
   '  new OOo window on the screen, but you cannot do anything
   '  with it.  You cannot even close it!
   ' In fact, you have to kill the OOo process, as even OOo
   '  cannot close this window since it has no Frame and
   '  therefore is not integrated into the desktop environment.
   ' So I had to go on writing additional code....
   
   ' Create a new frame.
   oFrame = CreateUnoService( "com.sun.star.frame.Frame" )
   ' Initialize this frame with our new window.
   oFrame.initialize( oWindow )
   ' Tell the frame that its parent is the Desktop.
   oFrame.setCreator( StarDesktop )
   
   ' At this point you have a window that can be resized, moved, or closed.
   
   ' Create a new frame.
   oSubFrame = CreateUnoService( "com.sun.star.frame.Frame" )
   ' Initialize this frame with our new window.
   oSubFrame.initialize( oSubWindow )
   ' Tell the frame that its parent is the Desktop.
   oSubFrame.setCreator( StarDesktop )
   
   ' Create a new frame.
   oSubFrame2 = CreateUnoService( "com.sun.star.frame.Frame" )
   ' Initialize this frame with our new window.
   oSubFrame2.initialize( oSubWindow2 )
   ' Tell the frame that its parent is the Desktop.
   oSubFrame2.setCreator( StarDesktop )
   
   
   ' add subframe to main frame
   oFrame.getFrames().append(oSubFrame)
   oFrame.getFrames().append(oSubFrame2)
   
   frames = oFrame.getFrames()
   
   'wait(500)
   'msgbox "Num Frames: " & frames.getCount()
   
   ' Note that if you wanted to, you could now load a component
   '  into your newly created window!
   component1 = oSubFrame.loadComponentFromURL( "private:factory/simpress","_self", 0, Array() )

   ' Note that if you wanted to, you could now load a component
   '  into your newly created window!
   component2 = oSubFrame2.loadComponentFromURL( "private:factory/scalc","_self", 0, Array() )

   ' Create a new button.
   oBtnCtrl = MakeButtonCtrl( oAwtToolkit, oWindow, "Meow",_
         MakeRectangle( 20, 30, 100, 40 ) )
   
   ' Create a menu.
'   CreateMenuBar( oWindow )
' menubar to be provided later....
' okay, well maybe not, see below...

	'wait(10 * 1000)	' wait ten seconds
	
	'msgbox "Click okay to close first frame..."
	'component1.close(false)
	
	'msgbox "Click okay to close second frame..."
	'component2.close(false)
	
	exit sub
	
Main_error:
	msgbox "error!"
	resume next
	
End Sub


Sub TopWindowListener_TopWindowListener(oEventObject)
End Sub

Sub TopWindowListener_windowClosing(oEventObject)
	'msgbox "window closing!"

	'wait(1000)
	
	'msgbox "Click okay to close first frame..."
	if not isNull(component1) then
		component1.close(false)
	end if
	
	'msgbox "Click okay to close second frame..."
	if not isNull(component2) then
		component2.close(false)
	end if
	
	'wait(10000)
End Sub

Sub TopWindowListener_windowClosed(oEventObject)
End Sub

Sub TopWindowListener_windowMinimized(oEventObject)
End Sub

Sub TopWindowListener_windowNormalized(oEventObject)
End Sub

Sub TopWindowListener_windowActivated(oEventObject)
End Sub

Sub TopWindowListener_windowDeactivated(oEventObject)
End Sub

Sub TopWindowListener_disposing(oEventObject)
	'msgbox "Disposing..."
	'wait(1000)
End Sub



Function CreateTopWindow( oAwtToolkit, x, y, w, h )
   oWindowDesc = CreateUnoStruct( "com.sun.star.awt.WindowDescriptor" )
   With oWindowDesc
      ' specifies a top level window on the desktop. It is also a container.
      .Type = com.sun.star.awt.WindowClass.TOP
      ' is a modal top level window on the desktop. It is also a container.
'      .Type = com.sun.star.awt.WindowClass.MODALTOP
      ' is a container that may contain other components. It is not a top window.
'      .Type = com.sun.star.awt.WindowClass.CONTAINER
      ' is the simplest window. It can be a container.
'      .Type = com.sun.star.awt.WindowClass.SIMPLE
      
      ' specifies the name of the component service.
      ' A zero length name means that the vcl creates a blank top,
      '  a container, or a simple window.
      .WindowServiceName = ""
      
      ' specifies the parent of the component.
      ' If Parent == 0 && ParentIndex == -1 , then the window is on the desktop.
'      .Parent = null
'      .Parent = createUnoValue( "com.sun.star.awt.XWindowPeer", 0 )
'      .Parent = oAwtToolkit.getDesktopWindow()
      ' specifies the index of the parent window, if available.
      ' If Parent == 0 and this struct is a member of an array,
      '  then this is the offset from the beginning of the array to the parent.
      '  A value of -1 means desktop.
'      .ParentIndex = -1
      
      ' specifies the position and size of the window.
      ' This member is ignored if the window attribute is
      '  WindowAttribute::FULLSIZE .
      .Bounds = MakeRectangle( x, y, w, h )
      
      ' specifies the window attributes.
      .WindowAttributes = 0
      ' specifies that the window is initially visible.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SHOW
      ' specifies that the window fills the complete desktop area.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.FULLSIZE
      ' specifies that the window is optimum size.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.OPTIMUMSIZE 
      ' specifies that the window is minimum size.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.MINSIZE
      ' specifies that the window has visible borders.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.BORDER
      ' specifies that the size of the window can be changed by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SIZEABLE
      ' specifies that the window can be moved by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.MOVEABLE
      ' specifies that the window can be closed by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.CLOSEABLE
      '[ DEPRECATED ] specifies that the window should support the XSystemDependentWindowPeer interface.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SYSTEMDEPENDENT
   End With
   
   oXWindowPeer = oAwtToolkit.createWindow( oWindowDesc )
   
   ' Look at the capabilities that these interfaces give you
   '  for manipulating your newly created window.
   ' Interfaces supported by oXWindowPeer...
   '  com.sun.star.awt.XTopWindow
   '  com.sun.star.awt.XWindow
   '  com.sun.star.awt.XWindowPeer
   '  com.sun.star.awt.XVclContainer
   '  com.sun.star.awt.XVclContainerPeer
   '  com.sun.star.awt.XVclWindowPeer
   '  com.sun.star.awt.XLayoutConstraints
   '  com.sun.star.awt.XView
   '  com.sun.star.awt.XDevice
   '  com.sun.star.lang.XEventListener
   '  com.sun.star.lang.XComponent
   '  com.sun.star.lang.XTypeProvider
   '  com.sun.star.accessibility.XAccessible
   '
   ' Properties...
   '  <object> MenuBar
   '  <array>  Windows
   '  <array>  Group
   '  <object> PosSize
   '  Boolean  Visible
   '  Boolean  Enable
   '  <object> Toolkit
   '  <object> Pointer
   '  Long     Background
   '  Boolean  DesignMode
   '  Long     Foreground
   '  <object> ControlFont
   '  <object> MinimumSize
   '  <object> PreferredSize
   '  <object> AccessibleContext
   '  <object> Graphics
   '  <object> Size
   '  <object> Info
   '  <array>  FontDescriptors
   
   CreateTopWindow = oXWindowPeer
End Function



Function CreateSubWindow( oAwtToolkit, parentWindow, x, y, w, h )
   oWindowDesc = CreateUnoStruct( "com.sun.star.awt.WindowDescriptor" )
   With oWindowDesc
      ' specifies a top level window on the desktop. It is also a container.
'      .Type = com.sun.star.awt.WindowClass.TOP
      ' is a modal top level window on the desktop. It is also a container.
'      .Type = com.sun.star.awt.WindowClass.MODALTOP
      ' is a container that may contain other components. It is not a top window.
'      .Type = com.sun.star.awt.WindowClass.CONTAINER
      ' is the simplest window. It can be a container.
      .Type = com.sun.star.awt.WindowClass.SIMPLE
      
      ' specifies the name of the component service.
      ' A zero length name means that the vcl creates a blank top,
      '  a container, or a simple window.
      .WindowServiceName = ""
      
      ' specifies the parent of the component.
      ' If Parent == 0 && ParentIndex == -1 , then the window is on the desktop.
'      .Parent = 0
'      .Parent = createUnoValue( "com.sun.star.awt.XWindowPeer", 0 )
'      .Parent = oAwtToolkit.getDesktopWindow()
      .Parent = parentWindow
      ' specifies the index of the parent window, if available.
      ' If Parent == 0 and this struct is a member of an array,
      '  then this is the offset from the beginning of the array to the parent.
      '  A value of -1 means desktop.
'      .ParentIndex = -1
      
      ' specifies the position and size of the window.
      ' This member is ignored if the window attribute is
      '  WindowAttribute::FULLSIZE .
      .Bounds = MakeRectangle( x, y, w, h )
      
      ' specifies the window attributes.
      .WindowAttributes = 0
      ' specifies that the window is initially visible.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SHOW
      ' specifies that the window fills the complete desktop area.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.FULLSIZE
      ' specifies that the window is optimum size.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.OPTIMUMSIZE
      ' specifies that the window is minimum size.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.MINSIZE
      ' specifies that the window has visible borders.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.BORDER
      ' specifies that the size of the window can be changed by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SIZEABLE
      ' specifies that the window can be moved by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.MOVEABLE
      ' specifies that the window can be closed by the user.
      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.CLOSEABLE
      '[ DEPRECATED ] specifies that the window should support the XSystemDependentWindowPeer interface.
'      .WindowAttributes = .WindowAttributes + com.sun.star.awt.WindowAttribute.SYSTEMDEPENDENT
   End With
   
   oXWindowPeer = oAwtToolkit.createWindow( oWindowDesc )
   
   ' Look at the capabilities that these interfaces give you
   '  for manipulating your newly created window.
   ' Interfaces supported by oXWindowPeer...
   '  com.sun.star.awt.XTopWindow
   '  com.sun.star.awt.XWindow
   '  com.sun.star.awt.XWindowPeer
   '  com.sun.star.awt.XVclContainer
   '  com.sun.star.awt.XVclContainerPeer
   '  com.sun.star.awt.XVclWindowPeer
   '  com.sun.star.awt.XLayoutConstraints
   '  com.sun.star.awt.XView
   '  com.sun.star.awt.XDevice
   '  com.sun.star.lang.XEventListener
   '  com.sun.star.lang.XComponent
   '  com.sun.star.lang.XTypeProvider
   '  com.sun.star.accessibility.XAccessible
   '
   ' Properties...
   '  <object> MenuBar
   '  <array>  Windows
   '  <array>  Group
   '  <object> PosSize
   '  Boolean  Visible
   '  Boolean  Enable
   '  <object> Toolkit
   '  <object> Pointer
   '  Long     Background
   '  Boolean  DesignMode
   '  Long     Foreground
   '  <object> ControlFont
   '  <object> MinimumSize
   '  <object> PreferredSize
   '  <object> AccessibleContext
   '  <object> Graphics
   '  <object> Size
   '  <object> Info
   '  <array>  FontDescriptors
   
   CreateSubWindow = oXWindowPeer
End Function




Function MakeButtonCtrl( oAwtToolkit, oWindow, Optional cLabel, Optional oPosSizeRect )
   ' Create a new button model.
   oButtonModel = CreateUnoService( "com.sun.star.awt.UnoControlButtonModel")
   
   ' Create a new button control.
   oButtonCtrl = CreateUnoService( "com.sun.star.awt.UnoControlButton" )
   
   ' Tell the control that it has a model.
   oButtonCtrl.setModel( oButtonModel )
   
   ' Tell the control to create its window peer.
   ' (To understand what this means, it is helpful to
   '  read some Java documention about how Java's AWT works
   '  even though we're not working with Java AWT here.)
   ' Basically, this puts something visible onto the window.
   oButtonCtrl.createPeer( oAwtToolkit, oWindow )
   
   If Not IsMissing( cName ) Then
      oButtonModel.Label = cLabel
      oButtonModel.ImageURL = "file:///c:/tmp/test-small.jpg"
   EndIf
   If Not IsMissing( oPosSizeRect ) Then
      oButtonCtrl.setPosSize( _
                  oPosSizeRect.X, oPosSizeRect.Y,_
                  oPosSizeRect.Width, oPosSizeRect.Height,_
                  com.sun.star.awt.PosSize.POSSIZE )
   EndIf
   
   MakeButtonCtrl = oButtonCtrl
End Function


' ripped from my library....

Function MakeRectangle( ByVal nX As Long, ByVal nY As Long,_
                  ByVal nWidth As Long, ByVal nHeight As Long ) As com.sun.star.awt.Rectangle
   oRectangle = createUnoStruct( "com.sun.star.awt.Rectangle" )
   With oRectangle
      .X = nX
      .Y = nY
      .Width = nWidth
      .Height = nHeight
   End With
   MakeRectangle() = oRectangle
End Function 
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
JeJe
Volunteer
Posts: 2764
Joined: Wed Mar 09, 2016 2:40 pm

Re: [Python] Display Calc chart in dialog

Post by JeJe »

Another option is to export the chart as a picture and then load it into an image control in the dialog.
Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
hubert lambert
Posts: 145
Joined: Mon Jun 13, 2016 10:50 am

Re: [Python] Display Calc chart in dialog

Post by hubert lambert »

Hi,

Here's two examples, based on JeJe suggestion.
The first uses a dialog designed with the basic gui editor.
The second creates the dialog from scratch. The later code :

Code: Select all

def createdialog2(event=None):
    doc = XSCRIPTCONTEXT.getDocument()
    # get the chart image
    sheet = doc.Sheets[0]
    chart_bitmap = sheet.Charts[0].EmbeddedObject.DrawPage[0].Bitmap
    chart_width = chart_bitmap.Size.Width
    chart_height = chart_bitmap.Size.Height
    # create the dialog
    ctx = XSCRIPTCONTEXT.getComponentContext()
    smgr = ctx.ServiceManager
    dlg_model = smgr.createInstance("com.sun.star.awt.UnoControlDialogModel")
    dlg = smgr.createInstance("com.sun.star.awt.UnoControlDialog")
    dlg.setModel(dlg_model)
    dlg.setPosSize(50, 50, chart_width+2*10, chart_height+6*10, 15)
    dlg.Title = "Chart dialog"
    # create OK button
    OKbtn_model = smgr.createInstance("com.sun.star.awt.UnoControlButtonModel")
    OKbtn_model.setPropertyValues(("DefaultButton", "PushButtonType"), (True, 1))
    OKbtn = smgr.createInstance("com.sun.star.awt.UnoControlButton")
    OKbtn.setModel(OKbtn_model)
    OKbtn.setPosSize(10, chart_height+2*10, 10*10, 3*10, 15)
    dlg.addControl("OKbtn", OKbtn)
    # create picto control
    picto_model = smgr.createInstance("com.sun.star.awt.UnoControlImageControlModel")
    picto_model.Graphic = chart_bitmap
    picto = smgr.createInstance("com.sun.star.awt.UnoControlImageControl")
    picto.setModel(picto_model)
    picto.setPosSize(10, 10, chart_width, chart_height, 15)
    dlg.addControl("picto", picto)
    # execute
    dlg.setVisible(True)
    dlg.execute()
    dlg.dispose() 
Regards.
Attachments
chartdialog.ods
LibreOffice only
(21.97 KiB) Downloaded 249 times
AOOo 4.1.2 on Win7 | LibreOffice on various Linux systems
JeJe
Volunteer
Posts: 2764
Joined: Wed Mar 09, 2016 2:40 pm

Re: [Python] Display Calc chart in dialog

Post by JeJe »

I got a runtime error on pushing the buttons - maybe that's because I don't use Python. But adapting the beginning of hubert lambert's code to Basic it works great... if anyone wants that...

Code: Select all

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

Sub Main
        doc = thiscomponent
        sheet = doc.Sheets(0)
        chart_bitmap = sheet.Charts(0).EmbeddedObject.DrawPage(0).Bitmap
        chart_width = chart_bitmap.Size.Width
       chart_height = chart_bitmap.Size.Height
		
		dlg = loaddialog("Standard","Dialog1")
		dlg.getcontrol("picto").setpossize 0,0,chart_width,chart_height,12
		dlg.getcontrol("picto").model.graphic = chart_bitmap 
		dlg.execute
end sub
        
Function LoadDialog(oLibraryName as String, oDialogName as String)
	Dim oLib as Object
	DialogLibraries.LoadLibrary(oLibraryName)
	oLib = DialogLibraries.GetByName(oLibraryname)
	LoadDialog() =  CreateUnoDialog(oLib.GetByName(oDialogName))
End Function



Windows 10, Openoffice 4.1.11, LibreOffice 7.4.0.3 (x64)
kiloran
Posts: 36
Joined: Sun Oct 14, 2012 2:06 pm

Re: [Solved][Python] Display Calc chart in dialog

Post by kiloran »

hubert lambert wrote:Hi,

Here's two examples, based on JeJe suggestion.
The first uses a dialog designed with the basic gui editor.
The second creates the dialog from scratch.
Regards.
That's brilliant, Hubert. Works perfectly on my Windows 10 and LibreOffice 6. Many many thanks.

And thanks to all for the other responses. I got rather sidetracked in recent weeks due to a failing SSD in my laptop. I had to replace it and then rebuild all my software. I think I'm now ready to get working on this again
--kiloran
LibreOffice 6 on Windows 10 and Linux Mint
Post Reply