BIM Coordinator Program (INT) April 22, 2024

Find the next step in your career as a Graphisoft Certified BIM Coordinator!

Archicad C++ API
About Archicad add-on development using the C++ API.
SOLVED!

Change a parameter value in memo

Anonymous
Not applicable
Hi !

I'm still quite new to this but i'm making progress
I need your help to change the value of a parameter in an element's memo.
i want this to work on an external library's object, that is selected in Archicad.
I'm able to get the selected items, iterate on them, list the parameters in the memo of each object but don't know how to change them.
I guess i have to use ACAPI_​Element_​Change ??

GSErrCode  ACAPI_Element_Change (
        API_Element*               element,
        const API_Element*         mask,
        const API_ElementMemo*     memo,
        UInt64                     memoMask,
        bool                       withdel
    );
so that's what i'm doing:

ACAPI_ELEMENT_MASK_CLEAR()
ACAPI_ELEMENT_MASK_SET(mask, API_ObjectType, ???); //don't know what to put here
changeErr = ACAPI_Element_Change(&element, objectmask;
changeErr = ACAPI_Element_Change(&element, ??, &memo,  ??, false); //don't know what masks to put
help
1 ACCEPTED SOLUTION

Accepted Solutions
Solution
Ralph Wessel
Mentor
Yes, you use ACAPI_Element_Change to write the change. The easiest option for the element mask is just to change everything using ACAPI_ELEMENT_MASK_SETFULL, and the memo mask for changing parameters is APIMemoMask_AddPars:
API_Element mask;
ACAPI_ELEMENT_MASK_SETFULL(mask);
ACAPI_Element_Change(elemData, &mask, elemMemo, APIMemoMask_AddPars, true)
The easiest way to change parameter values is APIAny_ChangeAParameterID.
Ralph Wessel BArch

View solution in original post

7 REPLIES 7
Solution
Ralph Wessel
Mentor
Yes, you use ACAPI_Element_Change to write the change. The easiest option for the element mask is just to change everything using ACAPI_ELEMENT_MASK_SETFULL, and the memo mask for changing parameters is APIMemoMask_AddPars:
API_Element mask;
ACAPI_ELEMENT_MASK_SETFULL(mask);
ACAPI_Element_Change(elemData, &mask, elemMemo, APIMemoMask_AddPars, true)
The easiest way to change parameter values is APIAny_ChangeAParameterID.
Ralph Wessel BArch
Anonymous
Not applicable
Thanks Ralph,
I'll look into it tomorrow at work and keep you posted
Anonymous
Not applicable
Grrr Something is still wrong...

void ManageSelection(void) {
	API_Element			element, mask;
	API_ElementMemo		memo;
	GSErrCode			err, changeErr;
	
	API_SelectionInfo selectionInfo;
	API_Neig **selNeigs;
	int    ii, nSel, j, nbParams;
	API_AddParType param;
	// Get selected elements (which are all objects from a custom library)
	err = ACAPI_Selection_Get(&selectionInfo, &selNeigs, false); 
	if (err == NoError){
		if (selectionInfo.typeID != API_SelEmpty){
			nSel = BMGetHandleSize((GSHandle)selNeigs) / sizeof(API_Neig);
			API_ParamOwnerType   paramOwner;
			API_ChangeParamType  chgParam;
			API_GetParamsType    getParams;
			for (ii = 0; ii < nSel && err == NoError; ii++) { //iterating on the selection
				BNZeroMemory(&element, sizeof(element));
				//insert guid in header
				element.header.guid = (*selNeigs[ii]).guid;
				//get the element
				if (ACAPI_Element_Get(&element) == NoError)
					DBPrintf("\n\n GET_ELEMENT OK\n\n");
				else
					DBPrintf("\n\n GET_ELEMENT NOK\n\n");

				if (element.header.hasMemo) {
					BNZeroMemory(&memo, sizeof(memo));
					err = ACAPI_Element_GetMemo(element.header.guid, &memo, APIMemoMask_AddPars);
					if (err == NoError)
						DBPrintf("\n\n GETMEMO OK\n\n");
					else
						ErrorBeep("ACAPI_Element_GetMemo", err);
				}
				//change value of attribute N_panneau of each item in selection
                                // start by filling the param owner
				BNZeroMemory(&paramOwner, sizeof(API_ParamOwnerType));
				paramOwner.libInd = 0;                              //this should be 0 because it's not a library part, it's a placed element
				paramOwner.typeID = API_ObjectID;      // object element
				paramOwner.guid = (*selNeigs[ii]).guid; // placed element guid 
				BNZeroMemory(&getParams, sizeof(API_GetParamsType));
                                
                                // Open a Library Part parameter list to edit
				err = ACAPI_Goodies(APIAny_OpenParametersID, &paramOwner, nullptr);
				if (err == NoError) {
					DBPrintf("\n\n APIAny_OpenParametersID OK");
					BNZeroMemory(&chgParam, sizeof(API_ChangeParamType));
                                        
                                        // Returns the actual (edited) values of a Library Part parameter list opened to edit.
					err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
					if (err == NoError) {
						DBPrintf("\n\n APIAny_GetActParametersID OK");
						CHCopyC("N_panneau", chgParam.name);  //N_panneau is the parameter's name
						chgParam.realValue = 13.0;   //setting the value to 13 instead of 11
                                                // Changes a value in an opened Library Part parameter list
						err = ACAPI_Goodies(APIAny_ChangeAParameterID, &chgParam, nullptr);
						if (err == NoError) {
							DBPrintf("\n\nAPIAny_ChangeAParameterID OK");
							err = ACAPI_Goodies(APIAny_GetActParametersID, &getParams, nullptr);
						}
						else
							DBPrintf("\n\n APIAny_ChangeAParameterID NOK\n\n");
					}
                                        else
                                                DBPrintf("\n\n APIAny_GetActParametersID NOK");
					err = ACAPI_Goodies(APIAny_CloseParametersID, nullptr, nullptr);
					if (err == NoError) {
						DBPrintf("\n\n APIAny_CloseParametersID OK");
						element.header.typeID = API_ObjectID;
						ACAPI_ELEMENT_MASK_CLEAR(mask);
						ACAPI_ELEMENT_MASK_SETFULL(mask);
						memo.params = getParams.params;
						err = ACAPI_Element_Change(&element, &mask, &memo, APIMemoMask_AddPars, true); 
                                               //the error is here, the error check prints  ACAPI_Element_Change NOK
						if (err == NoError)
							DBPrintf("\n\n ACAPI_Element_Change OK");
						else
							DBPrintf("\n\n ACAPI_Element_Change NOK %d", err);
					}
					else
						DBPrintf("\n\n APIAny_CloseParametersID NOK");
						
				}
				else
					DBPrintf("\n\n APIAny_OpenParametersID NOK\n\n");

			}
			BMKillHandle((GSHandle *)&selNeigs);
		}
		else {
			DBPrintf("\n\n SELECTION_EMPTY \n\n");
		} 
	}
}
basically i'm selecting elements in archicad then running this function
the output i'm getting is:
GET_ELEMENT OK
GETMEMO OK
APIAny_OpenParametersID OK
APIAny_GetActParametersID OK
APIAny_ChangeAParameterID OK
APIAny_CloseParametersID OK
ACAPI_Element_Change NOK ,APIERR_NEEDSUNDOSCOPE

this is the attribute i want to change: (it's called "Numero de panneau" here but the actual name is "N_panneau") First of all am I doing this right ?
and does this really need an undo scope ?
because I haven't seen it used in the example for APIAny_OpenParametersID here: link
and if so what would it look like ?
because this:

    GSErrCode err = ACAPI_CallUndoableCommand ("Create text",
        [&] () -> GSErrCode {
            return ACAPI_Element_Create (&element, &memo);
        });

    if (err != NoError)
        ErrorBeep ("ACAPI_Element_Create (text)", err);

    ACAPI_DisposeElemMemoHdls (&memo);
is beyond my comprehension
Thank you for your precious help
Ralph Wessel
Mentor
Yes, this method has to be called within an undo session. Refer to ACAPI_CallUndoableCommand. The same applies to any function that changes an element.
Ralph Wessel BArch
Anonymous
Not applicable
The whole office heard my shout of joy because this finally worked !
THANK YOU !
Tibor Lorantfy
Graphisoft Alumni
Graphisoft Alumni
wacim wrote:
First of all am I doing this right ?
Yes, at first sight it looks correct.
wacim wrote:
and does this really need an undo scope ?
Yes, as Ralph said, all operations which do some kind of element database modification can be executed only from an UndoableCommand.
wacim wrote:
because I haven't seen it used in the example for APIAny_OpenParametersID here: link
That example calls ACAPI_Element_ChangeDefaults function and you call ACAPI_Element_Change. That's the main difference which explains why you need an undo scope.
wacim wrote:
and if so what would it look like ?
because this is beyond my comprehension
Thank you for your precious help
Don't be shocked, it's just a little lambda expression (available since C++11)
You just have to change one line: Instead of calling your ManageSelection function directly, call it this way:
ACAPI_CallUndoableCommand ("Manage Selection",
	[&] () -> GSErrCode {
		ManageSelection ();

		return NoError;
	});
Anonymous
Not applicable
Thank you Tibor for your explanations
as for the " lambda expression" now i know how it's called so i can google it and see how it works...
what i did is i searched in all examples folder for use cases of "ACAPI_CallUndoableCommand" and tried to do something similar, which worked but now i'll actually be able to understand
Learn and get certified!