Как отличить диаграммы/фигуры, созданные программным путем, от всех диаграмм/фигур на рабочем листе?

Я ищу способ различать диаграммы, созданные моим кодом, и диаграммы, созданные пользователем вручную. Использование chart.name сработало бы, если бы я установил определенный префикс name_prefix или что-то еще для диаграмм, но это свойство бесполезно для меня, поскольку имена могут динамически изменяться пользователем. Я думал о том, чтобы посмотреть на диаграмму, как на фигуру, и изменить ее идентификатор, но с этим тоже не повезло. Я проверил объектную модель диаграммы/формы и не могу найти свойство, которое я мог бы использовать, чтобы каким-то образом отличить свои диаграммы от всех диаграмм в коллекции листов.

Общая идея заключается в том, что я создаю диаграмму с помощью VBA, и когда пользователь активирует ее, событие chart.activate открывает пользовательскую форму. Эта пользовательская форма должна открываться, когда пользователь активирует диаграмму, созданную моим кодом, а не при активации ЛЮБОЙ диаграммы на листе. Я умею делать все, кроме того, как различать графики.

Любые идеи, как это можно сделать? Заранее спасибо!

РЕДАКТИРОВАТЬ: я также подумал о добавлении некоторой информации к названиям серий, опять же, о префиксном типе информации. Это сработало бы, но опять же — конечный пользователь может легко изменить его, а этого я хотел бы избежать.


person Rafał Kowalski    schedule 10.01.2021    source источник
comment
Добавьте ссылку на объекты диаграммы, которые вы создаете программно, в словарь сценариев. Возможно, вы даже сможете использовать Varptr для получения адреса памяти, который вы можете использовать в качестве ключа, но я не уверен, как часто VBA/EWxcel может перемещать вещи в фоновом режиме, тем самым делая недействительным значение, полученное Varptr.   -  person freeflow    schedule 10.01.2021
comment
Интересная идея. У меня есть красные словари, но я ими раньше не пользовался. Как это сработает? Я предполагаю, что добавляю конкретный ключ диаграммы в словарь. Но если я не ошибаюсь, мне нужно было привязать этот ключ к конкретному элементу диаграммы, чтобы потом его расшифровать? Где будет храниться этот словарь? Можно ли получить его между сеансами, например, после закрытия книг?   -  person Rafał Kowalski    schedule 10.01.2021
comment
Если вам нужно хранить информацию между сессиями, это совсем другое дело. В таком случае я бы последовал предложению @rchardtallent.   -  person freeflow    schedule 10.01.2021
comment
@freeflow Понятно. Хотя за идею спасибо. Я обязательно посмотрю на это, так как это часть VBA, в которую я еще не вошел :)   -  person Rafał Kowalski    schedule 10.01.2021
comment
Также взгляните на свойство Chart.CodeName (Excel)   -  person freeflow    schedule 10.01.2021
comment
Я не могу назначить или получить свойство Chart.CodeName из встроенной диаграммы. Не относится ли это свойство только к рабочим листам диаграмм?   -  person Rafał Kowalski    schedule 10.01.2021
comment
Вы активировали события графика или назначили макрос для каждого созданного графика?   -  person FaneDuru    schedule 11.01.2021


Ответы (2)


Было бы хорошо, если бы вы опубликовали код, который используете. Я (только) могу предположить, что вы активировали события графиков.

Пожалуйста, попробуйте следующий способ, который должен работать с активированными событиями или нет:

  1. Скопируйте следующий код в стандартный модуль. Это Sub, который будет назначен всем созданным диаграммам. Его можно использовать вместо (существующих) событий или с работающими событиями:
Sub CreatedChart()
   Dim ch As Chart
   Set ch = ActiveSheet.ChartObjects(Application.Caller).Chart
   'you can call the form in discussion here...
   Select Case ch.Parent.Name
    Case "CrChart1", "CrChart2"
        MsgBox "Here you can do something in case of Chart 1 or Chart 2..."
    Case "CrChart3"
        MsgBox "Here you can do something in case of Chart 3..."
   End Select
