Лента Excel: отключить все настраиваемые вкладки, если лист защищен

Если лист защищен, большинство встроенных кнопок неактивны.

Как это сделать с помощью специальной ленты?

Как вы скажете: если лист защищен, отключите все настраиваемые вкладки/все кнопки на настраиваемых вкладках и включите их снова, если лист не защищен?

XML-фреймворк, стандартный модуль, ThisWorkbook:

' -- XML

<customUI xmlns = "http://schemas.microsoft.com/office/2009/07/customui"
 onLoad = "LoadRibbon">
  <ribbon>
    <tabs>
      <tab id = "Tabv3.1" label = "TOOLS" insertAfterMso = "TabHome">                  
       ' groups/buttons 
      </tab>
    </tabs>
  </ribbon>
</customUI>


' -- Standard Module

Option Explicit
Public RibUI As IRibbonUI

Sub LoadRibbon(Ribbon As IRibbonUI)
Set RibUI = Ribbon
    RibUI.InvalidateControl "xy"
End Sub

' =========
' Callbacks
' =========


' -- ThisWorkbook

Private Sub Workbook_SheetActivate(ByVal Sh As Object)
    RibUI.InvalidateControl "xy"
End Sub

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
    RibUI.InvalidateControl "xy"
End Sub

Лента Framework с двумя вкладками: «Инструменты» и «Макросы»:

<customUI xmlns = "http://schemas.microsoft.com/office/2009/07/customui" 
 onLoad = "LoadRibbon">   
  <ribbon>  
    <tabs>  
      <tab id = "ToolsV1.0.0" label = "Tools" insertAfterMso = "Developer">   
       ' built-in controls + a couple of macro buttons
      </tab>
      <tab id = "MacrosV4.0.0" label = "Macros" insertAfterMso = "ToolsV1.0.0">
       ' macro buttons      
      </tab>               
    </tabs> 
  </ribbon> 
</customUI> 

Теоретически это можно сделать, но это зависит от некоторых проблем: 1. Является ли книга, содержащая приведенный выше код (и XML для создания пользовательской вкладки ленты), надстройкой? Если нет, хотите ли вы, чтобы описанное выше поведение было только для соответствующей книги или нет? Во всех случаях решение будет разным. 2. Почему вы спрашиваете о «всех пользовательских вкладках», если в XML вы показываете, что создается только вкладка («ИНСТРУМЕНТЫ»)? Существуют ли другие вкладки, созданные другими книгами/надстройками? Даже в таком случае это можно было бы сделать, но решение было бы гораздо сложнее.

FaneDuru 16.05.2024 08:49

Да, в книге есть XML-файл с onLoad для создания ленты, это не надстройка. Приведенный выше код является лишь примером. На настоящей ленте есть две настраиваемые вкладки. 1. «Инструменты»: в основном встроенные элементы управления плюс несколько кнопок макросов. 2. «Макросы»: кнопки макросов. Если возможно, я хотел бы иметь описанное поведение для любой книги, содержащей ленту.

user23636411 16.05.2024 15:33
Преобразование HTML-таблицы в профессиональный документ Excel
Преобразование HTML-таблицы в профессиональный документ Excel
Это самый простой способ создания Excel из HTML-таблицы.
Импорт excel в laravel в базу данных
Импорт excel в laravel в базу данных
Здравствуйте, дорогой читатель, в этой статье я расскажу практическим и быстрым способом, как импортировать файл Excel в вашу базу данных с помощью...
0
2
105
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

По сути, необходимо добавить getEnabled к элементам управления, которые вы хотите условно включить или отключить (в XML), а затем Invalidate соответствующие элементы управления. Я попробую показать небольшой такой пример:

  1. Предлагаемое решение ссылается на следующий XML-код, вставляя две вкладки, каждая из которых содержит элемент управления. После редактирования я добавил <commands> для стандартного "SheetProtect"idMso, перехватив его событие OnAction:
<?xml version = "1.0" encoding = "UTF-8" standalone = "yes"?>
<customUI onLoad = "RibbonLoaded_Addin" xmlns = "http://schemas.microsoft.com/office/2009/07/customui"> 
  <commands>
      <command idMso = "SheetProtect" onAction = "mySheetProtect" />
  </commands>
  <ribbon> 
    <tabs> 
      <tab id = "ToolsV1.0.0" label = "TOOLS"  insertAfterMso = "Developer"> 
        <group id = "GroupDemo" label = "Test group1"> 
           <dropDown id = "TestDrD"  
                    label = "Test dropDown:"
                    getEnabled = "Test_getEnabled"/>
                     
        </group>        
    </tab>
    <tab id = "MacrosV4.0.0" label = "Macros" insertAfterMso = "ToolsV1.0.0">  
        <group id = "GroupDemo2" label = "Test group2"        
            imageMso = "AddInManager">    
             <checkBox id = "myCheckbox" 
                     getEnabled = "Chk_getEnabled" /> 
        </group>       
      </tab> 
    </tabs> 
  </ribbon> 
</customUI> 
  1. В стандартный модуль необходимо добавить следующие объявления (поверх него, в области объявлений) и функции API. Функции API (не обязательные) являются бонусом для обновления объекта MyRibbon в случае его потери (в случае ошибок VBA):
