Возможно ли вызвать событие у объекта не из самого объекта?

Для неординарных вопросов. Если вы опытный программист, попавший в трудную ситуацию, — вам сюда.

Модератор: gaidar

Правила форума
Этот раздел не предназначен для того, чтобы вы адресовали свою проблему профессионалам.
Этот раздел предназначен для профессионалов, которые столкнулись с проблемой и не могут решить ее самостоятельно.
Если вы считаете себя профессионалом, а свою проблему сложной — вам сюда.
Если модератор посчитает, что вы ошиблись, то на первый раз он перенесет ваше сообщение в основной раздел без последствий для автора. Во второй раз тема будет закрыта, а автору будет выписано нарушение. В третий раз автор будет забанен.
VDeltsov
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 23
Зарегистрирован: 30.07.2005 (Сб) 14:42
Откуда: Moscow

Возможно ли вызвать событие у объекта не из самого объекта?

Сообщение VDeltsov » 03.08.2006 (Чт) 19:44

Есть модуль, в котором написано куча всяких полезных функций.
Одна из функций принимает в качестве параметра объект (Control).
Нужно у этого объекта вызвать событие.
И вызвать так, чтобы его получили все подписчики.
Такое вообще возможно?


--------------------------------------------------------------------
----------Собственно пример, в котором это нужно--------------------
--------------------------------------------------------------------
В модуле Visual Basic 6.0, есть функция FGEnsureMouseRowColInSelection,
которую я вызываю по нажатию правой кнопкой мыши на FlexGrid-е
для того, чтобы убедиться, что мышкой нажали внутри выделения.
Если нажали не внутри выделения,
то на гриде выделяется та ячейка, на которой кликнули.
А после этого в другой функции этого же глобального модуля
я показываю контекстное меню, например с одним пунктом меню "копировать".

------------------------------------------------------------------------
Код: Выделить всё

Attribute VB_Name = "modFlexGrid"
Public Function FGEnsureMouseRowColInSelection(aFG As MSHFlexGrid) As Boolean
   
    If aFG.MouseCol < aFG.FixedCols Or aFG.MouseRow < aFG.FixedRows Then Exit Function
   
    If (aFG.MouseCol < aFG.Col And aFG.MouseCol < aFG.ColSel) _
    Or (aFG.MouseCol > aFG.Col And aFG.MouseCol > aFG.ColSel) _
    Or (aFG.MouseRow < aFG.Row And aFG.MouseRow < aFG.RowSel) _
    Or (aFG.MouseRow > aFG.Row And aFG.MouseRow > aFG.RowSel) Then

        aFG.Row = aFG.MouseRow
        aFG.Col = aFG.MouseCol
        aFG.ColSel = aFG.MouseCol
        aFG.RowSel = aFG.MouseRow

    End If
    FGEnsureMouseRowColInSelection = True
End Function

------------------------------------------------------------------------

На форме, где находится этот грид, по смене строки (RowColChange) этого грида
обновлются еще два зависимых списка.
Поскольку я меняю строку (aFG.Row) из кода, то событие RowColChange не возникает.
И из-за этого зависимые списки не обновляются, что приводит к недоразумениям.

Напоминаю, что модуль глобальный и функция используется по проекту много раз.

------------------------------------------------------------------------

Самое простое что придумал, это сделать в форме обработчик события публичным
Код: Выделить всё

Attribute VB_Name = "frmMain"
Public Sub FG_RowColChange()
    txtStatusBar.Text = FG.TextMatrix(FG.Row, FG.Col)
    Fill_FG1 'Обновить первый подчиненный список
    Fill_FG2 'Обновить второй подчиненный список
End Sub


А в функции вызвать у родительской формы метод FG_RowColChange:
Код: Выделить всё