End Sub
  1. Скопируйте следующий код в модуль. Он создаст диаграммы и назначит им указанные выше Sub:
Sub testChartsCreate()
   Dim ws As Worksheet, ch As ChartObject, i As Long
   Set ws = ActiveSheet
   For i = 1 To 3
        Set ch = ws.ChartObjects.Add(left:=1, _
                    top:=10, width:=100, height:=100)
        ch.Name = "CrChart" & i
        ws.Shapes(ch.Name).OnAction = "CreatedChart"
        ch.Chart.ChartType = xlLine
        'do here all your charts configuration...
   Next i
End Sub
  1. Вы можете определить, какие из всех существующих диаграмм на листе были созданы с помощью приведенного выше кода. Пожалуйста, позаботьтесь о том, чтобы также были созданы диаграммы вручную или программно, но не с помощью приведенного выше кода (типа), который назначает этот конкретный Sub:
Sub testIdentifCrCharts()
   Dim sh As Worksheet, ch As ChartObject, i As Long
   
   Set sh = ActiveSheet ' use here the necessary sheet
   For Each ch In sh.ChartObjects
        Debug.Print ch.Name, isCreatedChart(ch.Chart, sh)
   Next
End Sub

Private Function isCreatedChart(ch As Chart, sh As Worksheet) As Boolean
  If sh.Shapes(ch.Parent.Name).OnAction = "CreatedChart" Then
    isCreatedChart = True
  End If
End Function

Я использовал ch As Chart как первый параметр функции, для проверки графика, а не ChartObjects...

Приведенное выше решение может показаться сложным, но на самом деле его очень легко понять и применить.

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

person FaneDuru    schedule 11.01.2021
comment
Хорошая идея, мне нравится подход и креативность. Я просмотрел свойство OnAction, но понятия не имел, как его использовать. Однако есть один вопрос: можно ли каким-то образом применить значение к свойству OnAction без фактического запуска макроса? Вы использовали его с пустым макросом, чтобы просто присвоить значение этому свойству, которое можно было бы проверить позже? Мне просто интересно, какие потенциальные проблемы могут возникнуть у меня с этим пустым подходом. - person Rafał Kowalski; 11.01.2021
comment
@Rafał Kowalski: Основная идея заключалась в том, чтобы ответить на ваш вопрос. Я имею в виду, что я использовал свойство формы диаграммы OnAction, чтобы отличать диаграммы, созданные с помощью приведенного выше кода, от других диаграмм на листе. Но можно и два в одном, если надо... С помощью Application.Caller можно определить нажатый график и сделать что-то по его названию, используя для всех один назначенный макрос. Я отредактирую приведенный выше CreatedChart() Sub и покажу вам, как его можно использовать вместо события. - person FaneDuru; 11.01.2021
comment
@Rafał Kowalski: Обновлено. Пожалуйста, нажмите на диаграммы, созданные с помощью приведенного выше кода, и вы увидите результат. Использование Sub таким (новым) способом не влияет на способ идентификации созданных кодом диаграмм. Он работает точно так же... Это просто еще одна возможность заменить событие графика. - person FaneDuru; 11.01.2021

Одной из возможных идей было бы поместить ваше магическое значение в MailEnvelope.Introduction. Это настраиваемое строковое свойство VBA, которое вы, скорее всего, никогда не будете использовать по прямому назначению, и оно не отображается в пользовательском интерфейсе для созданной пользователем диаграммы.

person richardtallent    schedule 10.01.2021
comment
Спасибо за идею. Я попытался присвоить или прочитать значение в/из 'MailEnvelope', но получаю ошибку времени выполнения 1004 Object-defined error. Я не мог обойти это, и я не знал, для чего это свойство. Не могли бы вы дать мне еще несколько советов, как это будет работать? Я предполагаю, что когда я добавлю значение к этому свойству, оно будет присутствовать в этом объекте, пока оно не будет удалено? И в результате я должен иметь возможность проверить, имеет ли выбранный график mailenvelope.introduction = X, и если это правда, то что-то сделать? - person Rafał Kowalski; 10.01.2021