Option Explicit

'To memorize the Ribbon object! ___________
#If VBA7 Then
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal length As LongPtr)
#Else
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
#End If
'_________________________________________


Public myRibbon As IRibbonUI
Const strRib As String = "\MyRibbX" 'where to save the pointer...

Public boolEnableChk As Boolean, boolDrD As Boolean 'to Disable/Enable

Скопируйте также следующие процедуры в этот стандартный модуль: а. Для запуска на загруженной ленте (запомните указатель ленты и изначально установите необходимые элементы управления как «Включено»):

Sub RibbonLoaded_Addin(ribbon As IRibbonUI)
    Dim Path As String: Path = Environ("temp") & strRib
    Dim File As Integer: File = FreeFile
    Open Path For Output As #File
        Print #File, ObjPtr(ribbon) 'memorize IRibbonUI pointer
    Close #File

   Set myRibbon = ribbon
   
   boolEnableChk = True: boolDrD = True 'to initialy enable controls
   myRibbon.InvalidateControl "myCheckbox" 'to update it
   myRibbon.InvalidateControl "TestDrD"
End Sub

б. Субмарина способна восстановить потерянный объект «Лента»:

Sub getRibbon() 'reSet myRibbon if it was lost (it's Nothing):
    Dim Path As String: Path = Environ("temp") & strRib
    Dim File As Integer: File = FreeFile
    Dim ribValue As String
    
    If myRibbon Is Nothing Then
        Open Path For Input As #File
            Input #File, ribValue
        Close #File
        
        #If VBA7 Then
            CopyMemory myRibbon, CLngPtr(ribValue), 8 'place in memory IRibbonUI object from its memorized pointer '64 bit
        #Else
            CopyMemory myRibbon, CLng(ribValue), 4    'place in memory IRibbonUI object from its memorized pointer
        #End If
    End If
End Sub

в. Два необходимых getEnabled события:

Sub Chk_getEnabled(control As IRibbonControl, ByRef enabled)
  enabled = boolEnableChk
End Sub

Sub Test_getEnabled(control As IRibbonControl, ByRef enabled)
  enabled = boolDrD
End Sub

д. Два (единственных) тестовых сабвуфера, чтобы увидеть, как элементы управления на ленте поочередно изменяются при игре с ними?

Sub testMakeEn_Dis_ChkBox() 'pressing alternatively it will enable/disable the check box
  boolEnableChk = Not boolEnableChk
  
  If myRibbon Is Nothing Then getRibbon
  myRibbon.InvalidateControl ("myCheckbox")
End Sub

Sub testMakeEn_Dis_DropD() 'pressing alternatively it will enable/disable the DropDown
  boolDrD = Not boolDrD
  
  If myRibbon Is Nothing Then getRibbon
  myRibbon.InvalidateControl ("TestDrD")
End Sub

е. И следующий Sub, способный заменить вышеупомянутые тестовые, имеющий параметры для определения имени элемента управления: Enabled\Disabled:

Sub Invalidate_Control(controlName As String) 'to be used externaly
  If myRibbon Is Nothing Then getRibbon
  myRibbon.InvalidateControl controlName
End Sub
  1. Пожалуйста, скопируйте следующий код в модуль кода ThisWorkbook. Workbook_SheetActivate событие запускается, когда вы активируете разные листы и в соответствии с его оценкой, связанной с защитой, включает или отключает необходимые элементы управления:
Option Explicit

Private Sub Workbook_SheetActivate(ByVal sh As Object)
  If sh.ProtectContents Then
    boolEnableChk = False
    'boolDrD = False 'uncomment to also use it
  Else
    boolEnableChk = True
    'boolDrD = True 'uncomment to also use it
  End If
  Invalidate_Control "myCheckbox"
  'Invalidate_Control "TestDrD" 'uncomment to also use it
End Sub

Пожалуйста, оставьте отзыв после тестирования. В следующем комментарии я также пришлю проверенную рабочую тетрадь (с помощью трансферного сайта ее можно будет скачать в течение ограниченного периода времени)...

Редактировать: Чтобы вызвать нажатие кнопки "Protect Sheet", вы должны добавить его в часть XML (между <commands> - </commands>), см. выше, а в VBA вам также необходимо скопировать следующий Sub, способный запускать/перехватывать событие кнопки «OnAction» и использовать его:

Sub mySheetProtect(ByVal control As IRibbonControl, ByRef cancelDefault)
  Dim ShPr As CommandBarButton
  Set ShPr = Application.CommandBars.FindControl(msoControlButton, ID:=893) 'legacy way of finding the control caption...
                                                                            'control getText is not exposed...
  If ShPr.Caption = "&Protect Sheet..." Then
    boolEnableChk = False
    boolDrD = False
  Else
    boolEnableChk = True
    boolDrD = True
  End If
  Invalidate_Control "TestDrD": Invalidate_Control "myCheckbox"

  cancelDefault = False 'without it protect/unprotect is cancelled...
End Sub

Пожалуйста, оставьте отзыв после тестирования.

