Projeto paint

OBS: Este tutorial foi retirado do site DicasBCB

Clique em File e depois em New Application.
D
ê um clique sobre o menu File na Barra de Menus e escolha a opção Save All.
No diretório de sua preferência, salve a Unit com o nome de Guia.cpp e o projeto com o nome de Guia1.brp.
Pegue um componente TollBar da paleta Win32 (ou Win95) e coloque no Formulário (Form).
Na paleta Addtional, pegue sete SpeedButton, e coloque no Toolbar; pegue dois Shape na paleta Additional e coloque no TollBar.
Coloque, ainda, no ToolBar, um CColorGrid, da paleta de componentes Samples.
Defina a propriedade GridOdering,de CColorGrid para go16x1.
Procure deixar o formulário com a seguinte aparência:

 

Agora vamos preparar o projeto para receber uma janela filha. Selecione o Formulário e ajuste a propriedade FormStyle para fsMDIForm.
Ajuste a propriedadeCaption para Meu Pincel e a Name para FrmPncel.
Para criar um form MDI filho, adicione um novo form ao projeto (File | New Form).
Ajuste a propriedade FormStyle desse form para fsMDIChild, a propriedade Name para EdtDesenh e deixe a propriedade Caption sem nome.
Para criar um menu em nosso projeto, podemos utilizar o componenteMainMenu e o Menu Designer, do mesmo modo que fizemos em nosso editor de textos como o componente PopupMenu.
No entanto, como agora se trata de uma aplicação MDI, podemos adicionar algumas funcionalidades que determinarão uma junção dos menus das janelas abertas, o que permitirá que os itens do menu da janela Pai estejam disponíveis quando o foco estiver na janela filha.
Adicione um componente MainMenu ao Form principal (FrmPncel); Utilize o Menu Designer para criar os menus Arquivo, Janela e respectivos itens mostrados abaixo:

Arquivo

Janela

Novo

Lado a Lado Horizontalmente

Abrir

Lado a Lado Verticalmente

-

Cascata

Sair

Reorganizar Ícones

Vamos criar um menu para a janela filha. Adicione um componente MainMenu à janela filha (EdtDsnh). Utilize o Menu Designer para criar os menus Arquivo, Editar e respectivos itens mostrados abaixo:

Arquivo

Editar

Novo

Cortar

Abrir

Copiar

Fechar

Colar

Salvar

Deletar

Salvar Como

-

-

Selecionar Tudo

Imprimir

 

Configurar Impressora

 

Sair

 

Coloque atalhos para os itens do menu Arquivo e Editar. Tenha o cuidado de colocar os mesmos atalhos para os menus que se repetem nas janelas pai e filha.

Se você rodar a aplicação agora, vai notar que a janela filha aparece dentro da janela pai. Outra coisa que notará é que a barra de menus da janela filha substitui a barra de menus da janela pai. Cabe-nos providenciar, agora, a junção dos itens dos menus da janela pai com os itens dos menus da janela filha.

Vamos igualar a propriedade GroupIndex para os menus que desejamos integrantes de um mesmo grupo. Devemos respeitar algumas regras básicas: o valor (número) de um grupo (GroupIndex) é igual ou ascendente da esquerda para a direita (Ex: Arquivo = 0, Editar = 1, Janela = 2 etc); o grupo da janela pai que possuir o mesmo valor de GroupIndex da janela filha será substituído pelo grupo desta; após a junção, a localização dos menus será determinada pelo valor dos grupos - ascendente da esquerda para a direita.
Em posse dessas informações, vamos alterar os GroupIndex dos menus, conforme exposto a seguir:

FrmPncel

Arquivo - GroupIndex = 0

Janela - GroupIndex= 2

EdtDsnh

Arquivo - GroupIndex = 0

Editar - GroupIndex= 1

No menu Sair da janela pai digite a função Close() para encerrar o programa:

void __fastcallTFrmPncel::Sair1Click(TObject *Sender) 
{
Close();  // Encerra o programa
}

Faça um teste e veja que nada acontece quando você tentar usar o menu Sair. Isso porque os menus das janelas não compartilham o evento. Vamos, então, anexar um manipulador de eventos ao OnClick do menu Arquivo - Sair do EdtDsnh.

void __fastcallTedtDsnh::Sair1Click(TObject *Sender) 
{
 FrmPncel->SairClick(Sender); /*Chama o método SairClick
de FrmPncel*/
}
 
    
        