Attribute VB_Name = "modFlexGrid"
Public Function FGEnsureMouseRowColInSelection(aFG As MSHFlexGrid) As Boolean
   
    If aFG.MouseCol < aFG.FixedCols Or aFG.MouseRow < aFG.FixedRows Then Exit Function
   
    If (aFG.MouseCol < aFG.Col And aFG.MouseCol < aFG.ColSel) _
    Or (aFG.MouseCol > aFG.Col And aFG.MouseCol > aFG.ColSel) _
    Or (aFG.MouseRow < aFG.Row And aFG.MouseRow < aFG.RowSel) _
    Or (aFG.MouseRow > aFG.Row And aFG.MouseRow > aFG.RowSel) Then

        aFG.Row = aFG.MouseRow
        aFG.Col = aFG.MouseCol
        aFG.ColSel = aFG.MouseCol
        aFG.RowSel = aFG.MouseRow
       
        On Error Resume Next
        CallByName aFG.Parent, aFG.Name & "_RowColChange", VbMethod
        On Error GoTo 0
    End If
    FGEnsureMouseRowColInSelection = True
End Function

------------------------------------------------------------------------

Все вроде ничего, но есть два существеннх минуса:
1. Если эту функцию будет использовать тот, которых не знает/не помнит,
что обработчик события FG_RowColChange нужно обязательно сделать публичным,
то событие опять не будет вызвано.
2. Этот же объект (грид) может быть передан в другие классы,
в которых тоже обрабатывается это же событие.
И вот в этом классе событие опять не будет вызвано
То есть при таком подходе я не могу вызвать событие так, чтобы его получили все подписчики.
------------------------------------------------------------------------


Собственно вопрос:
Если ли какая-нибудь API-функция (пирсущая именно FlexGrid-у)
или вообще абстрактная, как CallByName,
которая может у объекта вызвать событие, которое получат все его подписчики?

------------------------------------------------------------------------

Спасибо,
Василий Дельцов
icq 93396861
Код: Выделить всё

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 03.08.2006 (Чт) 19:51

Можно попытаться сымитировать клик мышью на нужной ячейке. Проблема лишь в вычислении её позиции. Клик имитируется через API'шку mouse_event, или SendMessage, с соответствующими параметрами.
Изображение

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 04.08.2006 (Пт) 9:37

Поскольку я меняю строку (aFG.Row) из кода, то событие RowColChange не возникает.
Можно сделать чтобы возникало. Вместо aFG.Row ставь на aFG фокус и делай SendKeys "{up}" или "{down}".
Лучший способ понять что-то самому — объяснить это другому.

VDeltsov
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 23
Зарегистрирован: 30.07.2005 (Сб) 14:42
Откуда: Moscow

Сообщение VDeltsov » 04.08.2006 (Пт) 10:45

Antonariy писал(а):
Поскольку я меняю строку (aFG.Row) из кода, то событие RowColChange не возникает.
Можно сделать чтобы возникало. Вместо aFG.Row ставь на aFG фокус и делай SendKeys "{up}" или "{down}".



>>>aFG.SetFocus
>>>SendKeys "{DOWN}"

Это не помогло, т.к. моя функция вызывается перед вызовом контекстного меню.
И поэтому это сообщение передается после окончания всего моего кода, то есть передается не гриду, а менюшке.
И при этом выделяется первая менюшка.

keks-n
Доктор VB наук
Доктор VB наук
Аватара пользователя
 
Сообщения: 2509
Зарегистрирован: 19.09.2005 (Пн) 17:17
Откуда: г. Москва

Сообщение keks-n » 04.08.2006 (Пт) 11:33

DoEvents после SendKeys?
Изображение

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.08.2006 (Пт) 11:47

А зачем? Уж лучше второй аргумент как True передать.
А еще лучше Invoke сделать.
Но как это на VB сделать, не подскажу.
Lasciate ogni speranza, voi ch'entrate.

tyomitch
Пользователь #1352
Пользователь #1352
Аватара пользователя
 
Сообщения: 12822
Зарегистрирован: 20.10.2002 (Вс) 17:02
Откуда: חיפה

Сообщение tyomitch » 04.08.2006 (Пт) 12:27

прошу пояснения, Invoke чего и у чего вы собрались вызывать?
Изображение

VDeltsov
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 23
Зарегистрирован: 30.07.2005 (Сб) 14:42
Откуда: Moscow

Сообщение VDeltsov » 04.08.2006 (Пт) 12:51

