[Solved] Referencing form controls from macro's

Creating and using forms
Post Reply
BrianSwatton
Posts: 6
Joined: Fri Feb 25, 2011 4:38 am

[Solved] Referencing form controls from macro's

Post by BrianSwatton »

I keep going round the help and faq's in circles here. I'm exploring using OOo Base. I've called a macro from a form and want to read a text box from it, that's all. Help keeps pointing me to using dialogs, which doesn't seem to mention addressing forms.

I've done lots of programming over 25 years, in lots of languages, I'm finding this incredibly frustrating.

:crazy:
Last edited by BrianSwatton on Sat Feb 26, 2011 12:44 am, edited 1 time in total.
OpenOffice 3.3.0 on Windows XP
FJCC
Moderator
Posts: 9273
Joined: Sat Nov 08, 2008 8:08 pm
Location: Colorado, USA

Re: Referencing form controls from macro's

Post by FJCC »

An essential tool for writing macros is an object inspection tool like mri. Then you can see the properties and methods of each object. Here is an example of a macro called by the After Record Change event of a form that gets the string showing in a text box.

Code: Select all

Sub ForumMacro(oEv)
oForm = oEv.Source
oTextBox = oForm.getByName("txtSAMPLE_GROUP")
TextBoxString = oTextBox.string
end Sub
OpenOffice 4.1 on Windows 10 and Linux Mint
If your question is answered, please go to your first post, select the Edit button, and add [Solved] to the beginning of the title.
User avatar
DACM
Volunteer
Posts: 1138
Joined: Tue Nov 03, 2009 7:24 am

Re: Referencing form controls from macro's

Post by DACM »

Does this help at all?
AOO 4.1.x; LO 4.2.x; Windows 7/8 64-bit
Warning: Avoid embedded databases --> Solution: Adopt a portable 'split database' folder
Soli Deo gloria
BrianSwatton
Posts: 6
Joined: Fri Feb 25, 2011 4:38 am

Re: Referencing form controls from macro's

Post by BrianSwatton »

Hi,

Thanks for answering both of you.

FJCC, I had found Event.Source by accident before, and found I could use that, but only to reference the textbox where the event happened, nothing else (the macro is called by the change event in a textbox).

So, if I use GetByName() with what is returned by Event.Source, as in your example, I get "property or method not found" error for GetByName. Presumably because it is being applied to a textbox and not a form.

DACM, Reading the link you posted, I was amazed I had not seen "Parent" before anywhere in the help, this looked like being the answer, but when I used lines like :

Sub CheckPN(oEv)
Frm=oEv.Parent
' or
Frm=oEv.Source.Parent

I get "no property or method found" for parent for either line.

I think part of my problem with gaining understanding is not yet finding a list of standard objects and the methods and properties they have, as well as heirarchies. I will see what else I can glean from the link you sent anyway.

I'm not sure how much more time I will spend on this, I'm quite busy. I was hoping I could get Basic to do some straightforward stuff with a simple parts database, but got stuck at the first fence. I've spent many, many hours trying to get some clue from the help in progam and online.

Thanks again
OpenOffice 3.3.0 on Windows XP
FJCC
Moderator
Posts: 9273
Joined: Sat Nov 08, 2008 8:08 pm
Location: Colorado, USA

Re: Referencing form controls from macro's

Post by FJCC »

I think part of my problem with gaining understanding is not yet finding a list of standard objects and the methods and properties they have, as well as heirarchies.
This is where the MRI tool can help you a lot. If the macro is being called from a text box you may have to get to the form with code like

Code: Select all

oForm = oEv.Source.Model.Parent
I'm working from memory and could easily be wrong, not having programmed much with forms. The point is, you need a quick way to explore the object you are working with. MRI and the similar XRay tool are the best ways to do this. There is no documentation that lists the methods and properties as clearly and easily as these tools.
OpenOffice 4.1 on Windows 10 and Linux Mint
If your question is answered, please go to your first post, select the Edit button, and add [Solved] to the beginning of the title.
BrianSwatton
Posts: 6
Joined: Fri Feb 25, 2011 4:38 am

