Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - VBA

Страница: 1 | 2 |

 

  Вопрос: Worksheet_Change Добавлено: 01.01.10 19:29  

Автор вопроса:  Олег
Здравствуйте, Уважаемые!

Всех от души с Новым годом!

У меня такой вопрос (проблема) возник по ходу разработки макроса под Excel.

Дело в следующем... На одном из листов моей рабочей книги имеется ячейка, в которую транслируется значение из ячейки с другого листа. Когда значение в этой ячейке изменяется, программа должна проанализировать изменение и выполнить определённые действия.

Разумеется, я решил воспользоваться событием Worksheet_Change в Коде изменяемого листа. Но не тут-то было! Оказалось, что если этот лист не активен, то макрос никак не реагирует на это событие. Реакцию вызывает только НЕПОСРЕДСТВЕННОЕ изменение значения ячейки в АКТИВНОМ листе!

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

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

Итак, имеются два листа: Лист1 и Лист2.
На Лист2 в ячейку А1 вписана формула "=Лист1!A1". Таким образом, когда мы изменяем значение в ячейке А1 первого листа, автоматически изменяется и значение в ячейке А1 второго листа.

Теперь в Коде второго листа вписываем вот такую процедуру:

Private Sub Worksheet_Change(ByVal Target As Range)
   MsgBox (Target)
End Sub

После этого при НЕПОСРЕДСТВЕННОМ изменении любой ячейки на Лист2, выскакивает сообщение с тем значением, которое мы вводим.

Но когда мы изменяем ячейку А1 на первом листе, то сообщение не выскакивает (реакции на событие нет!), хотя значение в ячейке А1 второго листа тоже изменилось...

Как заставить программу реагировать на изменение ячеек на НЕАКТИВНОМ в данный момент листе?

Ответить

  Ответы Всего ответов: 17  

Номер ответа: 1
Автор ответа:
 ADSemenov.ru



Вопросов: 5
Ответов: 276
 Web-сайт: www.adsemenov.ru
 Профиль | | #1
Добавлено: 02.01.10 14:00
____ Ну, а если использовать в книге самой событие Workbook_SheetChange?

Ответить

Номер ответа: 2
Автор ответа:
 Smith



ICQ: adamis@list.ru 

Вопросов: 153
Ответов: 3632
 Профиль | | #2 Добавлено: 02.01.10 16:23
Или написать сторожа, правда цикл не есть гуд

Ответить

Номер ответа: 3
Автор ответа:
 hip



Вопросов: 3
Ответов: 22
 Профиль | | #3 Добавлено: 02.01.10 16:51
А сделать все необходимое в коде первого листа нельзя разве? Только переменной Target не удастся воспользоваться в этом случае - в ней будет диапазон с первого листа.

  1.  
  2. 'в коде листа, на котором происходят непосредственные изменения (Лист1):
  3. Private Sub Worksheet_Change(ByVal Target As Range)
  4.  
  5.   MsgBox (Sheets("Лист2").Cells(1,1).value)
  6.  
  7. End Sub

Ответить

Номер ответа: 4
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #4 Добавлено: 02.01.10 17:53
Большое спасибо, что откликнулись на мою просьбу помочь! Я даже не ожидал, что будет так много откликов, особенно если учесть, что сейчас у всех сейчас "отходняк" после Новогодней ночи :)

Smith пишет:
Или написать сторожа, правда цикл не есть гуд


Я совсем не опытный программист на VBA, поэтому что такое "сторож" не знаю. Но, на самом деле, хотел бы узнать! :) Я много программировал (непрофессионально, для своих нужд) на VB5, а в VBA, можно сказать, делаю свои первые шаги :)

hip пишет:
А сделать все необходимое в коде первого листа нельзя разве? Только переменной Target не удастся воспользоваться в этом случае - в ней будет диапазон с первого листа.

 
'в коде листа, на котором происходят непосредственные изменения (Лист1):
Private Sub Worksheet_Change(ByVal Target As Range)
 
  MsgBox (Sheets("Лист2";).Cells(1,1).value)
 
End Sub


Да в том-то и проблема, что я постоянно перемещаюсь по всем листам и на всех листах происходят ПОСТОЯННЫЕ быстрые изменения (получение информации из внешних источников, подсчёт, построение диаграмм). А ту ячейку, изменения в которой для меня особенно важны, я специально "вынес" на отдельный лист, чтобы там могла изменяться только она одна! (Чтобы не отфильтровывать "лишних" изменений!) Очень уж я рассчитывал на событие Worksheet_Change, наивно думал, что прога должна реагировать на изменения, даже когда лист не активен...


ADSemenov.ru пишет:
Ну, а если использовать в книге самой событие Workbook_SheetChange?
 


