2

VBA is not my particular strength, but here we go:

I would like to trigger a macro once a group of columns is hidden or shown. How can I archive this?


The results of my previous research

The only good hint about this I could find is this discussion at MSDN. Here, a solution is using the following way is drafted:

From the root dir of the xlsx file create a file customUI\customUI.xml with the content

<customUI  xmlns="http://schemas.microsoft.com/office/2006/01/customui" >
    <commands >
        <command 
            idMso="ColumnsHide"
            onAction="ColumnHide_onAction"/>
        <command 
            idMso="ColumnsUnhide"
            onAction="ColumnUnhide_onAction"/>
    </commands >
</customUI >

and add

<Relationship Id="edTAB" Type="http://schemas.microsoft.com/office/2006/relationships/ui/extensibility" Target="customUI/customUI.xml" />

to the _rels\_rels.xml. (All this probably is much easier using Visual Studio, but I have no access to such sophisticated tools in the microsoft world...) Now, the macro can be used the following way:

Public Sub ColumnHide_onAction(control As IRibbonControl, ByRef cancelDefault)
'
' Code for onAction callback. Ribbon control command
'
    MsgBox "Ribbon Column Hide"
    cancelDefault = False

End Sub
Public Sub ColumnUnhide_onAction(control As IRibbonControl, ByRef cancelDefault)
'
' Code for onAction callback. Ribbon control command
'
    MsgBox "Ribbon Column Unhide"
    cancelDefault = False
End Sub

This approach perfectly catches hiding and unhiding of columns, but not hiding and unhiding of groups. So, close, but not quite there.

Downloading the possible idMso values from here, I got notice of the GroupViewShowHide control. Using this the same way as ColumnsHide or ColumnsUnhide does not archive the desired result, though.

Any ideas?

Community
  • 1
  • 1
Thilo
  • 8,827
  • 2
  • 35
  • 56

1 Answers1

0

For hiding groups of columns, I've noticed you haven't used the .Hidden property in your code example. It can be quite useful, especially if you define a group of columns in an array. For example:
For byti = 0 To UBound(cols())
If Hide Then
ActiveSheet.columns(cols(byti)).EntireColumn.Hidden = True
...and so on.


To check if a group of columns is already hidden or not, you could also use an array. Group your columns by assigning them to an array, then compare your worksheet's current status (what columns are hidden, what are not) to that array.

The code below is a suggestion for starting, and you could adapt to your project. It doesn't require the customUI.xml file you mentioned in your question.

The key parts are the MyColumnCheck variant, which is used to check if columns are hidden, and the .Match method. This is the VBA equivalent of the Match spreadsheet function.

Working on this code taught me much about how to search within arrays, and the ups and downs of using Match versus other methods - such as Find and just looping through an array! This has been discussed in several posts already, see this one for a good example. I chose to do Match rather than a For...Next loop, although it would be easy to include a For..Next loop that checks if a hidden column is in a group you assign.

If you're wondering about the IfError statement:
Application.IfError(Application.Match(MyColumnCheck.Column, MyColumnArray, 0),... ... this is because using Match in VBA code is often somewhat tricky as mentioned here. Also, as @Lori_m wrote here, "Using Application without .WorksheetFunction returns a variant which allows for arrays in arguments and results."

Also, I chose to change the values of the group array to -1 as they were checked, so when the procedure was done a little simple math would reveal if all the columns referenced by the array were hidden. A negative number is better for this check because I'm assuming you would refer to an actual column with only positive numbers.


So, to sum up, .Match can be used effectively to check if the hidden columns on a worksheet match a group of columns defined by an array.

'the column group you're looking for, dim as a dynamic array of column numbers
Dim MyColumnArray(1) As Long
'MyColumnArray(0) is column 2 or "B", MyColumnArray(1) is column 3 or "C", etc
MyColumnArray(0) = 2
MyColumnArray(1) = 3
Dim MyColumnCheck As Variant 'column check

For Each MyColumnCheck In Worksheets("Sheet1").columns
  'if the column is hidden and exists in MyColumnArray array...
  If columns(MyColumnCheck.Column).EntireColumn.Hidden = True And _
  Application.IfError(Application.Match(MyColumnCheck.Column, MyColumnArray, 0), 0) > 0 _
  Then
    MyColumnArray(Application.Match(MyColumnCheck.Column, MyColumnArray, 0) - 1) = -1
    '... set that element of the MyColumnArray array to -1.
  End If
Next

If WorksheetFunction.Sum(MyColumnArray) = 0 - (UBound(MyColumnArray) + 1) Then
  Debug.Print "group MyColumnArray is hidden"
  'execute code here for when the group is hidden
Else
  Debug.Print "group MyColumnArray is visible"
  'execute code here for when the group is visible
End If
Community
  • 1
  • 1
Aaron Thomas
  • 5,054
  • 8
  • 43
  • 89