@user23636411 Пожалуйста, загрузите здесь рабочую тетрадь, в которую я играл, чтобы протестировать вышеуказанное решение. Если что-то не понятно, не стесняйтесь спрашивать разъяснения...

FaneDuru 17.05.2024 11:06

FaneDuru: Только что протестировал вашу книгу в Win10/Excel2019 и OSX 10.11.6/Excel2016. В принципе это работает: если вы открываете книгу и лист защищен, оба элемента управления становятся серыми. Но: элементы управления не обновляются мгновенно, как встроенные, при нажатии «Защитить/снять защиту листа». Пример флажка: Лист1 защищен. Я нажимаю «Снять защиту листа». Флажок остается отключенным. Но если я перейду на Лист2 и обратно на Лист1, флажок будет включен. Я раскомментировал три строки в Workbook_SheetActivate. Что мне не хватает? Спасибо!

user23636411 18.05.2024 19:05

@user23636411 user23636411 Нет, вы ничего не упускаете... Так было разработано вышеуказанное решение. Я понял, что код должен отключить контроль, ЕСЛИ лист защищен. Если бы я понимал, когда лист защищен, я бы ничего не делал. Excel не предоставляет никаких событий, которые могли бы инициировать изменение защиты. Но я думаю, что смогу справиться и с этим аспектом. Я имею в виду, что раньше мне удавалось перехватить событие щелчка элемента управления панели команд. Теперь я услышал о возможности такого перепрофилирования контроля. Попробую, но не сейчас, меня нет дома...

FaneDuru 19.05.2024 13:46

@user23636411 user23636411 Но вы можете задать еще один вопрос, упомянув, что это требование также относится к моменту, когда защита будет завершена, и, возможно, кто-то другой решит проблему. Если нет, то я попробую решить эту проблему, когда буду дома. Я почти уверен, что справлюсь...

FaneDuru 19.05.2024 13:52

@user23636411 user23636411 Пожалуйста, протестируйте решение, которое я опубликовал после редактирования, и внимательно прочитайте, как вам также нужно адаптировать XML-код. Вы также можете скачать адаптированную рабочую тетрадь здесь.

FaneDuru 19.05.2024 14:49

FaneDuru: Благодаря обновлениям элементы управления теперь мгновенно реагируют и меняют свое состояние при нажатии кнопки «Защитить/снять защиту листа». Все пользовательские кнопки теперь ведут себя как встроенные кнопки. Все отлично работает как в Win10/Excel2019, так и в OSX10.11.6/Excel2016. +1!

user23636411 19.05.2024 19:55

@user23636411 user23636411 Не стремитесь только к эффекту... Попытайтесь понять и изучить. Это новое событие делает то, что вы недавно прояснили и описали. Но предыдущий делает то, что нужно делать при перемещении между листами. Без предыдущего кода события он будет учитывать все листы, защищенные или не защищенные в соответствии с этим последним действием события, с точки зрения поведения ваших пользовательских элементов управления.

FaneDuru 19.05.2024 20:36

ФанеДуру: Да. Если я правильно понял, первое событие — Workbook_SheetActivate. Это заботится об элементах управления, реагирующих на изменение листа. Если лист защищен, элементы управления отключены и наоборот. Второе событие, новое — mySheetProtect, которое изменит состояние элементов управления, если вы нажмете кнопку «Защитить/Снять защиту листа». Для этого вы изменили назначение элемента управления getText. Чтобы оба события работали вместе, вам необходимо раскомментировать три строки с комментариями в ThisWorkbook. Вкратце: элементы управления «реагируют» на две вещи: 1. смену листа 2. нажатие кнопки.

user23636411 19.05.2024 21:47

@ user23636411 1. SheetActivate означает активацию листа (когда вы его активируете), а не смену листа. А второй означает кнопку SheetProtect — это событие OnAction, к которому подключено mySheetProtect. Чтобы перепрофилировать, вам нужно сделать что-то еще при нажатии на него. Ставим cancelDefault = False и отсудим код, чтобы делать все, что вам нужно. В нашем случае событие перехватывается, используется, а затем позволяется делать то, что оно обычно делает...

FaneDuru 19.05.2024 21:57

Другие вопросы по теме

Похожие вопросы

VBA Macro генерирует html-файлы с недопустимыми символами
Функция SCAN не отображает шаги, за которыми следует функция REDUCE при расчете
Активируйте несколько листов в файле Excel с помощью OpenPyxl
Получите СУММПРОИЗВ с несколькими критериями столбца и строки, если таблица содержит значения, которые не являются числовыми
Получите СУММПРОИЗВ с несколькими критериями столбца и строки и игнорируйте критерии, если ячейка с критериями пуста
Определить имя столбца/номер столбца сортировки в Excel
Найти значение на листе 1, скопировать значение смещения, найти значение смещения на листе 2, вставить текст в ячейку смещения
Заполнение ListBox. «Ошибка выполнения '380': не удалось установить свойство List. Недопустимое значение свойства»
Создает список, содержащий рабочие листы и формулы в них
Как отфильтровать столбец, когда ячейки объединены вместе (Фильтр при объединении ячеек в Excel)