На данный момент, для меня этот совет звучит самым заманчивым из всех... Сейчас буду экспериментировать... Потом отпишусь!

Хотя сразу вижу большой минус этой затеи в том, что много ресурсов компа будет уходить на реакцию (с последующей отфильтровкой) на ВСЕ изменения, которых в моей книге огромное количество. Боюсь, что тогда комп будет сильно тормозить. Ведь я же для того и собирался транслировать интересующее меня значение в ЕДИНСТВЕННУЮ изменяемую ячейку на ОТДЕЛЬНОМ листе, чтобы избежать затрат ресурсов на лишнюю фильтрацию. Макросы ведь и без того не слишком быстро работают, сами знаете...

Ответить

Номер ответа: 5
Автор ответа:
 ADSemenov.ru



Вопросов: 5
Ответов: 276
 Web-сайт: www.adsemenov.ru
 Профиль | | #5
Добавлено: 02.01.10 18:21
____ Так лист сразу отбить на входе в обработку и про ресурсы можно забыть. :)

Ответить

Номер ответа: 6
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #6 Добавлено: 02.01.10 18:45
ADSemenov.ru пишет:
Так лист сразу отбить на входе в обработку и про ресурсы можно забыть. :)


На этом месте хотелось бы поподробнее :)
В смысле, что такое "лист сразу отбить на входе в обработку", и как это сделать практически?

  1. Private Sub Workbook_SheetChange(ByVal Sh As Object, _
  2.         ByVal Source As Range)
  3.        ' Здесь-то всё равно приходится фильтровать
  4.        ' с помощью If, Select Case или что-нибудь в
  5.        ' этом роде.
  6. End Sub






Ответить

Номер ответа: 7
Автор ответа:
 ADSemenov.ru



Вопросов: 5
Ответов: 276
 Web-сайт: www.adsemenov.ru
 Профиль | | #7
Добавлено: 02.01.10 21:13
____ Проверить Sh на предмет идентичности листу с Вашей ячейкой и только после этого что-то делать.
____ Если машина не тройка [:)] и изменений в книге не десятки тысяч за один раз, то никаких задержек быть не должно.
____ А в чём сомнение?

Ответить

Номер ответа: 8
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #8 Добавлено: 02.01.10 22:04
ADSemenov.ru пишет:
 Проверить Sh на предмет идентичности листу с Вашей ячейкой и только после этого что-то делать.


Попробовал вот так вот сделать:
  1. Private Sub Workbook_SheetChange(ByVal Sh As Object, _
  2.         ByVal Source As Range)
  3.       
  4.       If Not Sh Is Worksheets.Item("Лист2") Then Exit Sub
  5.       
  6.          Beep
  7.  
  8. End Sub


Почему-то у меня не получается... Бибикает, только когда изменяю что-нибудь только НЕПОСРЕДСТВЕННО на втором листе, когда он активен. А если изменять значение ячейки А1 первого листа (и при этом изменяется ячейка А1 второго листа тоже), то не бибикает... Нужны дополнительные фильтры, наверно... Ниже я описал, как я потом ещё попробовал, но тоже неудачно :(


ADSemenov.ru пишет:
__ Если машина не тройка [:)] и изменений в книге не десятки тысяч за один раз, то никаких задержек быть не должно.
____ А в чём сомнение?


Машина хоть и не тройка, конечно :) , но довольно-таки старенькая (Селерон 1400 Мгц) :)
А изменений, на самом деле, очень много: программа непрерывно получает данные из внешнего источника, обрабатывает их, строит графики, а масштаб хочется покрупнее, чтобы зрение беречь. А крупная графика, разумеется, съедает много ресурсов, а тут ещё и макрос будет... Вот и не уверен я: потянет ли "мой старичок"?! :)

Хоть на том листе у меня других изменяемых ячеек не предполагается размещать, но всё равно, согласуясь с хорошим стилем программирования, хотелось бы фильтр поставить на возможные случайные изменения в других ячейках интересующего меня листа.

Попробовал вот так вот:

  1. Private Sub Workbook_SheetChange(ByVal Sh As Object, _
  2.         ByVal Source As Range)
  3.       
  4.       If Not Sh Is Worksheets.Item("Лист2") Then Exit Sub
  5.       
  6.       If Source = Worksheets("Лист2").Cells(1, 1) Then
  7.          Beep
  8.       End If
  9. End Sub


Почему-то не работает. Отказывается бибикать, когда изменяю значение в ячейке А1 первого листа, хотя при этом значение в ячейке А1 второго листа тоже изменяется... Что я делаю не так, не подскажете?

Ответить

