Change Visio Shape Color

Started by AdequateProgrammer, January 24, 2020, 02:50:36 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

AdequateProgrammer

Good morning,

I'm having issues changing the foreground color of shapes.  I found code to successfully change a shape's color:

shape.Cells("FillForegnd").Formula = "RGB(255,255,0)"

(As a side note, I cannot find any documentation of what properties you can access via the string notation in the Cells() call.  If anyone can point me to what is available to modify, background color, foreground color, line color, etc.  That would also be extremely helpful.  I've only found out these properties from forums, and not a document list on msdn.)

On a page in my Visio drawing, I make 4 calls:

        Visio.ActivePage.Duplicate
        Call PopulateData
        Call DeleteEmptyShapes
        Call ColorShapes

I duplicate the current page, and on the new page I add values to my shapes, delete the empty ones, change the line color of the existing ones and alter the foreground color of the existing ones.  The code I specified above works in changing the foreground color, BUT only if I run the ColorShapes method on it's own on a page that has existing shapes.  The code DOES NOT run if I duplicate the page and run my three method calls and it DOES NOT run if I call the PopulateData, DeleteEmptyShpes, and Color Shapes on its own page of existing shape.  These two methods that don't alter the color of my shapes do simple looping through all shapes on the Active Page to set values.  For example:

            For k = lowBound To upperBound
                excelDataRow = excelDataRecordSet.GetRowData(k)
                'Match it to the correct shape.
                For Each shape In Visio.ActivePage.Shapes
                    If shape.CellExists("Prop.Row_0", 0) <> 0 Then
                            shape.Cells("Prop.Row_1.Value").Formula = excelDataRow(1)
                            Exit For
                    End If
                Next shape
            Next

My ColorShapes method is extremely similar in the looping, and has one simple check before setting the color:

    For Each shape In Visio.ActivePage.Shapes
        If shape.CellExists("Prop.Row_1", 0) <> 0 Then
            status = shape.Cells("Prop.Status.Value").Formula
            If Not status Then
                shape.Cells("FillForegnd").Formula = "RGB(255,255,0)"
            Else
                shape.Cells("FillForegnd").Formula = "RGB(0,0,255)"
            End If
        End If
    Next shape

Like I said, the code works for a page with existing shapes and only calling the ColorShapes method.  Something is happening in the background that I'm not seeing.  Does anyone have any recommendations?  Or has anyone ever seen this issue before?

Thanks,

vojo

maybe need make sure the duplicate (or correct page) is the active page. 
Maybe the duplicate task, name the duplicate page as something else...
Then use the name as confirmation you are on the right page

At least in Excel VBA you can pick a different page from active (by name or by number).
Maybe you can do something like that here

I don't do much with Visio VBA (managing security settings can subvert security policies).

AdequateProgrammer

I am on the correct page because I can alter every shape's line color, delete empty shapes and set the properties on the shapes.  I see the properties of the shapes I'm altering and they are all correct.  Even if I was on the wrong page (whether it be the original or the duplicate), the foreground color is not set on either set of shapes.

wapperdude

#3
The main issue is the IF NOT statement.  That construct doesn't work.  Depending upon the what you want, try Status = False (or True).

The 2nd issue is the Status = statement.  The .Value isn't necessary.  The value cell is the default.  Then, the .Formula fetches the formula, not the value.  Better form is .Result(visBoolean)

The following code works fine:

    For Each Shape In Visio.ActivePage.Shapes
        If Shape.CellExists("Prop.Row_1", 0) <> 0 Then
            Status = Shape.Cells("Prop.Status").Result(visBoolean)
            If Status = False Then
                Shape.Cells("FillForegnd").Formula = "RGB(255,255,0)"
            Else
                Shape.Cells("FillForegnd").Formula = "RGB(0,0,255)"
            End If
        End If
    Next Shapes


Better yet, just use If Status Then, and swap the two FillForegnd conditions.
Visio 2019 Pro

AdequateProgrammer

Thank you for the reply.  A few things...

    1. )  The code I'm actually running is if my value is false, set the color to red.  I constructed the If Then Else only to make sure I hit a color setting property regardless. 
    2. )  I didn't know that the result contained the value, so that was extremely helpful!
    3. )  This still did not set the color of my shapes when I run all of my methods in a row.  If I run only the ColorShapes method, then it does change their color.   

So it seems that I am back in the same spot that I was in.  The code to change the color of the shapes is there and is correct, but it won't change the shape colors when run with all of my other code.

wapperdude

My suggestion would be to have two Windows, side by side.  Make one window the drawing page and the other the VBA page to display your code.  So, as you step thru the code, you can watch how it affects the drawing.

Next, I suggest a that you create a simple drawing to make debug easier. 

Now, in the code window mouse click once, anywhere within the macro.  Sets the focus,  now use the <f8> key to step thru code, line by line.  You can see what the code is actually doing and if that's what you expected. 

Additionally, you can temporarily add debug.print something as a check.  Also, after a line completes, you can hover mouse over a variable to see its current value.

There is no inherent reason the cliffhanger shouldn't work.  So, something must be amiss in the code.

BOTH.
Visio 2019 Pro

AdequateProgrammer

I did a side by side view before and stepped through and witnessed the property change.  The "FillForegnd" color before altering the color is: "THEMEGUARD(TINT(THEME("AccentColor5"),48))".  I step into my If Then Else condition and it successfully sets the "FillForegnd" property to "RGB(0,0,255)".  In the view, however, the shapes do not have their colors altered. Even before posting in the forum, I attempted to alter the property of simply one shape on the drawing with all of the same shape data as what I am altering, and it still does not alter the foreground color of the shape.

From msdn:

https://docs.microsoft.com/en-us/office/client-developer/visio/themeguard-function

You can override the formula's themeguard programmatically, as long as the the property "SETATREFEXPR" is not within the formula (which it isn't).  This isn't an issue with the code being correct syntactically or accessing incorrect properties of the shapes, because if I create a new button on the newly duplicated sheet and run the exact code above (that you altered or my original code), it changes the shape colors.

AdequateProgrammer

I made an example with a new rectangle shape and one of my shapes and compared the properties 1:1.  I noticed that the Fill Style on my shape was set to "Net Normal" and the rectangle was set to "Normal".  Changing that property allowed me to change the shape color of my shapes.

I found the property in the msdn documentation here:

https://docs.microsoft.com/en-us/office/vba/api/visio.shape.fillstyle

Do you know where the list of values you can supply the FillStyle method is stored?  The VBA documentation seems hard to sift through sometimes.

Thanks.

Paul Herber

The shape may be a group where the color is part of a sub-shape within the group. Open the Drawing Explorer window from the Developer tab, find the shape and expand it to see if there are sub-shapes.
Electronic and Electrical engineering, business and software stencils for Visio -

https://www.paulherber.co.uk/