Re: Referencing form controls from macro's

Post by BrianSwatton »

Ok I've just got MRI, and am now looking at it. By the looks of it, it may take me a little while to work out what is going on.

I can't help thinking this seems to be getting incredibly complicated for such a straightforward task. I thought maybe I was approaching it from the wrong angle.

I will persist though, and will mark this thread solved when it is.

Thanks
OpenOffice 3.3.0 on Windows XP
goodvibes
Posts: 22
Joined: Sun May 09, 2010 2:04 am

Re: Referencing form controls from macro's

Post by goodvibes »

Hi Brian,

You can use oEvent.Source to access the Control but you need to be aware that oEvent can point to different objects depending on what event it is and sometimes even code attached to the same event can have oEvent point to different oblects when the event is triggered from different controllers. MRI is very useful here.

You can usually use

Code: Select all

   oForm = ThisComponent.DrawPage.Forms.getByIndex(0)
to get the form object, unless you want to refer to a different form.
Or you can use

Code: Select all

    oForm = ThisComponent.DrawPage.Forms.GetByName("myFormName")
to refer to a hard coded form name.

Be aware that there are a couple of different 'form' objects and you need to specify the actual name of your form object.
By default the forms are called "MainForm". You can check by using the Form Navigator while in form design.
You can also rename "MainForm" using form navigator. (Right click).

Once you have the form object, you can use

Code: Select all

    oControl = oForm.GetByName("myControlName") to reference the Control object
and then

Code: Select all

   oControl.Text to reference the value of string controls
Or you can use

Code: Select all

    oForm.GetByName("myControlName").Text
to do it in 1 step.

Note that the .Text property doesn't apply to controls for all data types. Use MRI to find out what properties exist for your control.

For controls on subforms:

Code: Select all

   oForm = ThisComponent.DrawPage.Forms.getByIndex(0)
   oSubForm = oForm.GetByName("SubForm")        ' Assuming you haven't renamed your SubForm
   oTablemodel=oSubForm.getbyname("SubForm_Grid")    ' Assuming you haven't renamed your SubForm_Grid
   oControl = oTablemodel.GetByName("myControlName")
Open Office 3.3.0 RC10, Windows 7 (64bit)
BrianSwatton
Posts: 6
Joined: Fri Feb 25, 2011 4:38 am

Re: Referencing form controls from macro's

Post by BrianSwatton »

Thanks for all the help. I have solved the original issue by using "model" with "parent" which I hadn't seen before.

Sub CheckPN(Event)
CallObj=Event.Source
Frm=CallObj.Model.Parent

Once I had the form I was fine, able to access other objects with GetByName.

I guess I have a lot to find out about still. I have no idea what the "Model" means yet.

i've been playing with MRI and, while I was able to navigate through objects and methods, I never once understood what actual object I was looking at.
OpenOffice 3.3.0 on Windows XP
Arineckaig
Volunteer
Posts: 828
Joined: Fri Nov 30, 2007 10:58 am
Location: Scotland

Re: [Solved] Referencing form controls from macro's

Post by Arineckaig »

I have no idea what the "Model" means yet.
i've been playing with MRI and, while I was able to navigate through objects and methods, I never once understood what actual object I was looking at.
With the help of Hanya I developed for my own use a macro library to help the display by MRI of the properties and methods of form controls. It can be run from a form document in either edit or direct mode. When run it displays a form control tree similar to that used by the 'form navigator'. Double clicking the name of any form or form control in the list automatically runs an MRI scan on the 'model' of that object and on its 'view' if the object has one. It greatly simplifies the task of finding what properties or methods might be available. I store the library in 'My Macros' and call its 'Main' routine from an icon on the toolbar of the form document.

You use it at your own risk, but do please come back if you have any problems or find errors in its application. Though some routines at the end seem to be empty they must be included to avoid errors arising from the mouse and button event listeners.

Code: Select all

