Do you need to add printer support to your C++ applications using the Visual Component Library (VCL) or FireMonkey (FMX) GUI ? In this blog post I’ll show you how to build Windows applications that support printing image bitmaps using the VCL and FMX frameworks. One of my favorite C++Builder RTL features is that both frameworks provide similar printer components and ways of programming with only a few subtle differences.
Build VCL and FMX Application Projects
Use the “File | New | Windows VCL Application – C++Builder” menu item and create a starting C++ VCL application. Save the product to a folder.

Next, in the Project Window, right mouse click on the ProjectGroup node and select the “Add New Project…” menu item.

In the popup dialog choose to create a Multi-Device Application.

Click the OK button and on the next screen choose to create a “Blank Application”.

Use the File | Save All menu item (or type Shift+Ctrl+S) to save both starting projects and the project group to a folder.

Each of the VCL and FMX projects have a main form (.dfm and .fmx extensions respectively). While most of the IDE will look the same, if you select each form’s unit you will see different looks for each of their form designers.


There are many videos, articles and help files that describe the details of each designer (check out links in the reference section below). For now, let’s dig into the VCL and FMX printer examples I’ve created.
A Simple UI for each Printer Test Project
On each of the VCL and FMX main forms you’ll see the following components.


Each project’s main menu contains a File and Destination menu. The Destination menu item allows the user to choose to override the printing destination (Printer or File).



The File menu provides an OpenPictureDialog (VCL) or OpenDialog (FMX), PrintPicture dialog for choosing the printer and other printing options, PrinterSetup dialog to set additional printer setup options, Panel (aligned to the top of the form)with a label and ComboBox which will list the available printer device names, and an Image component (aligned to the client area) to contain the picture bitmap.
The VCL and FMX forms look like the following.


Right mouse click on the form and choose “View as Text” from the popup menu. Now you can see all of the form and component properties and sub-properties that have been set from their default values. You can also make changes in this text form mode but be careful to not make any errors.

