Как заполнить ячейки на листе Excel из функции VBA? - PullRequest
3 голосов
/ 11 мая 2009

Я просто хочу заполнить ячейки в моей электронной таблице с помощью функции VBA. Например, я хотел бы напечатать = FillHere () в ячейке, и в результате у меня будет несколько ячеек, заполненных некоторыми данными.

Я пробовал с такой функцией:

Function FillHere()
  Dim rngCaller As Range
  Set rngCaller = Application.Caller
  rngCaller.Cells(1, 1) = "HELLO"
  rngCaller.Cells(1, 2) = "WORLD"
End Function

Он ломается, как только я пытаюсь изменить диапазон. Затем я попробовал это (даже это не совсем то поведение, которое я ищу):

Function FillHere()
    Dim rngCaller As Range
    Cells(1, 1) = "HELLO"
    Cells(1, 2) = "WORLD"
End Function

Это тоже не работает. Но это работает, если я запускаю эту функцию из VBA, используя F5! Кажется, что невозможно изменить что-либо в электронной таблице при вызове функции ... хотя некоторые библиотеки делают это ...

Я также пытался (на самом деле это была моя первая идея) вернуть массив из функции. Проблема в том, что я получаю только первый элемент в массиве (есть хитрость, которая подразумевает выделение целой области с формулой в верхнем левом углу + F2 + CTRL-SHIFT-ENTER, но это означает, что пользователь должен знать заранее размер массива).

Я действительно застрял с этой проблемой. Я не конечный пользователь, поэтому мне нужно что-то очень простое в использовании, желательно без каких-либо аргументов.

PS: Извините, я уже задавал этот вопрос, но в то время я не был зарегистрирован, и, похоже, я больше не могу участвовать в другой теме.

Ответы [ 4 ]

3 голосов
/ 14 мая 2009

Вам нужно будет сделать это в два этапа:

Измените ваш модуль на что-то вроде:

Dim lastCall As Variant
Dim lastOutput() As Variant

Function FillHere()
    Dim outputArray() As Variant
    ReDim outputArray(1 To 1, 1 To 2)
    outputArray(1, 1) = "HELLO"
    outputArray(1, 2) = "WORLD"

    lastOutput = outputArray
    Set lastCall = Application.Caller

    FillHere = outputArray(1, 1)
End Function

Public Sub WriteBack()
    If IsEmpty(lastCall) Then Exit Sub
    If lastCall Is Nothing Then Exit Sub

    For i = 1 To UBound(lastOutput, 1)
        For j = 1 To UBound(lastOutput, 2)
            If (i <> 1 Or j <> 1) Then
                lastCall.Cells(i, j).Value = lastOutput(i, j)
            End If
        Next
    Next

    Set lastCall = Nothing
End Sub

Затем для вызова Sub перейдите в область ThisWorkbook в VBA и добавьте что-то вроде:

Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
    Call WriteBack
End Sub

То, что это делает, возвращает значение ячейки topleft, а затем, после завершения расчета, заполняет остальные. То, как я это написал, предполагает, что одновременно будет вызываться только одна функция FillHere. Если вы хотите иметь несколько пересчитываемых одновременно, вам понадобится более сложный набор глобальных переменных.

Одним словом предупреждения является то, что это не будет заботиться о том, что оно перезаписывает при заполнении других ячеек.

Edit: Если вы хотите сделать это на уровне приложения в XLA. Код для области ThisWorkbook должен выглядеть примерно так:

Private WithEvents App As Application

Private Sub App_SheetCalculate(ByVal Sh As Object)
    Call WriteBack
End Sub

Private Sub Workbook_Open()
    Set App = Application
End Sub

Это подключит расчет уровня приложения.

1 голос
/ 12 мая 2009

По сути, функция может влиять только на ячейку, из которой она вызывается. Похоже, вам, возможно, придется посмотреть на использование Worksheet_Change или Worksheet_SelectionChange событий , чтобы вызвать модификацию ячеек в заданном диапазоне.

1 голос
/ 11 мая 2009

То, что вы пытаетесь сделать, не будет работать в Excel - это специально.

Вы можете сделать это, хотя:

Function FillHere()
    Redim outputArray(1 To 1, 1 To 2)
    outputArray(1, 1) = "HELLO"
    outputArray(1, 2) = "WORLD"
    FillHere = outputArray
End Function

Если затем вы выберете две соседние ячейки на своем листе, введите =FillHere() и нажмите Control + Shift + Enter (для применения в качестве формулы массива), тогда вы увидите желаемый результат.

0 голосов
/ 13 мая 2009

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

Таким образом, пользователю не нужно иметь какой-либо код в своей книге.

Я думаю (но не знаю наверняка), что это техника, используемая Bloomberg и т. Д.

...