REM Control Tree Code
REM  *****  BASIC  *****
REM  I owe a debt of gratitude to Hanya for the Tree Control code as well as for the MRI extension.
REM  All the remaining errors and bugs, however, are entirely my responsibility. 
REM  The Main macro can be run from a Form Document open (in either edit or run mode).        
REM  Best called from an icon added to the standard toolbar saved in the OOoBase:Form design
REM  It displays a dialog similar to that of the Form Navigator. Double clicking any control on the
REM     list will run MRI on that control's model and where available on its view. A single click will 
REM     select a control from the list and MRI can then be run by selecting the MRI button. 
REM  Unless the auto  close check box has been selected, the dialog and Tree Control will remain
REM      open to permit MRI to be run on further controls. 
REM ****************************************************************************                                

Dim oDoc As Object
Dim oDocCtrl As Object
Dim oForms As Object
Dim oDialog As Object

Sub Main
  oDoc = ThisComponent
  oDocCtrl=oDoc.GetCurrentController()
  If oDoc.supportsService("com.sun.star.text.TextDocument") Then
   oForms = oDoc.getDrawPage().getForms()
  ElseIf oDoc.supportsService("com.sun.star.sheet.SpreadsheetDocument") Then
   ' Spreadsheet needs problem about active sheet changing
   oForms = oDoc.getCurrentController().getActiveSheet().getDrawPage().getForms()
  Else MsgBox("This is neither a Writer nor a Calc document - Macro will abort",0) : Exit Sub
  End If
  
  ' create dialog
  oDialog = CreateUnoService("com.sun.star.awt.UnoControlDialog")
  oDialogModel = CreateUnoService("com.sun.star.awt.UnoControlDialogModel")
  oDialogModel.setPropertyValues( _
    Array("Height", "PositionX", "PositionY", "Width","Title"), _
    Array(200, 50, 50, 130, "Double Click to run MRI") )
  oDialog.setModel(oDialogModel)
  
  ' AutoClose check box
  oCheckModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlCheckBoxModel")
  oCheckModel.setPropertyValues(_
    Array("Height", "Label", "PositionX", "PositionY", "State", "Width"), _
    Array(13, "Auto Close", 1, 187, 0, 40))
  oDialogModel.insertByName("AutoClose", oCheckModel)
  
  ' Close Button
  oCloseBtnModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlButtonModel")
  oCloseBtnModel.setPropertyValues(_
    Array("Height", "Label", "PositionX", "PositionY", "PushButtonType", "Width"), _
    Array(13, "~Close", 94, 187, com.sun.star.awt.PushButtonType.CANCEL, 35))
  oDialogModel.insertByName("CloseBtn", oCloseBtnModel)
  
  ' MRI Button
  oMRIBtnModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlButtonModel")
  oMRIBtnModel.setPropertyValues(_
    Array("Height", "Label", "PositionX", "PositionY", "PushButtonType", "Width"), _
    Array(13, "~MRI", 58, 187, com.sun.star.awt.PushButtonType.STANDARD, 35))
  oDialogModel.insertByName("MRIBtn", oMRIBtnModel)
  
  ' create tree control
  oTreeModel = oDialogModel.createInstance("com.sun.star.awt.tree.TreeControlModel")
  oTreeModel.setPropertyValues( _
    Array("Height", "PositionX", "PositionY", "SelectionType", "ShowsRootHandles", "Width"), _
    Array(186, 1, 1, com.sun.star.view.SelectionType.SINGLE, False, 128) )
  oDialogModel.insertByName("Tree", oTreeModel)
  oTree = oDialog.getControl("Tree")
  
  oTreeDataModel = CreateUnoService("com.sun.star.awt.tree.MutableTreeDataModel")

 ' make new tree model structure
  oTreeDataModel = CreateUnoService( _
    "com.sun.star.awt.tree.MutableTreeDataModel")
  ' top node
  oRootNode = oTreeDataModel.createNode("Forms", true)
  oRootNode.setCollapsedGraphicURL("private:graphicrepository/res/sx18013.png")
  oRootNode.setExpandedGraphicURL("private:graphicrepository/res/sx18013.png")
  
  ' set data to the root
  oTreeDataModel.setRoot(oRootNode)
  oTreeModel.DataModel = oTreeDataModel
  
  AddChildren(oForms, oTreeDataModel, oRootNode)
  oDialog.setVisible(True)
  
  oButtonListener = CreateUnoListener("ButtonPush_", "com.sun.star.awt.XActionListener")
  oMRIBtn = oDialog.getControl("MRIBtn").addActionListener(oButtonListener)
  
  oTree.expandNode(oRootNode) ' expand after dialog visible
  ExpandAllNodes(oTree, oRootNode)
  
  oMouseListener = CreateUnoListener("Mouse_", "com.sun.star.awt.XMouseListener")
  oTree.addMouseListener(oMouseListener)
  
  oDialog.execute()
  oTree.removeMouseListener(oMouseListener)
  CloseDialog()
