Alteração do código de desenho (Tutorial ATL, parte 4)

Por padrão, o código de desenho do controle exibe um quadrado e o texto PolyCtl. Nesta etapa, você alterará o código para exibir algo mais interessante. As seguintes tarefas estão envolvidas:

  • Modificar o arquivo de cabeçalho

  • Modificar a função OnDraw

  • Adicionar um método para calcular os pontos de polígono

  • Inicializar a cor de preenchimento

Modificar o arquivo de cabeçalho

Comece adicionando suporte para as funções matemáticas sin e cos (que serão usadas para calcular os pontos de polígono) e criando uma matriz para armazenar posições.

Para modificar o arquivo de cabeçalho

  1. Adicione a linha #include <math.h> à parte superior do PolyCtl.h. A parte superior do arquivo deve ter esta aparência:

    #include <math.h>
    #include "resource.h"       // main symbols
    
  2. Implemente a interface IProvideClassInfo para fornecer informações de método para o controle, adicionando o código a seguir ao PolyCtl.h. Na classe CPolyCtl, substitua a linha:

    public CComControl<CPolyCtl>
    

    por

    public CComControl<CPolyCtl>,
    public IProvideClassInfo2Impl<&CLSID_PolyCtl, &DIID__IPolyCtlEvents, &LIBID_PolygonLib>
    

    e, em BEGIN_COM_MAP(CPolyCtl), adicione as linhas:

    COM_INTERFACE_ENTRY(IProvideClassInfo)
    COM_INTERFACE_ENTRY(IProvideClassInfo2)
    
  3. Depois que os pontos de polígono forem calculados, eles serão armazenados em uma matriz de tipo POINT, portanto, adicione a matriz após a instrução de definição short m_nSides; em PolyCtl.h:

    POINT m_arrPoint[100];
    

Modificando o método OnDraw

Agora você deve modificar o método OnDraw em PolyCtl.h. O código que você adicionará cria uma nova caneta e um pincel para desenhar seu polígono e, em seguida, chama as funções de API Ellipse e Polygon do Win32 para executar o desenho real.

Para modificar a função OnDraw

  1. Substitua o método OnDraw existente em PolyCtl.h pelo código a seguir:

    HRESULT CPolyCtl::OnDraw(ATL_DRAWINFO& di)
    {
       RECT& rc = *(RECT*)di.prcBounds;
       HDC hdc  = di.hdcDraw;
    
       COLORREF    colFore;
       HBRUSH      hOldBrush, hBrush;
       HPEN        hOldPen, hPen;
    
       // Translate m_colFore into a COLORREF type
       OleTranslateColor(m_clrFillColor, NULL, &colFore);
    
       // Create and select the colors to draw the circle
       hPen = (HPEN)GetStockObject(BLACK_PEN);
       hOldPen = (HPEN)SelectObject(hdc, hPen);
       hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
       hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
    
       Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
    
       // Create and select the brush that will be used to fill the polygon
       hBrush    = CreateSolidBrush(colFore);
       SelectObject(hdc, hBrush);
    
       CalcPoints(rc);
       Polygon(hdc, &m_arrPoint[0], m_nSides);
    
       // Select back the old pen and brush and delete the brush we created
       SelectObject(hdc, hOldPen);
       SelectObject(hdc, hOldBrush);
       DeleteObject(hBrush);
    
       return S_OK;
    }
    

Adicionar um método para calcular os pontos de polígono

Adicione um método, chamado CalcPoints, que calculará as coordenadas dos pontos que compõem o perímetro do polígono. Esses cálculos serão baseados na variável RECT que é passada para a função.

Para adicionar o método CalcPoints

  1. Adicione a declaração do CalcPoints para a seção pública IPolyCtl da classe CPolyCtl em PolyCtl.h:

    void CalcPoints(const RECT& rc);
    

    A última parte da seção pública da classe CPolyCtl terá esta aparência:

       void FinalRelease()
       {
       }
    public:
       void CalcPoints(const RECT& rc);
    
  2. Adicione essa implementação da função CalcPoints ao final de PolyCtl.cpp:

    void CPolyCtl::CalcPoints(const RECT& rc)
    {
       const double pi = 3.14159265358979;
       POINT   ptCenter;
       double  dblRadiusx = (rc.right - rc.left) / 2;
       double  dblRadiusy = (rc.bottom - rc.top) / 2;
       double  dblAngle = 3 * pi / 2;          // Start at the top
       double  dblDiff  = 2 * pi / m_nSides;   // Angle each side will make
       ptCenter.x = (rc.left + rc.right) / 2;
       ptCenter.y = (rc.top + rc.bottom) / 2;
    
       // Calculate the points for each side
       for (int i = 0; i < m_nSides; i++)
       {
          m_arrPoint[i].x = (long)(dblRadiusx * cos(dblAngle) + ptCenter.x + 0.5);
          m_arrPoint[i].y = (long)(dblRadiusy * sin(dblAngle) + ptCenter.y + 0.5);
          dblAngle += dblDiff;
       }
    }
    