Nota:
O ramo TObject

Todos os objetos da VCL descendem de TObject , uma classe abstrata cujos métodos definem os comportamentos fundamentais como construção, destruição e tratamento de mensagens. A maior parte das poderosas capacidades dos objetos VCL é estabelecida pelos métodos que TObject introduz. TObject encapsula os comportamentos fundamentais comum a todos os objetos na VCL, apresentando métodos que provêem: a capacidade de responder quando objetos são criadas ou destruídos; informação de instância num objeto e informação em tempo de execução (RTTI ) acerca dessas propriedades públicas; suporte para tratamento de mensagens.

Esse ramo inclui diversos e diferentes tipos de classes que são muito úteis quando você está desenvolvendo aplicações.

Na linha de código:

void __fastcallTFrmPncel::Sair1Click(TObject *Sender)

Temos a declaração de um ponteiro do tipo TObject cujo nome é Sender (poderia ser outro nome qualquer que respeite as limitações impostas por C++). Daí temos o tipo de parâmetro passado pela função:
FrmPncel->SairClick(Sender);
ser o TObject. Se você observar bem, verá que esse também é o tipo recebido por:

void __fastcallTFrmPncel::Sair1Click(TObject *Sender) 

Dessa forma, conseguimos chamar o método sair de TfrmPncel, desde TedtDsnh, o qual será o responsável pelo encerramento do programa através da chamada da função Close().
A função Close() inserida dentro de uma janela filha provoca o fechamento desta janela; se colocada na janela principal, o encerramento do programa.

 
        

Tente rodar a aplicação. O compilador emitirá uma mensagem de erro acusando que FrmPncel não está definido. Devemos, então, adicionar o arquivo de cabeçalho correspondente. No meu compilador, ele ficou definido como Meu_Paint.h. Faça o seguinte: De um clique em File e depois em Include Unid Hdr... Na caixa de diálogo que se abrir, escolha o arquivo correspondente e dê um OK. Rode a aplicação e veja que o programa já encerra via menu Sair.

Ao rodar a aplicação, você deve ter notado que a janela filha está sendo criada automaticamente na inicialização do programa. Vamos mudar essa sistemática.
Dê um clique em Project, e depois em Options. Na paleta Formda caixa que se abrir, vamos alterar a lista Auto-create forms. Selecione EdtDsnh e dê um clique na seta >, o que fará que EdtDsnh seja movido para a janela Available forms. Dê um OK e pronto, a janela filha já não mais inicializa mais automaticamente.
Agora vamos incluir os códigos necessários à criação das janelas filhas em tempo de execução:

void __fastcall TFrmPncel::Novo1Click(TObject *Sender) 
{
new TEdtDsnh(this); //Cria janela filha em tempo de execução
}

Quando um programa é executado, o sistema operacional reserva um espaço de memória para o código (ou instruções do programa) e outro espaço para as variáveis usadas durante a execução. De um modo geral, esses espaços ocupam uma mesma região, que podemos denominar memória local. Também existem outras zonas de memória, como a pilha, usada, entre outras coisas, para realizar o intercâmbio de dados entre as funções. O resto, a memória que não estiver em uso por nenhum programa, é o que se conhece por memória livre (área de alocação dinâmica, heap ou free store). Quando um programa usa a área de alocação dinâmica, naturalmente estará usando parte desse resto de memória.

O maior poder esperado na utilização de ponteiros decorre talvez, justamente, de seu uso junto a esse conceito de alocação de memória no free store.

C++ dispõe de dois operadores que atuam em conjunto para acesso à memória dinâmica: new e delete. O operador new oferece um meio para alocação de espaço na memória livre, de uma forma parecida, porém muito superior àquela alocação oferecida pela função malloc() da livraria padrão da linguagem C. O operador new precisa, necessariamente, ser suprido com o tipo de dados para o qual está alocando memória, a fim de que o compilador saiba exatamente quanta memória deverá reservar para colocar os dados no heap. O operador delete é o meio tradicional fornecido por C++ de liberar a memória alocada pelo operador new.

Em funções-membros não static, a palavra-chave this é um ponteiro que contém o endereço do objeto pelo qual a função-membro é chamada. Toda chamada a funções-membros não static passa o ponteiro this como um argumento oculto.

