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.