понеделник, 19 ноември 2012 г.

#053 Как да използваме старата стойност при промяна

При създаването на макроси които да следят промяната на клетки често се налага да се извършват обработки с участието на данните в клетката преди тя да бъде променена. Проблемът тук е, че събитието Worksheet_change носи само информация за новата стойност! Т.е. нямаме две събития ПРЕДИ и СЛЕД промяната, а само едно събитие. Това налага правенето на различни трикове. Един от тези трикове е в момента на избор на клетка (събитието SelectionChange) да се запомнят данните в променлива или скрит работен лист.
В примера ще използвам факта че старата стойност се пази от самия Excel и може да бъде възстановена с помощта на UnDo! Тук има един гоооолям камък (не бих го нарекъл подводен). Проблемът произтича от факта, че Undo и промяната се извършва в събитие и имаме голяма опасност да се зациклим. Трябва да забраним генерирането на събития при извършване на манипулацията.

Ето едно забавно (и не много смислено;) примерче за по-лесно разбиране на решението:

Условие: Да се направи област, в която при въвеждане да не се изтрива старата стойност ами да се създава списък разделен със запетайка.Потребителя въвежда нова стойност и тя се "долепя" към текущите стойности.

Решение: Заставате върху името на листа. Десен бутон. View Code и копирате в редактора следния код:
'---------------------------------------- Начало
Private Sub Worksheet_Change(ByVal Target As Range)
    Dim r As Range
    Dim oldvalue, newvalue
    ' Зоната която се наблюдава в примера (променете за вашия случай!)
    '------
    Set r = Range("A1:A100")
    '-----
    ' Изход ако се променят повече от една клетка 
    ' или клетката не е в наблюдаваната зона
    If Target.Cells.Count > 1 Or Intersect(r, Target) Is Nothing Then Exit Sub

    'Изход ако се изтрива клетка
    If IsEmpty(Target) Then Exit Sub

    ' Изключване на събитията (така се предпазваме от зацикляне!)
    Application.EnableEvents = False
    'Вземаме текущата стойност
    newvalue = Target.Value
    'Връщаме старата стойност чрез Undo
    Application.Undo
    oldvalue = Target.Value
   
    'Създаване на новата стойност 
    '(променете според вашите изисквания)
    '-----

    'Ако клетката е била празна
    If IsEmpty(oldvalue) Then
      Target.Value = newvalue
    Else ' Ако клетката не е била празна долепяме новата стойност с запетайка
      Target.Value = oldvalue & "," & newvalue
    End If
    '-----
    ' Възстановяване обработката на събития
    Application.EnableEvents = True

End Sub
' ----------------------------- Край

Забележка: Опитайте да въвеждате стойности в зоната A1:A100. Когато въведете стойност в клетка в която вече има въведени данни те се запазват! Както казах примерът е по-скоро илюстративен, но може да ви послужи:) Според вашите нужди променяте  редовете които са заградени с "-".

Успех