Страницы: 1
RSS
Отличие адреса диапазона от Selection
 
Добрый вечер, всем.  
 
Помогите разобраться в понятиях ).  
Есть диапазон А1:А10 с числами от 1 до 10. Если в окне Immediate пишу:  
[A1:A10]=[A1:A10*2] и ентер, то все значения диапазона увеличиваются в два раза нормально, а если пишу:
[Selection]=[Selection*2] (перед этим выделив диапазон А1:А10) то в ячейках пишет #ИМЯ?.
 
Фактически, как я понимаю то Selection  в  данном случае равен А1:А10, а результат другой.  
Если кто сможет объяснить на ночь глядя, в чем тут загвоздка, буду благодарен.
Редко но метко ...
 
надеюсь пример не нужен для такого вопроса ? )
Редко но метко ...
 
В квадратных скобках или аргументом Evaluate должно быть то, что пишется в формулах листа. Selection - это элемент VBA, а не языка формул, поэтому  
 
selection=evaluate(selection.address & "*2")
 
{quote}{login=Казанский}{date=06.05.2011 11:37}{thema=}{post}В квадратных скобках или аргументом Evaluate должно быть то, что пишется в формулах листа. Selection - это элемент VBA, а не языка формул, поэтому  
 
selection=evaluate(selection.address & "*2"){/post}{/quote}  
 
Ваше выражение: selection=evaluate(selection.address & "*2") действительно считает, еще вопрос в догонку, если записать вот так:  
selection=[selection.address & "*2"]
то не считает (. Подскажите что опять не так, ведь формально: evaluate(выражение) то же самое что и [выражение].
Редко но метко ...
 
Интересный эффект получается, если на листе определить диапазон с именем Selection.  
Тогда по команде  
[Selection]=[Selection*2]
вычисляется массив удвоенных значений диапазона Selection, но помещается он не в этот диапазон, а в выделенный диапазон!  
Дальше - больше. Если написать  
[Selection]=[Selection*1]
, то выделенный диапазон становится равным диапазону Selection (с учетом размеров диапазонов).  
А если написать  
[Selection]=[Selection]
, то выделенный диапазон... ОЧИЩАЕТСЯ!  
Причем независимо от того, определен диапазон с именем Selection или нет.  
 
Так в Excel 2000.
 
А по поводу этой записи : selection=[selection.address & "*2"] нет мнений, почему не считает ?
Редко но метко ...
 
> если записать вот так:  
selection=[selection.address & "*2"]
то не считает (. Подскажите что опять не так, ведь формально: evaluate(выражение) то же самое что и [выражение].
 
Не то же самое. Evaluate("выражение") - то же самое, что [выражение]. То есть в квадратных скобках должна быть текстовая константа, и она должна быть выражением, допустимым для формулы листа. Эта константа "зашивается" в код при компиляции и не меняется во время исполнения. То есть можно написать [A1*2] или [A1 & "вася"], потому что
=A1*2 и =A1 & "вася"  
- это правильные формулы листа.  
Но нельзя написать [selection.address & "*2"], потому что
=selection.address & "*2"  
- это неправильная формула листа.  
Функция Evaluate позволяет формировать текстовое выражение во время исполнения.  
При использовании диапазонов для Evaluate всегда приходится брать их адрес.
 
Вот это я называю "Разжевать и в рот положить". Спасибо товарищ Казанский за столь исчерпывающий ответ.  
Умиротворенный и не терзаемый более вопросами, иду спать. )
Редко но метко ...
 
{quote}{login=Казанский}{date=07.05.2011 12:14}{thema=}{post}Интересный эффект получается, если на листе определить диапазон с именем Selection  
...  
А если написать  
[Selection]=[Selection]
, то выделенный диапазон... ОЧИЩАЕТСЯ!  
Причем независимо от того, определен диапазон с именем Selection или нет.{/post}{/quote}  
 
Чтобы ни у кого не создалось впечатление о VBA-произволе, распишу подробно, что к чему. Но можно и сразу прочесть рекомендации в п.4  
 
1. Имеется одно существенное отличие [X] от Evaluate("X"):
Вариант с квадратными скобками [X] пытается сначала выполнить VBA-код (встроенный или написанный), если конечно X не является математическим выражением и совпадает с именем VBA-свойства, метода, процедуры, функции или UDF, класса, объекта и т.п.
 
Если в VBA не найдено ничего из перечисленного с именем "X", то поиск переключается с объектной модели VBA на объектную модель  Excel. То есть, производится попытка выполнения формулы массива: =X  
 
Evaluate("X") никогда не пытается что-то искать в VBA, а сразу производит попытку выполнения формулы массива: =X  
Поэтому, кстати, Evaluate("X") немного быстрее, чем [X]
 
Пример1:  
 
' Вызов встроенной VBA-процедуры MsgBox  
Sub Test_MsgBox()  
 [MsgBox] "MsgBox"
End Sub  
 
Пример2:  
 
' Вызов своей процедуры MyMsgBox  
Sub Test_MyMsgBox()  
 [MyMsgBox]
End Sub  
 
Sub MyMsgBox()  
 MsgBox "Привет!"  
End Sub  
 
Пример3:  
 
' Вызов UDF MySel  
Sub Test_MySel()  
 MsgBox [MySel].Address ' можно и так: [MsgBox] [MySel].Address
End Sub  
 
Function MySel()  
 Set MySel = Selection  
End Function  
 
 
2. Еще одной редко учитываемой особенностью VBA является то, что если явно не указывать свойства, то компилятор подставит их сам, но по своему усмотрению, в зависимости он контекста VBA-кода. Это относится не только к [X] или Evaluate("X") а вообще ко всему коду.
 
Например: Range("АдресДиапазона1") = Range("АдресДиапазона2")    
 
чаще всего трактуется как: Range("АдресДиапазона1").Value = Range("АдресДиапазона2").Value  
 
Но это не гарантируется!  
Если "АдресДиапазона1" = "АдресДиапазона2" и не указано свойство Value, то вместо ожидаемого действия вызывается метод очистки значений диапазона:  
Range("АдресДиапазона1").ClearContents.  
 
Поэтому всегда лучше явно указывать требуемое свойство, чтобы не давать компилятору права выбора этого свойства:  
[A1:A2].Value = [A1:A2].Value
Range("A1:A2").Value = Range("A1:A2").Value  
 
 
3. С учетом изложенного, можно легко понять, что происходит с кодом, приведенным  Алексеем (Казанским)  
 
Вариант1: [Selection] = [Selection*2] или [Selection] = [Selection*1]
[Selection] равносильно Application.Selection , потому что в VBA найдено зарезервированное имя свойства Selection, которое работает и без начального Application.
А [Selection*2] равносильно формуле массива =Selection*2 , потому что внутри квадратных скобок - математическое выражение, при этом "Selection" - именованный диапазон.
 
Вариант2: [Selection] = [Selection]
Это равносильно: Selection = Selection (см.п.1)  
Но это совсем не одно и тоже, что: Selection.Value = Selection.Value    
а на самом деле означает: Selection.ClearContents (см.п.2)  
 
 
4. Выводы.  
   
4.1 Для предсказуемого результата используйте Evaluate("Выражение")  
где ожидается, что Выражение будет выполнено как формула массива Excel  
 
4.2 Если используете [Выражение] , то следите за тем, чтобы в VBA не было Вашего кода или встроенного с именем Выражение.
 
4.3 Если используете [Выражение] , то всегда дописывайте еще и требуемое свойство обычно это Value. То есть,
вместо: [A1:A2] = [A1:A2]
должно быть: [A1:A2].Value = [A1:A2] .Value
 
P.S. С Днем Радио!
 
{quote}{login=ZVI}{date=07.05.2011 04:46}{thema=Особенности Evaluate}{post}Если "АдресДиапазона1" = "АдресДиапазона2" и не указано свойство Value, то вместо ожидаемого действия вызывается метод очистки значений диапазона:  
Range("АдресДиапазона1").ClearContents.{/post}{/quote}  
Интересно ещё, что если "АдресДиапазона1" = "АдресДиапазона2", и диапазон содержит только одну ячейку, то очистка не выполняется, и все работает как ожидается. Объясняется тем, что диапазон одной ячейки для компилятора всегда по умоляанию имеет свойство Value. А для несколькиз ячеек - в зависмости от ситуации. Кстати, и VarType(Range("A1:A2")) = vbArray, но VarType(Range("A1")) <> vbArray  
 
Это лишний раз подтверждает необходимость самому явно указывать требуемые свойства (см. п.4.3)
 
{quote}{login=ZVI}{date=07.05.2011 04:46}{thema=Особенности Evaluate}{post}{quote}{login=Казанский}{date=07.05.2011 12:14}{thema=}{post}С Днем Радио!{/post}{/quote}  
В связи с категорически приближающимся Днём химика :-), хочу добавить к сказанному ZVI.  
Конструкции формул, которые должны возвращать массив, но содержащие "немассивные" функции, с Evaluate иногда отказываются работать, пока формулу не обернуть INDEX' ом.  
Пример:  
На рабочем листе формула {=СЧЁТЕСЛИ(Большой_список;Список_уникальных)} - старательно подсчитывает число уникальных в списке с повторами, а VBA-проге Evaluate("COUNTIF(BigList,UniqueList)") - не понимает, что это должен быть массив.  
А если написать: ArrayOfUnique = Evaluate("INDEX(COUNTIF(BigList,UniqueList),0,0)") - всё Ok.
 