Номер ответа: 9
Автор ответа:
 ADSemenov.ru



Вопросов: 5
Ответов: 276
 Web-сайт: www.adsemenov.ru
 Профиль | | #9
Добавлено: 02.01.10 22:49
____ Да. И тут событие не обрабатывается только на открытом листе.
____ Можно схитрить и это вполне работает:

  1. Dim m
  2.  
  3. Private Sub Workbook_Open()
  4.   m = Sheets("Лист2").Cells(1, 1).Value
  5. End Sub
  6.  
  7. Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  8.   If Sheets("Лист2").Cells(1, 1).Value = m Then Exit Sub
  9.   m = Sheets("Лист2").Cells(1, 1).Value
  10.   Beep
  11. End Sub


____ Первая ячейка на Лист2 меняется по значению с Лист1. При активном Лист1 прекрасно "ловит" событие изменения в первой ячейке на Лист2.

Ответить

Номер ответа: 10
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #10 Добавлено: 02.01.10 23:35
ADSemenov.ru пишет:
_ Первая ячейка на Лист2 меняется по значению с Лист1. При активном Лист1 прекрасно "ловит" событие изменения в первой ячейке на Лист2.


Огромное спасибо!!! Классно!!!

Ответить

Номер ответа: 11
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #11 Добавлено: 04.01.10 23:32
  1. Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  2.   If Sheets("Лист2").Cells(1, 1).Value = m Then Exit Sub
  3.   m = Sheets("Лист2").Cells(1, 1).Value
  4.   Beep
  5. End Sub


Снова задумался по ходу разработки... Всё-таки как-то неуклюже получается... Меня интересует изменение только ОДНОЙ-ЕДИНСТВЕННОЙ ячейки на отдельном листе, где кроме этой ячейки вообще ничего потенциально изменяемого нет. А с таким кодом, программа будет так или иначе реагировать АБСОЛЮТНО НА ВСЕ изменения НА ВСЕХ листах! Это даже обидно как-то. Ну неужели нет другого выхода?! Хотя бы Sh заставить как-нибудь работать...

Ответить

Номер ответа: 12
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #12 Добавлено: 06.01.10 13:42
На самом первом этапе разработки программы я предполагал использовать Таймер, по которому макрос будет заглядывать в интересующую меня ячейку каждую секунду, фиксировать изменения (если будут) и реагировать на них соответствующим образом. Но потом я подумал: "Это ж каждую секунду программа будет заглядывать в эту ячейку, ресурсов много будет расходоваться впустую. А кроме того, возможны (хотя это очень маловероятно) резкие изменения значения этой ячейки ВНУТРИ 1-секундного промежутка, которые программа "прозевает"...

А потом меня озарило: "Можно же транслировать значение из этой ячейки на отдельный, "персонально" для неё выделенный лист, а там "ловить" событие Worksheet_Change"... Но оказалось, что не всё так просто :( Теперь впору снова возвращаться к идее Таймера. Так ресурсов будет расходоваться гораздо меньше относительно вот такого подхода:

  1. Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
  2.   If Sheets("Лист2").Cells(1, 1).Value = m Then Exit Sub
  3.   m = Sheets("Лист2").Cells(1, 1).Value
  4.   Beep
  5. End Sub

 
Кстати, я уже на трёх(!) форумах поднял этот вопрос, и только на одном (на вашем!) хоть как-то пытаются помочь. На самом деле, большое вам спасибо!

Ответить

Номер ответа: 13
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #13 Добавлено: 07.01.10 22:45
Кому интересно, я ответ нашёл на свой вопрос!!! На одном форуме мне подсказали...

В данном случае событие Worksheet_Change для второго листа и не генерируется...

На втором листе используйте событие
Код:

Private Sub Worksheet_Calculate()
' Срабатывает пересчёт формул на листе
End Sub

Ответить

Номер ответа: 14
Автор ответа:
 hip



Вопросов: 3
Ответов: 22
 Профиль | | #14 Добавлено: 07.01.10 23:10
М-да, ларчик то просто открывался. Вот всегда так получается.

Ответить

Номер ответа: 15
Автор ответа:
 Олег



Вопросов: 9
Ответов: 30
 Профиль | | #15 Добавлено: 07.01.10 23:23
Я над этим "ларчиком" полгода пыхтел! Ну правда с перерывами :)
А на том форуме создал такую же тему около часа тому назад, - просто всё из этой темы тупо скопировал туда. А там модератор - 30-летний парнишка с Урала - ответил сразу же через несколько минут после того, как я тему создал! В результате, у той (аналогичной!) темы всего два просмотра было и один ответ! Но какой ответ!!!

Ответить

Страница: 1 | 2 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам