Adicionando um evento (Tutorial ATL, parte 5)

Nesta etapa, você adicionará um evento ClickIn e um ClickOut ao controle da ATL. Você disparará o evento ClickIn se o usuário clicar no polígono e disparará ClickOut se o usuário clicar do lado de fora. As tarefas para adicionar um evento são as seguintes:

  • Adicionar os métodos ClickIn e ClickOut

  • Gerar a biblioteca de tipos

  • Implementar as interfaces do ponto de conexão

Adicionar os métodos ClickIn e ClickOut

Quando você criou o controle ATL na etapa 2, selecionou a caixa de seleção Pontos de conexão. Isso criou a interface _IPolyCtlEvents no arquivo Polygon.idl. Observe que o nome da interface começa com um sublinhado. Essa é uma convenção para indicar que a interface é uma interface interna. Assim, os programas que permitem navegar por objetos COM podem optar por não exibir a interface para o usuário. Observe também que selecionar Pontos de conexão adicionou a seguinte linha no arquivo Polygon.idl para indicar que _IPolyCtlEvents é a interface de origem padrão:

[default, source] dispinterface _IPolyCtlEvents;

O atributo de origem indica que o controle é a origem das notificações, portanto, ele chamará essa interface no contêiner.

Agora, adicione os métodos ClickIn e ClickOut à interface _IPolyCtlEvents.

Adicionar os métodos ClickIn e ClickOut

  1. Em Gerenciador de Soluções, abra Polygon.idl e adicione o seguinte código em methods: na declaração dispInterface_IPolyCtlEvents da biblioteca PolygonLib:

    [id(1), helpstring("method ClickIn")] void ClickIn([in] LONG x,[in] LONG y);
    [id(2), helpstring("method ClickOut")] void ClickOut([in] LONG x,[in] LONG y);
    

Os métodos ClickIn e ClickOut tomam as coordenadas x e y do ponto clicado como parâmetros.

Gerar a biblioteca de tipos

Gere a biblioteca de tipos neste momento, pois o projeto a usará para obter as informações necessárias para construir uma interface de ponto de conexão e uma interface de contêiner do ponto de conexão para o controle.

Gerar a biblioteca de tipos

  1. Recompile o projeto.

    -ou-

  2. Clique com o botão direito do mouse no arquivo Polygon.idl no Gerenciador de Soluções e clique em Compilar no menu de atalho.

Isso criará o arquivo Polygon.tlb, que é sua biblioteca de tipos. O arquivo Polygon.tlb não está visível no Gerenciador de Soluções, pois é um arquivo binário e não pode ser exibido ou editado diretamente.

Implementar as interfaces do ponto de conexão

Implemente uma interface de ponto de conexão e uma interface de contêiner do ponto de conexão para seu controle. No COM, os eventos são implementados por meio do mecanismo de pontos de conexão. Para receber eventos de um objeto COM, um contêiner estabelece uma conexão de consultoria com o ponto de conexão que o objeto COM implementa. Como um objeto COM pode ter vários pontos de conexão, o objeto COM também implementa uma interface de contêiner do ponto de conexão. Por meio dessa interface, o contêiner pode determinar quais pontos de conexão têm suporte.

A interface que implementa um ponto de conexão é chamada IConnectionPoint, e a interface que implementa um contêiner de ponto de conexão é chamada IConnectionPointContainer.

Para ajudar a implementar IConnectionPoint, você usará o Assistente para Implementar Ponto de Conexão. Esse assistente gera a interface IConnectionPoint lendo sua biblioteca de tipos e implementando uma função para cada evento que pode ser acionado.

