Controles ActiveX MFC: pintando um controle ActiveX
Este artigo descreve o processo de pintura de controle ActiveX e como é possível alterar o código de pintura para otimizar o processo. (Consulte Otimizar o desenho de controle para obter as técnicas sobre como otimizar o desenho sem que os controles restaurem de modo individual os objetos GDI selecionados anteriormente. Depois que todos os controles forem desenhados, o contêiner poderá restaurar automaticamente os objetos originais.)
Importante
O ActiveX é uma tecnologia herdada que não deve ser usada para novo desenvolvimento. Para mais informações sobre tecnologias modernas que substituem o ActiveX, confira Controles do ActiveX.
Os exemplos neste artigo são de um controle criado pelo Assistente de Controle ActiveX do MFC com configurações padrão. Para obter mais informações sobre como criar um aplicativo de controle de esqueleto usando o Assistente de Controle ActiveX do MFC, consulte o artigo Assistente de Controle ActiveX do MFC.
Os seguintes tópicos são abordados:
O processo de pintura de um controle ActiveX
Quando os controles ActiveX são exibidos inicialmente ou redesenhados, eles seguem um processo de pintura semelhante a outros aplicativos desenvolvidos usando MFC, com uma distinção importante: os controles ActiveX poderão estar em um estado ativo ou inativo.
Um controle ativo é representado em um contêiner de controle ActiveX por uma janela filho. Como outras janelas, será responsável por pintar a si mesma quando uma mensagem WM_PAINT for recebida. A classe base do controle, COleControl, trata essa mensagem na função OnPaint
. Essa implementação padrão chama a função OnDraw
do controle.
Um controle inativo é pintado de forma diferente. Quando o controle estiver inativo, a janela ficará invisível ou inexistente, portanto, não poderá receber uma mensagem de pintura. Em vez disso, o contêiner de controle chama diretamente a função OnDraw
do controle. Isso difere do processo de pintura de um controle ativo em que a função membro OnPaint
nunca é chamada.
Conforme discutido nos parágrafos anteriores, como um controle ActiveX é atualizado depende do estado do controle. No entanto, como a estrutura chama a função membro OnDraw
, em ambos os casos você adicionará a maior parte do código de pintura nessa função membro.
A função membro OnDraw
manipula a pintura de controle. Quando um controle está inativo, o contêiner de controle chama OnDraw
, passando o contexto de dispositivo do contêiner de controle e as coordenadas da área retangular ocupada pelo controle.
O retângulo passado pela estrutura à função membro OnDraw
contém a área ocupada pelo controle. Se o controle estiver ativo, o canto superior esquerdo será (0, 0) e o contexto de dispositivo passado será para a janela filho que contém o controle. Se o controle estiver inativo, a coordenada superior esquerda não será necessariamente (0, 0) e o contexto do dispositivo passado será para o contêiner de controle que contém o controle.
Observação
É importante que as modificações no OnDraw
não dependam que o ponto superior esquerdo do retângulo seja igual a (0, 0) e que você desenhe apenas dentro do retângulo passado para o OnDraw
. Resultados inesperados poderão ocorrer se você desenhar além da área do retângulo.
A implementação padrão fornecida pelo Assistente de Controle ActiveX do MFC no arquivo de implementação de controle (.CPP), mostrado abaixo, pinta o retângulo com um pincel branco e preenche a elipse com a cor da tela de fundo atual.
void CMyAxUICtrl::OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& /*rcInvalid*/)
{
if (!pdc)
return;
// TODO: Replace the following code with your own drawing code.
pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
pdc->Ellipse(rcBounds);
}
Observação
Ao pintar um controle, não faça suposições sobre o estado do contexto do dispositivo que é passado como parâmetro pdc para a função OnDraw
. Ocasionalmente, o contexto do dispositivo é fornecido pelo aplicativo de contêiner e não será necessariamente inicializado no estado padrão. Em particular, selecione explicitamente as canetas, os pincéis, as cores, as fontes e outros recursos dos quais o código de desenho depende.
Otimizar o código de pintura
Depois que o controle estiver se pintando com êxito, a próxima etapa será otimizar a função OnDraw
.
A implementação padrão da pintura de controle ActiveX pinta toda a área de controle. Isso é suficiente para controles simples, mas, em muitos casos, repintar o controle será mais rápido se apenas a parte que precisa de atualização for repintada, em vez de todo o controle.
A função OnDraw
fornece um método fácil de otimização passando rcInvalid, a área retangular do controle a ser redesenhada. Use essa área, geralmente menor que toda a área de controle, para acelerar o processo de pintura.
Pintar o controle usando metarquivos
Na maioria dos casos, o parâmetro pdc para a função OnDraw
aponta para um contexto de DC (dispositivo de tela). No entanto, ao imprimir as imagens do controle ou durante uma sessão de visualização de impressão, o DC recebido para renderização será um tipo especial chamado "DC de metarquivo". Ao contrário de um DC de tela, que trata imediatamente de solicitações enviadas a ele, um DC de metarquivo armazena as solicitações que serão reproduzidas posteriormente. Alguns aplicativos de contêiner também poderão optar por renderizar a imagem de controle usando um DC de metarquivo, quando estiver em modo de design.
As solicitações de desenho de metarquivo poderão ser feitas pelo contêiner por meio de duas funções de interface: IViewObject::Draw
(essa função também pode ser chamada para desenho não metarquivo) e IDataObject::GetData
. Quando um DC de metarquivo é passado como um dos parâmetros, a estrutura do MFC faz uma chamada para COleControl::OnDrawMetafile. Como essa é uma função membro virtual, substitua essa função na classe de controle para fazer qualquer processamento especial. O comportamento padrão chama COleControl::OnDraw
.
Para garantir que o controle poderá ser desenhado em contextos de dispositivo de tela e metarquivo, use apenas funções membro com suporte em uma tela e um DC de metarquivo. Lembre-se de que o sistema de coordenadas não pode ser medido em pixels.
Como a implementação padrão de OnDrawMetafile
chama a função OnDraw
, use apenas funções membro adequadas tanto para um contexto de dispositivo de tela quanto de metarquivo, a menos que você substitua OnDrawMetafile
. A seguir, lista o subconjunto de funções membro do CDC
que podem ser usadas em um contexto de dispositivo de tela e em um de metarquivo. Para obter mais informações sobre essas funções, consulte a classe CDC na Referência do MFC.
Arc | BibBlt | Acorde |
---|---|---|
Ellipse |
Escape |
ExcludeClipRect |
ExtTextOut |
FloodFill |
IntersectClipRect |
LineTo |
MoveTo |
OffsetClipRgn |
OffsetViewportOrg |
OffsetWindowOrg |
PatBlt |
Pie |
Polygon |
Polyline |
PolyPolygon |
RealizePalette |
RestoreDC |
RoundRect |
SaveDC |
ScaleViewportExt |
ScaleWindowExt |
SelectClipRgn |
SelectObject |
SelectPalette |
SetBkColor |
SetBkMode |
SetMapMode |
SetMapperFlags |
SetPixel |
SetPolyFillMode |
SetROP2 |
SetStretchBltMode |
SetTextColor |
SetTextJustification |
SetViewportExt |
SetViewportOrg |
SetWindowExt |
SetWindowORg |
StretchBlt |
TextOut |
Além das funções membro de CDC
, há várias outras funções compatíveis em um DC de metarquivo. Essas incluem CPalette::AnimatePalette, CFont::CreateFontIndirect e três funções membro de CBrush
: CreateBrushIndirect, CreateDIBPatternBrush, and CreatePatternBrush.
As funções que não são registradas em um metarquivo são: DrawFocusRect, DrawIcon, DrawText, ExcludeUpdateRgn, FillRect, FrameRect, GrayString, InvertRect, ScrollDC e TabbedTextOut. Como um DC de metarquivo não é realmente associado a um dispositivo, não é possível usar SetDIBits, GetDIBits e CreateDIBitmap com um DC de metarquivo. É possível usar SetDIBitsToDevice e StretchDIBits com um DC de metarquivo como o destino. CreateCompatibleDC, CreateCompatibleBitmap e CreateDiscardableBitmap não são significativos com um DC de metarquivo.
Outro ponto a ser considerado ao usar um DC de metarquivo é que o sistema de coordenadas não pode ser medido em pixels. Por esse motivo, todo o código de desenho deverá ser adaptado para ajustar no retângulo passado para OnDraw
no parâmetro rcBounds. Isso evitará a pintura acidental fora do controle porque rcBounds representa o tamanho da janela do controle.
Após implementar a renderização de metarquivo para o controle, use o Contêiner de Teste para testar o metarquivo. Confira Testar Propriedades e Eventos com o Contêiner de Testes para obter informações sobre como acessar o contêiner de testes.
Testar o metarquivo do controle usando o Contêiner de Teste
No menu Editar do Contêiner de Teste, clique em Inserir Novo Controle.
Na caixa Inserir Novo Controle, selecione o controle e clique em OK.
O controle aparecerá no contêiner de teste.
No menu Controle, clique em Desenhar Metarquivo.
Uma janela separada aparecera na qual o metarquivo será exibido. É possível alterar o tamanho dessa janela para ver como o dimensionamento afetará o metarquivo do controle. Você poderá fechar essa janela a qualquer momento.