this é uma variável local disponível no corpo de qualquer função-membro não static. Use this implicitamente dentro da função para referências de membros. this não precisa ser declarado e raramente é referido explicitamente na definição de uma função. No código acimathis determina que a janela filha pertença à janela pai. Em determinadas situação, se quiséssemos que o objeto pertencesse a outro componente diferente do formulário em que se encontra, deveríamos trocar a palavra-chavethis pelo nome do componente ao qual queremos que o objeto pertença.

void __fastcallTEdtDsnh::Novo1Click(TObject *Sender) 
{
//Chama o método NovoClick de FrmPncel
FrmPncel->Novo1Click (Sender);  
}

Podemos usar OnClose para efetuar algum processo especial no fechamento do form. O evento OnClose especifica qual o evento handler será chamado quando o form estiver quase fechado. O handler especificado em OnClose pode ser usado para forçar, por exemplo, um teste para verificar se todos os campos de entrada de dados num form possuem conteúdo válido, antes de permitir que o form seja encerrado.

Um form é fechado pelo método Close ou quando o usuário escolhe Fechar desde o system menu do form.

O tipo TCloseEvent aponta para o método que trata o fechamento do form. O valor do parâmetro Action determina se o form realmente fecha. Esses são os possíveis valores do parâmetro Action: caNone, caHide, caFree e caMinimize.

void __fastcallTEdtDsnh::FormClose(TObject *Sender,TCloseAction &Action) 
{
// Libera os recursos alocados na criação da janela filha
Action = caFree
}

Setando Action para caFree, determinamos que o form seja fechado e toda a memória alocada para o form seja liberada.
Se um form é um form MDI child, e a propriedade BorderIcons do mesmo estiver para biMinimize, então a default para Action é caMinimize, determinando que o form seja minimizado em detrimento de ser fechado. Se um form MDI child não possuir esta marcação, então a default para Action é caNone, o que significa que nada acontece quando o usuário tenta fechar o form.

Se um form é umform SDI child, o default para Action é caHide. caHide faz com que o form seja escondido, porém ativo, podendo ser acessado pela aplicação.

Para fechar o form acima criado pelo operador newe liberá-lo num evento OnClose, devemos marcar o parâmetro Action para caFree, o que provocará a liberação da memória alocada em sua criação, dispensando-se, nestes casos, o uso do operador delete para a desalocação da memória.

Feito isso, precisamos adicionar o arquivo de cabeçalho EdtDesenh.h. No menu File dê um clique em Include Unid Hdr... Na caixa de diálogo que se abrir, escolha o arquivo correspondente e dê um OK.
Para que as janelas abertas sejam listadas como itens de menu, selecione o form FrmPncel e ajuste a propriedade WindowMenu para Janela1.

Vamos adicionar alguns códigos para trabalhar com as janelas abertas

void __fastcall TEdtDsnh::Fechar1Click(TObject *Sender) 
{
Close();    //fecha a janela filha
}
//----------------------------------------------------------------------
 
void __fastcallTFrmPncel::LadoaLadoHorizontalmente1Click(TObject *Sender) 
{
// exibe as janelas filhas abertas horizontalmente
TileMode = tbHorizontal;   
Tile();
}
//----------------------------------------------------------------------
void __fastcallTFrmPncel::LadoaLadoVerticalmente1Click(TObject *Sender) 
{
TileMode = tbVertical; // exibe as janelas filhas abertas verticalmente
Tile();
}
//----------------------------------------------------------------------
void __fastcallTFrmPncel::Cascata1Click(TObject *Sender) 
{
Cascade();     // exibe as janelas filhas abertas em cascata
}
//----------------------------------------------------------------------
void __fastcallTFrmPncel::Reorganizarcones1Click(TObject *Sender) 
{
ArrangeIcons();
}
 

Basicamente, podemos colocar qualquer componente ou funcionalidade em uma janela filha. Em nossa aplicação, usaremos um componente Image para trabalhar com imagens.
Coloque em EdtDsnh um componente Image da paleta Additional, altere a propriedade AutoSizedo componente para true e o dimensione de acordo com o tamanho do Form.
Para poder abrir uma imagem, coloque um componente OpenPictureDialog no FrmPncel. Vamos aos códigos. No evento Abrir1Click de FrmPncel digite:

// Abre a caixa de diálogo "abrir figuras"
if(OpenPictureDialog1->Execute()) 
new TEdtDsnh(this)->     //Cria uma janela filha em tempo de execução
/* carrega a imagem selecionada para a janela filha criada 
em tempo de execução*/
Image1->Picture-> LoadFromFile(OpenPictureDialog1->FileName);

