FireMonkey TCanvas SaveCanvas and RestoreCanvas C++ Code Samples

By: Tim DelChiaro

Abstract: This example shows how to use the SaveCanvas and RestoreCanvas functions and their results. Is also shows how to dynamically customize the drawing stroke and fill properties of the TCanvas.

    FMXTCanvasSaveCanvas (C++)

 

    Language:

    Versions:

 

Contents

    Description

This example shows how to use the SaveCanvas and RestoreCanvas functions and their results. Is also shows how to dynamically customize the drawing stroke and fill properties of the TCanvas.

To build and test this example, create a FireMonkey HD Application - C++ and add the following controls on the form:

The set of TColorComboBoxTNumberBox, and TComboBox objects display the current state of the drawing and filling TCanvasproperties. When the selected values change, the TCanvas properties are updated.

This example does the following:

  • Draws an ellipse, a rectangle, or displays a text with the current draw and fill properties.
  • Saves the state of the canvas at a moment and restores it after.

The drawing is made on the canvas of the bitmap. The bitmap is displayed on the TImage.

In the next sample image, the ellipse was drawn with the state displayed in the memo, and the rectangle was drawn with the state displayed by the set of combo boxes.

File:SaveCanvas.png

    Code

Add as global variables two pointers, SaveState and InitialState, to keep the initial state of the canvas and the state saved when the SaveState button is clicked.

TForm1 *Form1;
TCanvasSaveState *SaveState, *InitialState;

Add a new procedure to the form class, named UpdateStateComboBox (do not forget to add it on the header as well), to update the set of combo boxes. This method is called when the form is created, the canvas is cleared, or a state is restored, so the combo boxes set show the current draw and fill properties.

void __fastcall TForm1::UpdateStateComboBox() {
	// updates the combo boxes with the current state of the canvas
	StrokeColorComboBox->Color = MainImage->Bitmap->Canvas->Stroke->Color;
	ThicknessNumberBox1->Value = MainImage->Bitmap->Canvas->StrokeThickness;
	StrokeCapComboBox->ItemIndex = StrokeCapComboBox->ListBox->Items->IndexOf
		(GetEnumName(__delphirtti(TStrokeCap),
		(int)(MainImage->Bitmap->Canvas->StrokeCap)));
	StrokeDashComboBox->ItemIndex = StrokeDashComboBox->ListBox->Items->IndexOf
		(GetEnumName(__delphirtti(TStrokeDash),
		(int)(MainImage->Bitmap->Canvas->StrokeDash)));
	StrokeJoinComboBox->ItemIndex = StrokeJoinComboBox->ListBox->Items->IndexOf
		(GetEnumName(__delphirtti(TStrokeJoin),
		(int)(MainImage->Bitmap->Canvas->StrokeJoin)));
	FillColorColorComboBox->Color = MainImage->Bitmap->Canvas->Fill->Color;
	TextSizeNumberBox->Value = MainImage->Bitmap->Canvas->Font->Size;
}

Add the following code to the OnCreate event handler of the form.

void __fastcall TForm1::FormCreate(TObject *Sender) {
	// initializes the initial bitmap
	MainImage->Bitmap = new TBitmap(MainImage->Width, MainImage->Height);
	// updates the combo boxes values
	UpdateStateComboBox();
	// saves the initial state of the canvas to be customized
	InitialState = MainImage->Bitmap->Canvas->SaveState();
}

Add the following lines of code to the OnClick event handlers of SaveCanvas and RestoreCanvas buttons:

