Последний Excel для Mac больше не компилируется - PullRequest
1 голос
/ 27 сентября 2019

Следующий код отлично работает в последних версиях Excel Windows, а также в Excel 16.28 на Mac.Но в последнем Excel для Mac (16.29 и 16.30) он генерирует эту ошибку: «Ошибка компиляции: метод или элемент данных не найден» в строке кода MyShape.Select.

Я предполагаю, что есть альтернативный способделать то, что я хочу, чтобы компилятор одобрил, но я не знаю, что это будет.В качестве альтернативы я попытался не выбирать форму и просто ссылаться на нее, но затем я получаю ту же ошибку, но в строке With MyShape.ShapeRange.Fill.

  Dim MyShape As Shape
  'Other stuff
  Set MyShape = ActiveSheet.Shapes.AddShape(msoShapeRectangle, 400, 400, DistanceBetweenCells, LineWidth)
  MyShape.Select
  With Selection.ShapeRange.Fill
    'stuff here
  End With

Я надеюсь, что более новая версия MacПосле выпуска Excel вернется к более старой версии, чтобы разрешить все вышеперечисленное, но при условии, что это не так, какие-либо обходные пути?

Ответы [ 3 ]

1 голос
/ 27 сентября 2019

Мне нравится, что вы явно ссылаетесь на ActiveSheet, слава!

Проблема в том, что ActiveSheet - это Object, что означает, что компилятор беспомощен:ActiveSheet.Shapes компилируется, но так же будет ActiveSheet.Shapess - даже если указано Option Explicit.Все выражение вычисляется во время выполнения.

Давайте сначала исправим это:

Dim sheet As Worksheet
Set sheet = ActiveSheet

Теперь sheet.Shapes получает проверку целостности и время компиляции вместе с последующим членом .AddShapeвызов.Вы даже получаете всплывающие подсказки с параметрами при наборе списка аргументов!

Что происходит дальше, интересно: вы объявили MyShape как Shape, но это не Shape, на который вы смотрите -У класса Shape нет свойства ShapeRange, так что ... откуда тогда взялся MyShape.ShapeRange?

Если вы прервете выполнение (F9, чтобы установить точку останова) после вызова MyShape.Selectи затем откройте панель быстрого доступа (Ctrl + G), появится ответ:

?typename(selection)
Rectangle

Если вы нажмете Shift + F2 на слове Rectangle ...

Dim myRectangle As Excel.Rectangle '<~ here

... VBE, похоже, не понимает этого («идентификатор под курсором не распознан»).Поэтому мы нажимаем F2, затем щелкаем правой кнопкой мыши где-нибудь и отмечаем опцию «Показывать скрытых участников» - и, конечно же, вот она:

Rectangle.ShapeRange in the VBE's Object Browser

Итак, ваш код говорит: «Давайте использоватьShape interface ", но работает с Rectangle объектом.И поскольку это работает, это означает, что Rectangle "является" Shape: два интерфейса просто описывают один и тот же объект через разные линзы, поэтому любой из них работает ... но тогда Shape.ShapeRange выглядит не совсем правильно, так каккласс Shape не определяет этот член , и это тот интерфейс, о котором мы прямо говорили, что будем работать с .

Если мы хотим вызвать члены Rectangle,мы можем - и так как мы теперь показываем скрытые элементы в браузере объектов, intellisense отображает скрытые типы и элементы тоже.Если весь блок With имеет раннюю привязку, все имеет гораздо больший смысл:

With myRectangle.ShapeRange.Fill

... и объясняет, как код с поздней привязкой из ActiveSheet будет работать во время выполнения для разрешениявызов члена, и теперь компилятору нужна совершенно другая стратегия для компиляции кода VBA: возможно , которая может встряхнуть все, чтобы заставить его работать, а может и нет.По крайней мере, неоднозначности типов и игнорируемые оператором операторы исчезли:)

Что удивляет, так это то, что вы не можете сделать это с помощью пользовательского кода VBA.Если вы создали класс MyShape с методом DoSomething:

'@ModuleDescription "A metaphorical Shape"
Option Explicit

Public Sub DoSomething()
    MsgBox TypeName(Me)
End Sub

А затем класс MyRectangle, который реализует MyShape и предоставляет член в своем собственном общедоступном интерфейсе, который выдает MyShape ссылка на объект:

'@ModuleDescription "A metaphorical Rectangle"
Option Explicit
Private sh As MyShape
Implements MyShape

Public Property Get Thing() As Object
    Set Thing = sh
End Property

Private Sub Class_Initialize()
    Set sh = New MyShape
End Sub

Private Sub MyShape_DoSomething()
    MsgBox TypeName(Me)
End Sub