To switch back to the form mode click the right mouse button (or hit Alt-F12) and choose “View as Form” from the popup menu.
VCLPrintUnit.dfm (View as Text)
object MainVCLForm: TMainVCLForm
Left = 0
Top = 0
Caption = 'Printer Test (C++, VCL)'
ClientHeight = 473
ClientWidth = 667
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Menu = MainMenu1
OldCreateOrder = False
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object Image1: TImage
Left = 0
Top = 41
Width = 667
Height = 432
Align = alClient
Proportional = True
ExplicitLeft = 104
ExplicitTop = 102
ExplicitWidth = 424
ExplicitHeight = 317
end
object Panel1: TPanel
Left = 0
Top = 0
Width = 667
Height = 41
Align = alTop
TabOrder = 0
object Label1: TLabel
Left = 10
Top = 12
Width = 41
Height = 13
Caption = 'Printers:'
end
object PrintersComboBox: TComboBox
Left = 57
Top = 9
Width = 250
Height = 21
TabOrder = 0
Text = 'PrintersComboBox'
end
end
object PrintDialog1: TPrintDialog
Options = [poPrintToFile]
Left = 176
Top = 56
end
object PrinterSetupDialog1: TPrinterSetupDialog
Left = 304
Top = 64
end
object OpenPictureDialog1: TOpenPictureDialog
DefaultExt = 'bmp'
InitialDir = 'c:\temp'
Left = 56
Top = 56
end
object MainMenu1: TMainMenu
Left = 424
Top = 64
object File1: TMenuItem
Caption = 'File'
object File2: TMenuItem
Caption = 'Open Picture'
OnClick = File2Click
end
object PrintPicture1: TMenuItem
Caption = 'Print Picture'
Enabled = False
OnClick = PrintPicture1Click
end
object PrinterSetup1: TMenuItem
Caption = 'Printer Setup'
Enabled = False
OnClick = PrinterSetup1Click
end
object PrintPicture2: TMenuItem
Caption = 'Exit'
OnClick = PrintPicture2Click
end
end
object Destination1: TMenuItem
Caption = 'Destination'
object PrintToPrinterDestinationMenuItem: TMenuItem
Caption = 'Print to Printer'
Checked = True
OnClick = PrintToPrinterDestinationMenuItemClick
end
object PrintToFileDestinationMenuItem: TMenuItem
Caption = 'Print to File'
OnClick = PrintToFileDestinationMenuItemClick
end
end
end
end
FMXPrintUnit.fmx (View as Text)
object MainFMXForm: TMainFMXForm
Left = 0
Top = 0
Caption = 'Printer Test (C++, FMX)'
ClientHeight = 380
ClientWidth = 640
Position = Designed
WindowState = wsMaximized
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnShow = FormShow
DesignerMasterStyle = 0
object Image1: TImage
MultiResBitmap = <
item
end>
Align = Client
Size.Width = 640.000000000000000000
Size.Height = 339.000000000000000000
Size.PlatformDefault = False
end
object PrintDialog1: TPrintDialog
Options = [poPrintToFile]
Left = 68
Top = 40
end
object PrinterSetupDialog1: TPrinterSetupDialog
Left = 190
Top = 42
end
object OpenDialog1: TOpenDialog
DefaultExt = 'bmp'
Filter = '*.bmp'
InitialDir = 'c:\temp'
Left = 312
Top = 44
end
object MainMenu1: TMainMenu
Left = 418
Top = 46
object FileMenu: TMenuItem
Text = 'File'
object OpenBitmapMenuItem: TMenuItem
Locked = True
Text = 'Open Bitmap'
OnClick = OpenBitmapMenuItemClick
end
object PrintMenuItem: TMenuItem
Enabled = False
Locked = True
Text = 'Print'
OnClick = PrintMenuItemClick
end
object PrinterSetupMenuItem: TMenuItem
Enabled = False
Locked = True
Text = 'Printer Setup'
OnClick = PrinterSetupMenuItemClick
end
object ExitMenuItem: TMenuItem
Locked = True
Text = 'Exit'
OnClick = ExitMenuItemClick
end
end
object DestinationMenu: TMenuItem
Text = 'Destination'
object PrintToPrinterDestinationMenuItem: TMenuItem
Locked = True
IsChecked = True
Text = 'Print to Printer'
OnClick = PrintToPrinterDestinationMenuItemClick
end
object PrintToFileDestinationMenuItem: TMenuItem
Locked = True
Text = 'Print to File'
OnClick = PrintToFileDestinationMenuItemClick
end
end
end
object Panel1: TPanel
Align = Top
Size.Width = 640.000000000000000000
Size.Height = 41.000000000000000000
Size.PlatformDefault = False
object PrintersComboBox: TComboBox
Position.X = 72.000000000000000000
Position.Y = 8.000000000000000000
Size.Width = 233.000000000000000000
Size.Height = 22.000000000000000000
Size.PlatformDefault = False
end
object Label1: TLabel
Position.X = 8.000000000000000000
Position.Y = 9.000000000000000000
Size.Width = 57.000000000000000000
Size.Height = 17.000000000000000000
Size.PlatformDefault = False
Text = 'Printers:'
end
end
end
Additional comments about component properties and event handlers are included in the source code for the projects.
The Source Code
Below you will find the header files for the VCL and FMX form units. The header files will show the component declarations, event handlers and any public/private declarations.
VCLPrintUnit.h
//---------------------------------------------------------------------------
#ifndef VCLPrintUnitH
#define VCLPrintUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Dialogs.hpp>
#include <Vcl.ExtCtrls.hpp>
#include <Vcl.ExtDlgs.hpp>
#include <Vcl.Menus.hpp>
#include <Vcl.WinXCtrls.hpp>
//---------------------------------------------------------------------------
class TMainVCLForm : public TForm
{
__published: // IDE-managed Components
TPrintDialog *PrintDialog1;
TPrinterSetupDialog *PrinterSetupDialog1;
TImage *Image1;
TOpenPictureDialog *OpenPictureDialog1;
TMainMenu *MainMenu1;
TMenuItem *File1;
TMenuItem *File2;
TMenuItem *PrintPicture1;
TMenuItem *PrintPicture2;
TMenuItem *Destination1;
TMenuItem *PrintToPrinterDestinationMenuItem;
TMenuItem *PrintToFileDestinationMenuItem;
TMenuItem *PrinterSetup1;
TPanel *Panel1;
TLabel *Label1;
TComboBox *PrintersComboBox;
void __fastcall File2Click(TObject *Sender);
void __fastcall FormShow(TObject *Sender);
void __fastcall PrintToPrinterDestinationMenuItemClick(TObject *Sender);
void __fastcall PrintToFileDestinationMenuItemClick(TObject *Sender);
void __fastcall PrintPicture1Click(TObject *Sender);
void __fastcall PrinterSetup1Click(TObject *Sender);
void __fastcall PrintPicture2Click(TObject *Sender);
private: // User declarations
bool PictureLoaded; // boolean for whether a picture is loaded or not
public: // User declarations
__fastcall TMainVCLForm(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainVCLForm *MainVCLForm;
//---------------------------------------------------------------------------
#endif
FMXPrintUnit.h
//---------------------------------------------------------------------------
#ifndef FMXPrintUnitH
#define FMXPrintUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
#include <FMX.Objects.hpp>
#include <FMX.Dialogs.hpp>
#include <FMX.Printer.hpp>
#include <FMX.Menus.hpp>
#include <FMX.ListBox.hpp>
//---------------------------------------------------------------------------
class TMainFMXForm : public TForm
{
__published: // IDE-managed Components
TImage *Image1;
TPrintDialog *PrintDialog1;
TPrinterSetupDialog *PrinterSetupDialog1;
TOpenDialog *OpenDialog1;
TMainMenu *MainMenu1;
TMenuItem *FileMenu;
TMenuItem *OpenBitmapMenuItem;
TMenuItem *PrintMenuItem;
TMenuItem *PrinterSetupMenuItem;
TMenuItem *ExitMenuItem;
TPanel *Panel1;
TComboBox *PrintersComboBox;
TLabel *Label1;
TMenuItem *DestinationMenu;
TMenuItem *PrintToPrinterDestinationMenuItem;
TMenuItem *PrintToFileDestinationMenuItem;
void __fastcall PrintMenuItemClick(TObject *Sender);
void __fastcall OpenBitmapMenuItemClick(TObject *Sender);
void __fastcall ExitMenuItemClick(TObject *Sender);
void __fastcall PrinterSetupMenuItemClick(TObject *Sender);
void __fastcall FormShow(TObject *Sender);
void __fastcall PrintToPrinterDestinationMenuItemClick(TObject *Sender);
void __fastcall PrintToFileDestinationMenuItemClick(TObject *Sender);
private: // User declarations
BOOL PictureLoaded; // boolean for whether a picture is loaded or not
public: // User declarations
__fastcall TMainFMXForm(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TMainFMXForm *MainFMXForm;
//---------------------------------------------------------------------------
#endif
Below you will find the source code for the VCL and FMX form units.
VCLPrinterUnit.cpp
//---------------------------------------------------------------------------
#include <vcl.h>
#include <Vcl.Imaging.GIFImg.hpp>
#include <Vcl.Imaging.jpeg.hpp>
#include <Vcl.Imaging.pngimage.hpp>
#include <Vcl.Printers.hpp>
#pragma hdrstop
#include "VCLPrintUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainVCLForm *MainVCLForm;
//---------------------------------------------------------------------------
__fastcall TMainVCLForm::TMainVCLForm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::File2Click(TObject *Sender)
{
if (OpenPictureDialog1->Execute()) {
Image1->Picture->LoadFromFile(OpenPictureDialog1->FileName);
PictureLoaded = true;
PrintPicture1->Enabled = true;
PrinterSetup1->Enabled = true;
}
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::FormShow(TObject *Sender)
{
PictureLoaded = false;
PrintToPrinterDestinationMenuItem->Checked = true;
PrintToFileDestinationMenuItem->Checked = false;
// get printers list and put in combobox
PrintersComboBox->Items = Printer()->Printers;
// make the currently selected printer the Item in the ComboBox
PrintersComboBox->ItemIndex = 0;
for (int i = 0; i < Printer()->Printers->Count-1; i++) {
if (Printer()->Printers->Strings[Printer()->PrinterIndex] == PrintersComboBox->Items->Strings[i]) {
PrintersComboBox->ItemIndex = i;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintToPrinterDestinationMenuItemClick(TObject *Sender)
{
// set menu item checked for print to printer
PrintToPrinterDestinationMenuItem->Checked = true;
PrintToFileDestinationMenuItem->Checked = false;
// set PrintDialog PrintToFile checkbox off
// Note: to allow user to override the menu item - make sure
// PrintDialog Options poPrintToFile is set to true
// so that the PrintToFile checkbox appears in the dialog
PrintDialog1->PrintToFile = false;
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintToFileDestinationMenuItemClick(TObject *Sender)
{
// set menu item checked for print to file
PrintToPrinterDestinationMenuItem->Checked = false;
PrintToFileDestinationMenuItem->Checked = true;
// set PrintDialog PrintToFile checkbox on
// Note: to allow user to override the menu item - make sure
// PrintDialog Options poPrintToFile is set to true
// so that the PrintToFile checkbox appears in the dialog
PrintDialog1->PrintToFile = true;
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintPicture1Click(TObject *Sender)
{
// check if a picture is loaded
if (PictureLoaded) {
if (PrintDialog1->Execute()) {
// Call BeginDoc - to get the dimensions for selected printer
Printer()->BeginDoc();
try {
// use StretchDraw to do full size bitmap printing
// notes:
// printer settings can be made using the
// PrintDialog and PrinterSetupDialog
// you can also control page layout in code:
// Property is Orientation:
// poPortrait
// poLandscape
Printer()->Canvas->StretchDraw(
Rect(0, 0, Printer()->PageWidth,Printer()->PageHeight),
Image1->Picture->Graphic);
}
__finally {
// end the document and the printing will begin
Printer()->EndDoc();
}
}
}
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrinterSetup1Click(TObject *Sender)
{
// Printer Setup
PrinterSetupDialog1->Execute();
}
//---------------------------------------------------------------------------
void __fastcall TMainVCLForm::PrintPicture2Click(TObject *Sender)
{
Application->Terminate();
}
//---------------------------------------------------------------------------
FMXPrinterUnit.cpp
//---------------------------------------------------------------------------
#include <fmx.h>
#include "FMX.Printer.hpp"
#include "System.SysUtils.hpp"
#pragma hdrstop
#include "FMXPrintUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"
TMainFMXForm *MainFMXForm;
//---------------------------------------------------------------------------
__fastcall TMainFMXForm::TMainFMXForm(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::PrintMenuItemClick(TObject *Sender)
{
TRectF SrcRect, DestRect;
if (PrintDialog1->Execute()) {
// Set the default DPI for the printer. The SelectDPI routine defaults
// to the closest available resolution as reported by the driver.
// Printer->ActivePrinter->SelectDPI(1200, 1200);
// Printer->ActivePrinter->ActiveDPIIndex = 1; // you can also the DPI index
// Set canvas filling style
// Printer->Canvas->Fill->Color = claBlack;
// Printer->Canvas->Fill->Kind = TBrushKind(1);
// Start printing
Printer::Printer()->BeginDoc();
// Set the Source and Destination TRects
SrcRect = TRectF(0, 0, Image1->Bitmap->Width, Image1->Bitmap->Height);
DestRect = TRectF(0, 0, Printer::Printer()->PageWidth, Printer::Printer()->PageHeight);
// Print the picture, on all the surface of the page and all opaque.
Printer::Printer()->Canvas->DrawBitmap(Image1->Bitmap, SrcRect, DestRect, 1);
// Finish the printing job
Printer::Printer()->EndDoc();
}
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::OpenBitmapMenuItemClick(TObject *Sender)
{
// open a bitmap for printing
if (OpenDialog1->Execute()) {
Image1->Bitmap->LoadFromFile(OpenDialog1->FileName);
PrintMenuItem->Enabled = true;
PrinterSetupMenuItem->Enabled = true;
PictureLoaded = true;
}
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::ExitMenuItemClick(TObject *Sender)
{
// exit the application
Application->Terminate();
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::PrinterSetupMenuItemClick(TObject *Sender)
{
// use the Printer Setup dialog box
PrinterSetupDialog1->Execute();
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::FormShow(TObject *Sender)
{
// on form show event handler
PictureLoaded = false;
PrintToPrinterDestinationMenuItem->IsChecked = true;
PrintToFileDestinationMenuItem->IsChecked = false;
// populate the ComboBox with the printer device names
PrintersComboBox->ItemIndex = 0;
for (int i = 0; i < Printer::Printer()->Count-1; i++) {
PrintersComboBox->Items->Add(Printer::Printer()->Printers[i]->Title);
// set the ComboBox ItemIndex to the active printer
if (Printer::Printer()->Printers[i]->Title == Printer::Printer()->ActivePrinter->Title) {
PrintersComboBox->ItemIndex = i;
}
}
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::PrintToPrinterDestinationMenuItemClick(TObject *Sender)
{
// set menu item checked for print to printer
PrintToPrinterDestinationMenuItem->IsChecked = true;
PrintToFileDestinationMenuItem->IsChecked = false;
// set PrintDialog PrintToFile checkbox off
// Note: to allow user to override the menu item - make sure
// PrintDialog Options poPrintToFile is set to true
// so that the PrintToFile checkbox appears in the dialog
PrintDialog1->PrintToFile = false;
}
//---------------------------------------------------------------------------
void __fastcall TMainFMXForm::PrintToFileDestinationMenuItemClick(TObject *Sender)
{
// set menu item checked for print to file
PrintToPrinterDestinationMenuItem->IsChecked = false;
PrintToFileDestinationMenuItem->IsChecked = true;
// set PrintDialog PrintToFile checkbox on
// Note: to allow user to override the menu item - make sure
// PrintDialog Options poPrintToFile is set to true
// so that the PrintToFile checkbox appears in the dialog
PrintDialog1->PrintToFile = true;
}
//---------------------------------------------------------------------------
The VCL and FMX applications in Action


References
VCL Printing
Printing in VCL Applications
Vcl.Printers
FMX Printing
Printing from a FireMonkey Application
FMX.Printer
YouTube Videos
Creating your First VCL Application for Windows with C++Builder
Creating Your First C++ Windows App
Why C++Builder?
Source Code
Source Code for VCL and FMX printing projects (zip file)
About C++Builder
C++Builder Product Page – Native Apps that Perform. Build Windows C++ Apps 10x Faster with Less Code
C++Builder Product Editions – C++Builder is available in four editions – Professional, Enterprise, Architect and Community (free). C++Builder is also available as part of the RAD Studio development suite.