No evento Abri1Click de EdtDsnh digite:

Agora vamos trabalhar com os botões. Usá-los-emos para alternar entre os tipos de atividades que desenvolveremos no componente Image (exemplo: riscar, pintar etc). Alteremos a propriedade Name:

SpeedButton1 - Name = SpdLaps

SpeedButton2 - Name = SpdTint

SpeedButton3 - Name = SpdApag

SpeedButton4 - Name = SpdCircvz

SpeedButton5 - Name = SpdQdrvz

SpeedButton6- Name = SpdCircch

SpeedButton7 - Name = SpdQdrch

Agora, para relacioná-los num grupo único, altere a propriedade GroupIndex de todos eles para 1. Altere a propriedade Down do SpdLaps para true (na inicialização do programa, ele estará selecionado). Para colocar um efeito 3D nos botões, basta alterar a propriedade Flat deles para true. Use a propriedade Glyph para escolher alguma figura para os botões. Obviamente, as figuras devem corresponder à função de cada botão e possuir tamanho equivalente ao tamanho dos botões.

Vamos colocar alguns códigos no SpdLaps, o qual será usado para fornecer o comando que nos permitirá riscar as imagens com linhas. Antes, porém, digite o seguinte código no evento OnMouseMove de Image1, apenas para vermos como é fácil produzir riscos no componente, usando o objeto Canvas.

// risca Image1 com o simples passar do mouse
Image1->Canvas->LineTo(X, Y);

Se testar o programa agora, verá que já pode produzir riscos em Image1, seja numa figura nova ou numa figura carregada de seus arquivos.

Nota: suspenderemos o projeto Paint por alguma lições, a fim de abordarmos tópicos importantes relacionados ao tema.

A partir de agora estaremos trabalhando para concluir nosso curso básico. Um dos motivos pelo qual interrompemos a construção de nosso Paint é o fato de que precisávamos compreender melhor o objeto TCanvas, bem como o que se passa quando acionamos o envento OnMouseMove. Seria interessante rever esses tópicos, visto que nos ajudarão a compreender melhor os próximos passos.
Ok, missão cumprida, continuemos!
Canvas permite-nos desenhar num bitmap providenciando um objeto TCanvas para tal propósito. Na sétima parte do projeto Paint, nós percebemos como é fácil fazer riscos num Image usando Canvas, sem, contudo, nos preocuparmos em controlar esse evento.
Vamos, então, melhorar o código de nossa última aula, inserindo um comando que verifica se o botão esquerdo do mouse está pressionado:


//se o botão esquerdo do mouse estiver pressionado
if (!Shift.Contains(ssLeft))
return;
// risca Image1 com o passar do mouse
Image1
->Canvas->LineTo(X, Y);

 

O código acima já nos dá algum controle, uma vez que permitirá que Image1 seja riscado apenas quando o botão esquerdo do mouse estiver pressionado. Isso, porém, não é o bastante, visto que, nem sempre, estaremos riscando o componente, mas somente quando desejarmos essa opção ativada. Ativá-la-emos através de nosso primeiro SpeedButton (SpdLaps):


void __fastcall TEdtDsnh::Image1MouseMove(TObject *Sender,
TShiftState Shift, int X, int Y)
{
//se o botão esquerdo do mouse estiver pressionado
if (!Shift.Contains(ssLeft))
return;

// e se o botão SpdLaps estiver pressionado
if (FrmPncel->SpdLaps->Down)
{
// risca Image1 com o passar do mouse
Image1
->Canvas->LineTo(X, Y);
return;
}
}

 

Ainda não temos o controle total da situação. Se fizermos vários riscos, perceberemos que eles se emendam (o fim do último com o início do próximo). Precisamos colocar o código que determina o início do risco no local onde Image1 recebe o clique do mouse. No evento OnMouseDown de Image1 digite:


Image1->Canvas->MoveTo(X, Y);

 