End Sub

Sub CloseDialog()
  If oDialog.getControl("AutoClose").State = 1 Then 
    oDialog.endExecute()
  Endif
End Sub


Function GetFormControl(oForms As Object, oNode As Object) As Object
  Dim oControl As Object
  Dim sNames() As String
  While NOT IsNull(oNode)
   n = UBound(sNames) +1
   ReDim Preserve sNames(n)
   sNames(n) = CStr(oNode.getDisplayValue())
   oNode = oNode.getParent()
  WEND
  ' find control
  oControl = oForms
  For i = UBound(sNames) -1 to 0 step -1
   oControl = oControl.getByName(sNames(i))
  Next
  GetFormControl = oControl
End Function

Sub SelectControl(oForms As Object, oNode As Object) As Object
  oControl = GetFormControl(oForms, oNode)
  If IsNull(oControl) Then Exit Sub
  oDoc.getCurrentController().select(oControl)
End Sub

Sub OpenWithMRI(oForms As Object, oControl As Object)
  oControl = GetFormControl(oForms, oControl)
  If IsNull(oControl) Then Exit Sub
  Globalscope.BasicLibraries.loadLibrary("MRILib")
  MRILib.Mri(oControl)
 REM Views not available for Columns in Grid Control, Hidden Controls, Forms or Sub-Forms 
  if oControl.Parent.ImplementationName = "com.sun.star.comp.forms.OGridControlModel" Then Exit Sub
  If oControl.ImplementationName = "com.sun.star.comp.forms.ODatabaseForm" OR _
          oControl.ImplementationName = "com.sun.star.comp.forms.OFormsCollection" OR _
          oControl.ImplementationName = "com.sun.star.comp.forms.OHiddenModel" then Exit Sub               
REM Document's Controller and Form Control's Model gives Form Control's View
 oView = oDocCtrl.GetControl(oControl)                   
 If NOT ISNULL(oView) then MRI oView                       
End Sub

Sub Mouse_mousePressed(oEv As com.sun.star.awt.MouseEvent)
  If oEv.Buttons = com.sun.star.awt.MouseButton.RIGHT Then
    oTree = oEv.Source.getContext().getControl("Tree")
    oNearNode = oTree.getClosestNodeForLocation(oEv.X,oEv.Y)
    If IsNull(oNearNode) Then Exit Sub
   
    aRect = CreateUnoStruct("com.sun.star.awt.Rectangle")
    aRect.X = oEv.X + oTree.PosSize.X
    aRect.Y = oEv.Y + oTree.PosSize.Y
   
    oPopup = CreateUnoService("stardiv.vcl.PopupMenu")'"com.sun.star.awt.PopupMenu")
   
    oPopup.insertItem(1, "Select", 0, 0)
    oPopup.insertItem(2, "MRI", 0, 1)
    oPopup.setCommand(1, "select")
    oPopup.setCommand(2, "mri")
   
    n = oPopup.execute(oTree.getContext().getPeer(), aRect, _
    com.sun.star.awt.PopupMenuDirection.EXECUTE_DEFAULT)
    If n > 0 Then
      sCommand = oPopup.getCommand(n)
      Select Case sCommand
      Case "select"
        SelectControl(oForms, oNearNode)
      Case "mri"
        OpenWithMRI(oForms, oNearNode)
      End Select
      CloseDialog()
    End If
  End If
End Sub