Inicializar a cor de preenchimento

Inicialize m_clrFillColor com uma cor padrão.

Para inicializar a cor de preenchimento

  1. Use verde como a cor padrão adicionando esta linha ao construtor CPolyCtl em PolyCtl.h:

    m_clrFillColor = RGB(0, 0xFF, 0);
    

O construtor agora tem esta aparência:

CPolyCtl()
{
   m_nSides = 3;
   m_clrFillColor = RGB(0, 0xFF, 0);
}

Compilação e teste do controle

Recompile o controle. Verifique se o arquivo PolyCtl.htm está fechado. Em seguida, clique em Compilar Polígono no menu Compilar. Você pode exibir o controle mais uma vez na página PolyCtl.htm, mas desta vez use o Contêiner de Teste de Controle ActiveX.

Para usar o Contêiner de Teste de Controle ActiveX

  1. Compile e inicie o Contêiner de Teste de Controle ActiveX. O exemplo TSTCON: contêiner de teste de controle ActiveX pode ser encontrado no GitHub.

    Observação

    Para erros envolvendo ATL::CW2AEX, em Script.Cpp, substitua a linha TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT ); por TRACE( "XActiveScriptSite::GetItemInfo( %s )\n", pszNameT.m_psz ); e a linha TRACE( "Source Text: %s\n", COLE2CT( bstrSourceLineText ) ); por TRACE( "Source Text: %s\n", bstrSourceLineText );.
    Para erros envolvendo HMONITOR, abra StdAfx.h no projeto TCProps e substitua:

    #ifndef WINVER
    #define WINVER 0x0400
    #endif
    

    por

    #ifndef WINVER
    #define WINVER 0x0500
    #define _WIN32_WINNT 0x0500
    #endif
    
  2. No Contêiner de Teste, no menu Editar, clique em Inserir Novo Controle.

  3. Localize o controle, que será chamado PolyCtl class, e clique em OK. Você verá um triângulo verde dentro de um círculo.

Tente alterar o número de lados seguindo o próximo procedimento. Para modificar propriedades em uma interface dupla de dentro do Contêiner de Teste, use os Métodos de Invocação.

Para modificar a propriedade de controle de dentro do Contêiner de Teste

  1. No Contêiner de Teste, clique em Invocar Métodos no menu Controle.

    A caixa de diálogo Invocar Método é exibida.

  2. Selecione a versão PropPut da propriedade Sides na caixa de listagem suspensa Nome do Método.

  3. Digite 5 na caixa Valor do Parâmetro, clique em Definir Valor e clique em Invocar.

Observe que o controle não é alterado. Embora você tenha alterado o número de lados internamente definindo a variável m_nSides, isso não fez o controle se repintar. Se você alternar para outro aplicativo e voltar para o Contêiner de Teste, descobrirá que o controle foi repintado e tem o número correto de lados.

Para corrigir esse problema, adicione uma chamada à função FireViewChange, definida em IViewObjectExImpl, depois de definir o número de lados. Se o controle estiver em execução em sua própria janela, FireViewChange chamará o método InvalidateRect diretamente. Se o controle estiver executando sem janelas, o método InvalidateRect será chamado na interface do site do contêiner. Isso força o controle a se repintar.

Para adicionar uma chamada ao FireViewChange

  1. Atualize o PolyCtl.cpp adicionando a chamada FireViewChange ao método put_Sides. Quando você terminar, o método put_Sides deve ter esta aparência:

    STDMETHODIMP CPolyCtl::put_Sides(short newVal)
    {
       if (2 < newVal && newVal < 101)
       {
          m_nSides = newVal;
          FireViewChange();
          return S_OK;
       }
       else
       {
          return Error(_T("Shape must have between 3 and 100 sides"));
       }
    }
    

Depois de adicionar FireViewChange, recompile e tente o controle novamente no Contêiner de Teste de Controle ActiveX. Desta vez, ao alterar o número de lados e clicar em Invoke, você visualizará a alteração de controle imediatamente.

Na próxima etapa, você adicionará um evento.

Voltar para a Etapa 3 | Na Etapa 5

Confira também

Tutorial
Testando propriedades e eventos com contêiner de teste