Que tal podermos escolher a cor do risco? Usaremos o componente Shape com as cores do componente CColorGrid1 para essa finalidade.
Inicialmente tratemos das propriedades de Shape1: altere seu nome para ShpCor. Podemos, aqui, definir a cor inicial do risco. Que tal preto? Dê um duplo clique na propriedade Brush desse componente e altere sua cor (Color) para preto (clBlack); alteremos, agora, sua borda para branco. Dê um duplo clique na propriedade Pen e altere sua cor para branco (clWhite).
Vamos entender o funcionamento desse dispositivo. A cor do risco será capturada de ShpCor. Precisamos, então, de um dispositivo que altere a cor desse componente. Usaremos as cores de CColorGrid1 e de uma caixa de diálogo de cores, mais especificamente uma ColorDialog.
Em FrmPncel, coloque um ColorDialog e mais um SpeedButton no TollBar (logo após CColorGrig1).
Renomeie o botão para SpdCores e em seu evento OnClick digite o código responsável pela chamada a ColorDialog1, usado para pintar ShpCor:


if (ColorDialog1->Execute())
ShpCor->Brush->Color = ColorDialog1->Color;

 

A seguir, atrelemos ShpCor a CColorGrid1. No evento OnChange de CColorGrig1, digite:

 

ShpCor->Brush->Color = /*a cor Brush.color de ShpCor será igual*/
CColorGrid1
->ForegroundColor; /*à cor escolhida em CColorGrid1*/

 

Feito isso, precisamos ligar a cor do risco à cor de ShpCor. Melhoremos o evento OnMouseDown de Image1:


if (FrmPncel->SpdLaps->Down) /*se SpdLaps estiver pressionado*/
{
Image1->Canvas->Pen->Color = /*a cor do risco em Image1 será igual*/
FrmPncel
->ShpCor->Brush->Color; /* à cor de ShpCor (Shape1)*/
/*Determina o início do risco no local onde Image1 recebe o clique do mouse*/
Image1
->Canvas->MoveTo(X,Y);
return;

}

Vamos agora aprender como pintar uma região delimitada por linhas. Lembremos:


void __fastcall FloodFill(int X, int Y, TColor Color, TFillStyle FillStyle);

Usamos FloodFill para encher uma região possivelmente não retangular da imagem com o valor de Brush. Os limites da região para ser preenchidos são determinados pelo passar ao lado externo do ponto (X,Y), quando o limite de cor que envolve o parâmetro Color é encontrado. FillStyle determina qual tipo de mudança de cor define os limites.
Os princípios são bastante semelhantes com aqueles que usamos para fazer os riscos. No evento OnMouseDown de Image1 digite:


if (FrmPncel->SpdTint->Down)
{
if (
Button == mbLeft)
{
Image1->Canvas->Brush->Color = FrmPncel->ShpCor->Brush->Color;
Image1->Canvas->FloodFill(X, Y, Image1->Canvas->Pixels[X][Y], fsSurface);
return;
}
}

Com esse código já é possivel preencher (pintar) regiões de Image1. Como exercício, comente o código acima.

Já sabemos que podemos usar a propriedade Width para dar à linha maior ou menor espessura e que se Width for assinalado com um valor menor do que 1, o valor de pen automaticamente será remetido para 1. Podemos nos valer dessa propriedade para criar uma borracha que apagará trechos da figura. Na verdade, a borracha não apaga. Ela simplesmente desenha uma linha branca sobre a região desejada.
Usaremos o terceito botão: SpdApag.
No evento OnMouseDown de Image1 digite um velho e conhecido código:


if (FrmPncel->SpdApag->Down)
{
Image1->Canvas->Pen->Color = FrmPncel->Shape2->Brush->Color;
Image1->Canvas->Pen->Width = 2; // experimente outros valores
Image1
->Canvas->MoveTo(X,Y);
return;
}

e, como não poderia deixar de ser, no evento OnMouseMove:


if (FrmPncel->SpdApag->Down)
{
Image1->Canvas->LineTo(X,Y);
return;
}

Precisamos retornar o Width padrão (para o pincel). No evento OnMouseUp de Image1:


if (FrmPncel->SpdApag->Down)
{
Image1->Canvas->Pen->Width = 1; //
return;
}

Assim, temos nosso apagador.

Vamos inserir o código responsável pelos desenhos de quadrados e círculos, vazios e cheios:
Na parte private de EdtDesenh.h digite:


int InicialX;
int
InicialY;
TImage *TmpImage;
void __fastcall
DesenhaFigura(int X, int Y);

Já deve ter ficado claro que estaremos tratando os três eventos de mouse de Image1.
Comecemos pelo OnMouseDown:


// Assinalamos as coordenadas iniciais
InicialX
= X;
InicialY = Y;
// TmpImage guarda a imagem existente no evento down, e
// que pode ser guardada até o mouse ser liberado. Poderá
// ser usada para restaurar a imagem durante a redefinição
// de tamanhos dos quadrados e círculos
TmpImage
= new TImage(this);
TmpImage->Picture = Image1->Picture;