ZVI  
Владимир, большое спасибо. Я сам собирался заняться таким расследованием... а тут уже все готово!  
 
С.М.  
Спасибо за метод "force array"
 
Уважаемые модераторы,  
 
может, тему в Копилку?  
И дать более подходящее название, например  
 
VBA: квадратные скобки, Evaluate и свойства диапазона по умолчанию
 
Алексей, в "Копилку" мало кто заглядывает... Правда, и тут её не сыскать. А копию, кажется, никак. Переговорю с Димой.
 
Владимир (ZVI) настоящий просветитель Excel. И все темы с его развернутыми разъяснениями я бы выделил в отдельную ветку. Название например "Теория Excel VBA в примерах"...
 
Хорошо, что иногда вопросы задают и Знатоки! Интересно вникать.
 
{quote}{login=VovaK}{date=03.09.2011 10:34}{thema=}{post}Владимир (ZVI) настоящий просветитель Excel. И все темы с его развернутыми разъяснениями я бы выделил в отдельную ветку. Название например "Теория Excel VBA в примерах"...{/post}{/quote}  
Ну не все, разумеется, но тем не менее) Для объективности стоит отметить, что "просветитель" не только ZVI) В очередной раз повторюсь - на форуме много достойных умов : )  
 
В целом идея (лично мне и не только в отношении ZVI) кажется хорошей)
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук


https://github.com/nervgh
Страницы: 1
Наверх