Sub Mouse_mouseReleased(oEv)
  If oEv.Buttons = com.sun.star.awt.MouseButton.LEFT and oEv.ClickCount = 2 Then
    oTree = oEv.Source.getContext().getControl("Tree")
    oNearNode = oTree.getClosestNodeForLocation(oEv.X,oEv.Y)
    If IsNull(oNearNode) Then Exit Sub
    OpenWithMRI(oForms, oNearNode)
    CloseDialog
  End If
End Sub

Sub ButtonPush_actionPerformed(oEv As com.sun.star.awt.ActionEvent)
  ' get selected item
  Dim oSelected() As Object
  oTree = oEv.Source.getContext().getControl("Tree")
  oSelected = oTree.getSelection()
  If IsArray(oSelected) Then
    Exit Sub
  Else
    OpenWithMRI(oForms, oSelected(0))
    CloseDialog
  End If
End Sub


Sub AddChildren( oContainer As Object, oDataModel As Object, oParent As Object )
  For i = 0 To oContainer.getCount() - 1 step 1
    oModel = oContainer.getByIndex(i)
    sName = oModel.getName()
    sImageURL = GetImageURL(oModel.getServiceName())
    
    If HasUnoInterfaces(oModel, _
       "com.sun.star.container.XContainer") Then
      oChild = oDataModel.createNode(sName, true)
      AddChildren(oContainer.getByName(sName), oDataModel, oChild)
    Else
      oChild = oDataModel.createNode(sName, false)
    End If

    oChild.setExpandedGraphicURL(sImageURL)
    oChild.setCollapsedGraphicURL(sImageURL)
    oParent.appendChild(oChild)
  Next
End Sub

Sub ExpandAllNodes(oTree As Object, oParent)
  For i = 0 To oParent.getChildCount() - 1 step 1
   oChild = oParent.getChildAt(i)
   oTree.expandNode(oChild)
   If oChild.getChildCount() > 0 Then
     ExpandAllNodes(oTree, oChild)
   End If
  Next
End Sub

Function GetImageURL(sServiceName As String) As String
  Dim sName As String
  sControlService = Mid(sServiceName, 28) 'stardiv.one.form.component.Form
  
  sServices = Array(_
   "CheckBox", "ComboBox", "CommandButton", _
   "CurrencyField", "DateField", "Edit", "FileControl", _
   "FixedText", "Form", "FormattedField", _
   "Grid", "GroupBox", "HiddenControl", _
   "ImageButton", "ImageControl", "ListBox", _
   "NumericField", "PatternField", "RadioButton", _
   "TextField", "TimeField", _
   ".NavigationToolBar", ".SpinButton", ".ScrollBar")

  sNames = Array(_
   "sx10596", "sx10601", "sx10594", _
   "sx10707", "sx10704", "sx10599", "sx10605", _
   "sx10597", "sx10593", "sx10728", _
   "sx10603", "sx10598", "sx18022", _
   "sx10604", "sx10710", "sx10600", _
   "sx10706", "sx10708", "sx10595", _
   "sx10599", "sx10705", _
   "sx10607", "sx10769", "sx10768")
  
  For i = 0 To UBound(sServices) step 1
    If sServices(i) = sControlService Then
      sName = sNames(i)
      Exit For
    End If
  Next
  GetImageURL = "private:graphicrepository/res/" & sName & ".png"
End Function

Sub Mouse_mouseEntered(ev)
End Sub
Sub Mouse_mouseExited(ev)
End Sub
Sub Mouse_disposing(ev)
End Sub

Sub ButtonPush_dispose(oEv)
End Sub
When this issue has been resolved, it would help other users of the forum if you add the word - [Solved] - to the Subject line of your 1st post (edit button top right).
AOOo 4.1.5 & LO 6 on MS Windows 10 MySQL and HSQLDB
BrianSwatton
Posts: 6
Joined: Fri Feb 25, 2011 4:38 am

Re: [Solved] Referencing form controls from macro's

Post by BrianSwatton »

That's a big help thanks, I've just run it up and can at least know what I'm looking at now :super:
OpenOffice 3.3.0 on Windows XP
Post Reply