alibek писал(а):А зачем? Уж лучше второй аргумент как True передать.
А еще лучше Invoke сделать.
Но как это на VB сделать, не подскажу.



Да, вот так ПОМОГЛО.

Код: Выделить всё

Attribute VB_Name = "modFlexGrid"
Public Function FGEnsureMouseRowColInSelection(aFG As MSHFlexGrid) As Boolean
    Dim fRedraw As Boolean

    If aFG.MouseCol < aFG.FixedCols Or aFG.MouseRow < aFG.FixedRows Then Exit Function
   
    If (aFG.MouseCol < aFG.Col And aFG.MouseCol < aFG.ColSel) _
    Or (aFG.MouseCol > aFG.Col And aFG.MouseCol > aFG.ColSel) _
    Or (aFG.MouseRow < aFG.Row And aFG.MouseRow < aFG.RowSel) _
    Or (aFG.MouseRow > aFG.Row And aFG.MouseRow > aFG.RowSel) Then

        'Ищу свободную соседнюю ячейку,
        'выделяю ее и жму кнопку "вправо", "влево", "вверх" или "вниз".
        'Для того, чтобы ничего не мигало, прорисовку отключаем.
       
        fRedraw = aFG.Redraw
        aFG.Redraw = False
       
        If aFG.MouseRow > aFG.FixedRows Then
            aFG.Row = aFG.MouseRow - 1
            aFG.Col = aFG.MouseCol
            aFG.ColSel = aFG.MouseCol
            aFG.RowSel = aFG.MouseRow - 1
           
            aFG.SetFocus
            SendKeys "{DOWN}", True
        ElseIf aFG.MouseRow < aFG.Rows - 1 Then
            aFG.Row = aFG.MouseRow + 1
            aFG.Col = aFG.MouseCol
            aFG.ColSel = aFG.MouseCol
            aFG.RowSel = aFG.MouseRow + 1
           
            aFG.SetFocus
            SendKeys "{UP}", True
        ElseIf aFG.MouseCol > aFG.FixedCols Then
            aFG.Row = aFG.MouseRow
            aFG.Col = aFG.MouseCol - 1
            aFG.ColSel = aFG.MouseCol - 1
            aFG.RowSel = aFG.MouseRow
           
            aFG.SetFocus
            SendKeys "{RIGHT}", True
        ElseIf aFG.MouseCol < aFG.Cols - 1 Then
            aFG.Row = aFG.MouseRow
            aFG.Col = aFG.MouseCol + 1
            aFG.ColSel = aFG.MouseCol + 1
            aFG.RowSel = aFG.MouseRow
           
            aFG.SetFocus
            SendKeys "{LEFT}", True
        End If
       
        If Not aFG.Redraw = fRedraw Then aFG.Redraw = fRedraw
    End If
    FGEnsureMouseRowColInSelection = True
End Function

VDeltsov
Начинающий
Начинающий
Аватара пользователя
 
Сообщения: 23
Зарегистрирован: 30.07.2005 (Сб) 14:42
Откуда: Moscow

Сообщение VDeltsov » 04.08.2006 (Пт) 12:54

А вообще принципиально возможно съимитировать событие объекта, находясь вне него? Или это теоретически невозможно?

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.08.2006 (Пт) 12:55

tyomitch писал(а):прошу пояснения, Invoke чего и у чего вы собрались вызывать?

Это я не то сказанул :)
Lasciate ogni speranza, voi ch'entrate.

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 04.08.2006 (Пт) 12:58

VDeltsov писал(а):Или это теоретически невозможно?

Возможно.
Почитай статью Events in COM в MSDN.
Только там много букв.
Lasciate ogni speranza, voi ch'entrate.

Antonariy
Повелитель Internet Explorer
Повелитель Internet Explorer
Аватара пользователя
 
Сообщения: 4824
Зарегистрирован: 28.04.2005 (Чт) 14:33
Откуда: Мимо проходил

Сообщение Antonariy » 04.08.2006 (Пт) 13:10

А я бы вынес aFG.SetFocus перед If. Но это уже мелочь.
Лучший способ понять что-то самому — объяснить это другому.


Вернуться в Раздел для Профессионалов

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

    TopList