Implementar os pontos de conexão

  1. Em Gerenciador de Soluções, abra _IPolyCtlEvents_CP.h e adicione o seguinte código na instrução public: na classe CProxy_IPolyCtlEvents:

    VOID Fire_ClickIn(LONG x, LONG y)
    {
        T* pT = static_cast<T*>(this);
        int nConnectionIndex;
        CComVariant* pvars = new CComVariant[2];
        int nConnections = m_vec.GetSize();
    
        for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
        {
            pT->Lock();
            CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
            pT->Unlock();
            IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
            if (pDispatch != NULL)
            {
                pvars[1].vt = VT_I4;
                pvars[1].lVal = x;
                pvars[0].vt = VT_I4;
                pvars[0].lVal = y;
                DISPPARAMS disp = { pvars, NULL, 2, 0 };
                pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
            }
        }
        delete[] pvars;
    
    }
    VOID Fire_ClickOut(LONG x, LONG y)
    {
        T* pT = static_cast<T*>(this);
        int nConnectionIndex;
        CComVariant* pvars = new CComVariant[2];
        int nConnections = m_vec.GetSize();
    
        for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
        {
            pT->Lock();
            CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
            pT->Unlock();
            IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
            if (pDispatch != NULL)
            {
                pvars[1].vt = VT_I4;
                pvars[1].lVal = x;
                pvars[0].vt = VT_I4;
                pvars[0].lVal = y;
                DISPPARAMS disp = { pvars, NULL, 2, 0 };
                pDispatch->Invoke(0x2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
            }
        }
        delete[] pvars;
    
    }
    

Você verá que esse arquivo tem uma classe chamada CProxy_IPolyCtlEvents que deriva de IConnectionPointImpl. _IPolyCtlEvents_CP.h agora define os dois métodos Fire_ClickIn e Fire_ClickOut, que tomam os dois parâmetros de coordenada. Você chama esses métodos quando deseja disparar um evento do seu controle.

Ao criar o controle com a opção Pontos de conexão selecionada, o arquivo _IPolyCtlEvents_CP.h foi gerado para você. Ele também adicionou CProxy_PolyEvents e IConnectionPointContainerImpl à lista de várias heranças do controle e expôs IConnectionPointContainer para você adicionando entradas apropriadas ao mapa COM.

Você terminou de implementar o código para dar suporte a eventos. Agora, adicione algum código para disparar os eventos no momento apropriado. Lembre-se de que você vai disparar um evento ClickIn ou ClickOut quando o usuário clicar no botão esquerdo do mouse no controle. Para descobrir quando o usuário clica no botão, adicione um manipulador para a mensagem WM_LBUTTONDOWN.

Adicionar um manipulador para a mensagem WM_LBUTTONDOWN

  1. No Modo de Exibição de Classe, clique com o botão direito do mouse em CPolyCtl e clique em Propriedades no menu de atalho.

  2. Na janela Propriedades, clique no ícone Mensagens e clique em WM_LBUTTONDOWN na lista à esquerda.

  3. Na lista suspensa que é exibida, clique em <Adicionar> OnLButtonDown. A declaração do manipulador OnLButtonDown será adicionada ao PolyCtl.h e a implementação do manipulador ao PolyCtl.cpp.

Em seguida, modifique o manipulador.

Modificar o método OnLButtonDown

  1. Altere o código que compreende o método OnLButtonDown em PolyCtl.cpp (excluindo qualquer código colocado pelo assistente) para que ele tenha esta aparência:

    LRESULT CPolyCtl::OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, 
       BOOL& /*bHandled*/)
    {
       HRGN hRgn;
       WORD xPos = LOWORD(lParam);  // horizontal position of cursor
       WORD yPos = HIWORD(lParam);  // vertical position of cursor
    
       CalcPoints(m_rcPos);
    
       // Create a region from our list of points
       hRgn = CreatePolygonRgn(&m_arrPoint[0], m_nSides, WINDING);
    
       // If the clicked point is in our polygon then fire the ClickIn
       //  event otherwise we fire the ClickOut event
       if (PtInRegion(hRgn, xPos, yPos))
          Fire_ClickIn(xPos, yPos);
       else
          Fire_ClickOut(xPos, yPos);
    
       // Delete the region that we created
       DeleteObject(hRgn);
       return 0;
    }
    

Esse código usa os pontos calculados na função OnDraw para criar uma região que detecta cliques do mouse do usuário com a chamada para PtInRegion.

O parâmetro uMsg é a ID da mensagem do Windows que está sendo tratada. Isso permite que você tenha uma função que manipula um intervalo de mensagens. Os parâmetros wParam e lParam são os valores padrão para a mensagem que está sendo tratada. O parâmetro bHandled permite que você especifique se a função lidou com a mensagem ou não. Por padrão, o valor é definido como TRUE para indicar que a função lidou com a mensagem, mas você pode defini-la como FALSE. Isso fará com que a ATL continue procurando outra função de manipulador de mensagens para a qual enviar a mensagem.

Compilação e teste do controle

Agora experimente seus eventos. Crie o controle e inicie o Contêiner de Teste de Controle ActiveX novamente. Desta vez, exiba a janela do log de eventos. Para rotear eventos para a janela de saída, clique em Registrar em log no menu Opções e selecione Registrar na janela de saída. Insira o controle e tente clicar na janela. Observe que ClickIn será acionado se você clicar no polígono preenchido e ClickOut será acionado quando clicar fora dele.

Em seguida, você adicionará uma página de propriedades.

Voltar para a Etapa 4 | Na Etapa 6

Confira também

Tutorial