void __fastcall TForm1::SaveButtonClick(TObject *Sender) {
	StateMemo->Lines->Clear();
	// saves the current state and display the current properties on the StateMemo
	SaveState = MainImage->Bitmap->Canvas->SaveState();
	RestoreButton->Enabled = true;
	// displays the saved properties on the StateMemo
	StateMemo->Lines->Add("Stroke Color: " +
		StrokeColorComboBox->ListBox->Selected->Text);
	StateMemo->Lines->Add("StrokeThickness: " + ThicknessNumberBox1->Text);
	StateMemo->Lines->Add("StrokeCap: " +
		StrokeCapComboBox->ListBox->Selected->Text);
	StateMemo->Lines->Add("StrokeDash: " +
		StrokeDashComboBox->ListBox->Selected->Text);
	StateMemo->Lines->Add("StrokeJoin: " +
		StrokeJoinComboBox->ListBox->Selected->Text);
	StateMemo->Lines->Add("Text Size: " + TextSizeNumberBox->Text);
	StateMemo->Lines->Add("Fill Color: " +
		FillColorColorComboBox->ListBox->Selected->Text);
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::RestoreButtonClick(TObject *Sender) {
	// restores the saved properties
	MainImage->Bitmap->Canvas->RestoreState(SaveState);
	RestoreButton->Enabled = false;
	// updates the combo boxes
	UpdateStateComboBox();
	// clears the memo
	StateMemo->Lines->Clear();
}
// ---------------------------------------------------------------------------


Add the following lines of code to the OnExit event handlers of the TColorComboBoxTNumberBox, and TComboBox objects, respectively:

void __fastcall TForm1::StrokeColorComboBoxExit(TObject *Sender) {
	// sets the stroke color
	MainImage->Bitmap->Canvas->Stroke->Color = StrokeColorComboBox->Color;
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::ThicknessNumberBox1Exit(TObject *Sender) {
	// sets the thickness of the stroke
	MainImage->Bitmap->Canvas->StrokeThickness = ThicknessNumberBox1->Value;
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::StrokeCapComboBoxExit(TObject *Sender) {
	// sets the stroke cap
	MainImage->Bitmap->Canvas->StrokeCap =
		TStrokeCap(GetEnumValue(__delphirtti(TStrokeCap),
		StrokeCapComboBox->Selected->Text));
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::StrokeDashComboBoxExit(TObject *Sender) {
	// sets the stroke dash
	MainImage->Bitmap->Canvas->StrokeDash =
		TStrokeDash(GetEnumValue(__delphirtti(TStrokeDash),
		StrokeDashComboBox->Selected->Text));
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::StrokeJoinComboBoxExit(TObject *Sender) {
	// sets the stroke join
	MainImage->Bitmap->Canvas->StrokeJoin =
		TStrokeJoin(GetEnumValue(__delphirtti(TStrokeJoin),
		StrokeJoinComboBox->Selected->Text));
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::FillColorColorComboBoxExit(TObject *Sender) {
	// sets the fill color
	MainImage->Bitmap->Canvas->Fill->Color = FillColorColorComboBox->Color;
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::TextSizeNumberBoxExit(TObject *Sender) {
	// sets the font size
	MainImage->Bitmap->Canvas->Font->Size = TextSizeNumberBox->Value;
}
// ---------------------------------------------------------------------------

Add the following lines of code to the OnClik event handlers of the ellipse, rectangle, text, and clear TButton objects, respectively:

void __fastcall TForm1::EllipseButtonClick(TObject *Sender) {
	TRectF MyRect;
	int x1, y1, x2, y2;
	// draws and fills an ellipse on the canvas with the current state
	x1 = 20;
	y1 = 20;
	x2 = MainImage->Bitmap->Canvas->Width - 20;
	y2 = MainImage->Bitmap->Canvas->Height - 20;
	// sets the circumscribed rectangle of the ellipse
	MyRect.init(x1, y1, x2, y2);
	// draws the ellipse on the canvas+
        MainImage->Bitmap->Canvas->BeginScene();
	MainImage->Bitmap->Canvas->DrawEllipse(MyRect, 40);
	MainImage->Bitmap->Canvas->FillEllipse(MyRect, 40);
        MainImage->Bitmap->Canvas->EndScene();
	// updates the bitmap
	MainImage->Bitmap->BitmapChanged();
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::RectangleButtonClick(TObject *Sender) {
	TRectF MyRect;
	int x1, y1, x2, y2;
	// draws and fills a rectangle on the canvas with the current state
	// the rectangle to be drawn
	x1 = 60;
	y1 = 60;
	x2 = MainImage->Bitmap->Canvas->Width - 60;
	y2 = MainImage->Bitmap->Canvas->Height - 60;
	MyRect.init(x1, y1, x2, y2);
        MainImage->Bitmap->Canvas->BeginScene();
	MainImage->Bitmap->Canvas->DrawRect(MyRect, 0, 0, AllCorners, 100);
	MainImage->Bitmap->Canvas->FillRect(MyRect, 0, 0, AllCorners, 100);
        MainImage->Bitmap->Canvas->EndScene();
	// updates the bitmap
	MainImage->Bitmap->BitmapChanged();
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::TextButtonClick(TObject *Sender) {
	TRectF MyRect;
	int x1, y1, x2, y2;
	x1 = 60;
	y1 = 60;
	x2 = MainImage->Bitmap->Canvas->Width - 60;
	y2 = MainImage->Bitmap->Canvas->Height - 60;
	MyRect.init(x1, y1, x2, y2);
	// fills and draws the text in the specified rectangle area of the canvas
        MainImage->Bitmap->Canvas->BeginScene();
	MainImage->Bitmap->Canvas->FillText(MyRect, TextEdit->Text, false, 100,
		TFillTextFlags() << TFillTextFlag::ftRightToLeft, TTextAlign::taCenter,
		TTextAlign::taCenter);
        MainImage->Bitmap->Canvas->EndScene();
	// updates the bitmap
	MainImage->Bitmap->BitmapChanged();
}
// ---------------------------------------------------------------------------
 
void __fastcall TForm1::ClearButtonClick(TObject *Sender)
{
	 //clears the canvas and restores the initial state
  MainImage->Bitmap->Canvas->BeginScene();
  MainImage->Bitmap->Canvas->Clear(claNull);
  MainImage->Bitmap->BitmapChanged();
  MainImage->Bitmap->Canvas->RestoreState(InitialState);
  MainImage->Bitmap->Canvas->EndScene();
  //updates the combo boxes
  UpdateStateComboBox();
}
//---------------------------------------------------------------------------

    Uses

    See Also

Server Response from: ETNASC01