И теперь в любом стандартном модуле мы можем проверить это - сначала все с ранним связыванием, и у нас будет фабричный метод, который возвращает MyShape для имитацииShapes.CreateShape:

Public Sub WorksMaybe()
    Dim r As MyShape
    Set r = CreateRect
    r.Thing.DoSomething
End Sub

Private Function CreateRect() As MyShape
    Set CreateRect = New MyRectangle
End Function

Итак, мы запускаем это (в Windows), и я ожидал, что код не компилируется:

Compile error: method of data member not found

Позднее связываниеоднако ...

Public Sub WorksMaybe()
    Dim r As Object
    Set r = CreateRect
    r.Thing.DoSomething
End Sub

Private Function CreateRect() As MyShape
    Set CreateRect = New MyRectangle
End Function

... работает?Нет:

run-time error 438:

Разве мы не смотрим на MyRectangle объект?Нет: мы рассматриваем пределы позднего связывания полиморфизма в VBA - мы создали New MyRectangle, но компилятору CreateRect возвращает ссылку на объект MyShape.Если мы поместим точку останова на End Function, запустим ее, а затем наберем ?TypeName(CreateRect) в непосредственной панели (Ctrl + G) при достижении точки останова, несмотря на то, что объявленный тип равен MyShape, тип времени выполнения явно MyRectangle.

И это должно работать - но это не так.Ошибка 438, член не найден: поздняя привязка / эквивалент времени выполнения ошибки компиляции «метод или элемент данных не найден».

И если мы используем интерфейс, мы действительно хотим работать с ...

Public Sub WorksMaybe()
    Dim r As MyRectangle
    Set r = CreateRect
    r.Thing.DoSomething
End Sub

Private Function CreateRect() As MyShape
    Set CreateRect = New MyRectangle
End Function

... тогда все "просто работает":

Теперь я не запускаю это на Mac, но этот код компилируетсядля меня ...

Option Explicit
Const DistanceBetweenCells As Long = 50
Const LineWidth As Long = 2

Public Sub WorksMaybe()
    Dim r As Excel.Rectangle
    Set r = CreateRect
    r.ShapeRange.Fill.BackColor.RGB = vbRed
End Sub

Private Function CreateRect() As Excel.Shape
    Set CreateRect = Shapes.AddShape(msoShapeRectangle, 40, 40, DistanceBetweenCells, LineWidth)
End Function

... и систематически вызывает ошибку времени выполнения 13, как только возвращается CreateRect и ссылка Shape назначается на Rectangle - ошибка 13 является "несоответствием типов".Другими словами, Rectangle - это , а не a Shape (!!?! ??).Доказательство: если мы заставим CreateRect вернуть Excel.Rectangle, мы теперь получим ошибку несоответствия типов, как только мы попытаемся присвоить возвращаемое значение функции, и больше ничего не имеет смысла: что-то странное происходит, и, ну, яу меня нет идей - кажется, нет никакого способа работать с ранним связыванием с Rectangle, несмотря на то, что TypeName(Selection) утверждает, что тип (класс в конце концов скрыт / недокументирован по причине!),что ... в значительной степени разрушает всякую надежду, особенно если ни With Selection.Fill, ни With MyShape.Fill не работают (хотя на моем Windows-боксе это прекрасно работает).

Отправка недовольства с помощью некоторого кода репро черезФункция обратной связи с пользователем должна быть услышана от команды разработчиков Microsoft.Я сомневаюсь, что они что-то удалили откуда угодно - но не исключено, что что-то сломалось в том, как разрешаются интерфейсы, где-то глубоко внутри какого-то, казалось бы, не связанного фрагмента внутреннего API:)

0 голосов
/ 27 сентября 2019

Ответ от Стив Риндсберг (MVP) :

Итерация по коллекции .ShapeRange:

For x = 1 To .ShapeRange.Count
   With .ShapeRange(x)
       '...stuff....
   End With
Next

IУ меня было несколько схожих странных ошибок на Mac, где ошибки в отличном коде (в Windows) или иногда приводили к тому, что приложение Mac становилось пустяковым!И исчезнуть.Итерация коллекций таким способом была исправлением.

0 голосов
/ 27 сентября 2019

Хорошо, я думаю, это выяснилось.В Mac Excel версии 16.29 Microsoft удалила некоторых членов класса, по крайней мере, для фигур.Например, «Заполнить» и «Выбрать» больше не доступны.Таким образом, любой код, который ссылается на них, выдаст ошибку.Я не уверен, насколько это обширно или какие-либо другие последствия, но я знаю, что код отлично работает в версии 16.28, а также что список членов в 16.28 показывает и «заполнить», и «выбрать», но не в 16.29.Спасибо Мэтью Гиндону выше за вклад, а также за постера, который удалил его ветку - оба эти человека действительно помогли.Я сообщил об этой проблеме в Microsoft.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...