OnMouseMove:


// Precisamos informar as alterações ocorridas
// para nossa função
DesenhaFigura
(X, Y);

OnMouseUp:


// Enviamos as últimas coordenadas
DesenhaFigura
(X, Y);
// apagamos o componente criado em tempo de execução.
delete TmpImage;

Eis a definição da função DesenhaFigura():


//---------------------------------------------------------------------------
void __fastcall TEdtDsnh::DesenhaFigura(int X, int Y)
{
TRect bounds; // para funções gráficas que requerem um rect
// essencial para a correta definição das figuras.
// experimente comentar todas as ocorrências desse
// componente para compreender melhor sua utilidade.
Image1
->Picture = TmpImage->Picture;
// definimos, aqui, as cores (Pen e Brush) dos círculos e quadrados.
Image1
->Canvas->Brush->Color = FrmPncel->ShpCor->Brush->Color;
Image1->Canvas->Pen->Color = FrmPncel->ShpCor->Brush->Color;
// Conforme a posição do cursor em relação às coordenadas
// iniciais, as variáveis bounds terão valores diferentes.
if (X < InicialX)
{
bounds.Left = X;
bounds.Right = InicialX;
}
else
{
bounds.Right = X;
bounds.Left = InicialX;
}

if (Y < InicialY)
{
bounds.Top = Y;
bounds.Bottom = InicialY;
}
else
{
bounds.Bottom = Y;
bounds.Top = InicialY;
}

// Desenha o círculo ou o quadrado usando a função correspondente.
if (FrmPncel->SpdCircvz->Down)
Image1->Canvas->Arc(InicialX, InicialY, X, Y, X, Y, X, Y);
else if (
FrmPncel->SpdCircch->Down)
Image1->Canvas->Ellipse(InicialX, InicialY, X, Y);
else if (
FrmPncel->SpdQdrvz->Down)
Image1->Canvas->FrameRect(bounds);
else if (
FrmPncel->SpdQdrch->Down)
Image1->Canvas->FillRect(bounds);
}
//---------------------------------------------------------------------------

Assim já temos o código dos quatro últimos botões.
TRATAMENTO DE ERROS - Em face dessa nova função DesenhaFigura(), precisamos, agora, prevenir alguns bugs nos eventos OnMouseMove e OnMouseUp do componente Image. No primeiro evento digite:


//evita erros na chamada a DesenhaFigura()
if (FrmPncel->SpdTint->Down)
return;

E no evento OnMouseUp digite:


//evita erros na chamada a DesenhaFigura()
if ((FrmPncel->SpdLaps->Down) || (FrmPncel->SpdTint->Down))
return;

Na região dos includes de EdtDesenh.cpp:


#include "Clipbrd.hpp"

No evento OnClick do menu Copiar:


Clipboard()->Assign(Image1->Picture);

No evento OnClick do menu Cortar:


TRect ARect;
// copia a figura para o Clipboard, através do método copiar.
Copiar1Click
(Sender);
// preenche a seção cortada com branco.
// CmBlackness determinaria preto
Image1
->Canvas->CopyMode = cmWhiteness;
// dimensiona a seção da tela copiada que será preenchida com branco
ARect
= Rect(0, 0, Image1->Width, Image1->Height);
// complementa as duas linhas acima, retirando a figura (cortando)
Image1
->Canvas->CopyRect(ARect, Image1->Canvas, ARect);
// restaura o modo default
Image1
->Canvas->CopyMode = cmSrcCopy;

No evento OnClick do menu Colar:


if (Clipboard()->HasFormat(CF_BITMAP))
{
Image1->Picture->Bitmap->Assign(Clipboard());
}

Assim nós finalizamos a construção conjunta de nosso Paint. Daqui para frente é com você, uma vez que os principais conceitos foram abordados, nestes ou em outros temas. Assumimos que você já possui condições de completar esse aplicativo por si mesmo.
Esse exemplo, em grande parte, foi baseado no exemplo que acompanha os compiladores C++Builder. Para mais detalhes, consulte esse material

 

VMS Desenvolvimentos

Diversas Dicas, Apostilas, Arquivos Fontes, Tutoriais, Vídeo Aula, Download de Arquivos Relacionado a Programação em C++ Builder.

Voltar ao Site