C++ is probably the most powerful programming language and one of the world’s most popular programming languages with many variables, functions, methods, namespaces and libraries to help you solve a multitude of problems. Using a fast and reliable C++ IDE is very important for beginners and professionals alike to ensure that when they develop C++ apps for Windows – and for other operating systems – the process is as smooth and as efficient as possible. When a user wants to develop modern C++ applications taking the time to learn to use a professional IDE pays dividends in efficiency, accuracy of the final solution and speed. In this post we explain the basics of C++ Builder as a guide for those who are taking those first tentative steps on the path to becoming a developer.
What is an IDE?
An integrated development environment (IDE) is a software application that provides a complete set of features for application development. Code is generally written in text format, and you can easily edit or modify your code using text editors like Notepad, Word, WordPad, etc. For a developer (beginner or professional), however, an IDE is really important because features like highlights, auto code completion and help system, and the opportunity to run, test, debug, deploy, merge or transform code on other platforms (multiplatform coding) are also important. All these capabilities require a powerful IDE.
Step 1. Download the free C++ Builder Community Edition
If you are new to C++ and want to compile a code first time we recommend you free C++ Builder Community Edition for students, beginners, and startups. C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, macOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. C++ Builder comes with Rapid Application Development Studio, also known as RAD Studio, and C++ Builder is one of the most professional IDE’s that work under RAD Studio. It is the oldest IDE (it began as Borland TurboC in 1990 and was later renamed Borland C++ Builder). Under the Embarcadero brand, it comes with new versions, features, updates, and support. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs. More details about C++ Builder & RAD Studio for the beginners can be found in Official Wiki of Rad Studio.
Here are the features of the C++ Builder CE version;
- Build Windows and iOS C++ Applications 10x Faster with Less Code.
- C++Builder Community Edition provides you with an integrated toolchain and professional-level developer tools from Day 1
- Featuring Clang-enhanced compiler, Dinkumware standard library, MSBuild/CMake/Ninja support, and popular libraries like Boost and Eigen.
- Develop Windows and iOS applications with a single codebase and responsive UI
- Enjoy the award winning Visual Designer using the C++Builder VCL and FireMonkey frameworks for maximum productivity
- Built-in Debugging Tools that allow you to debug on any device
- Build database apps with local/embedded capabilities
- Hundreds of included components to enhance your app and reduce development cycles
- Direct access to InterBase, SQLite, MySQL, SQL Server, Oracle, PostgreSQL, DB2, SQL Anywhere, Advantage DB, Firebird, Access, Informix, MongoDB, and more.
- Licensed for use until your individual revenue from C++Builder applications or company revenue reaches $5,000 US or your development team expands to more than 5 developers
C++ Builder CE is the easiest and fastest C & C++ IDE for developing simple or professional applications on different operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files and LSP support. C++ Builder comes with Rapid Application Development Studio, also knowns as RAD Studio, and C++ Builder is one of the most professional IDEs that work under RAD Studio.
You can download the free C++ Builder Community Edition here: https://www.embarcadero.com/products/cbuilder/starter.Professional developers can use the Professional, Architect or Enterprise versions of C++ Builder which can be found at https://www.embarcadero.com/products/cbuilder.
Step 2. Start creating modern visually appealing C++ applications
Ok, so, there’s a little more to it than downloading the IDE and just getting on with it!
If you want to know how to compile modern, visually appealing applications in C++, you can start with a simple example with some visual components. This first simple application is good to understand how to edit text, how to format the text, how to compile the test application and link it, how to debug the app and execute it, how to deploy or release it ready for your end-users. We will start with a simple app.
Now let’s create a modern C++ example in C++ Builder. In our first application we will create a windows application which has visual input and output UI elements. Our application will get width of a square and it will calculate the area of this square. This simple example helps us understand how C++ Builder integrates with C++ code and its VCL (VisualComponentLibrary) or FMX (FireMonkey) framework. Let’s see the steps to create this application,
- Open C++ Builder or the RAD Studio IDE.
- Create a new Windows VCL Application in C++ Builder. This will allow you develop C++ apps with VCL UI elements. Or you can create a new MultiDevice Application in C++ Builder. You can select both from the File->New IDE menu. Selecting “multi device application” will allow you develop C++ apps which use FireMonkey UI elements to create apps which can work on Windows, macOS, Linux, iOS and Android. However, in this example we will be using the “Windows VCL Application” option which only works on Microsoft Windows.
- Once the initial blank app has been created by the IDE, save all units and project files with “MyFirstApp_” prefix in a HelloWorld folder.
- Now add a Label (TLabel), Edit (TEdit), Memo (TMemo) and a Button (TButton) from the Palette to your Form. When you drag these component classes, they will create class objects of these components: Label1, Edit1, Memo1, Button1. Here our Edit1 object is a good input component to get values. The Memo1 object is good to display all test output as in console applications.
- Click the Memo1 object and find the Lines property from the Object Inspector on the left side. Now click […] (the ellipsis) next to the edit text lines of this Memo. A text editor window will open allowing you to edit the string list. In this String List Editor, delete any default text inside and add “
Welcome to My First App
” or your own choice of words as given below,
Press “OK” to accept and exit from the String List Editor
6. Click the Label1 object, If you are developing VCL C++ app find the Caption
property from the Object Inspector. If you are developing a FireMonkey C++ app find the Text
property from the Object Inspector. Change it’s text value to “Width”
7. Click the Edit1 object, find the Text property from the Object Inspector. Change its text value to “10”. This will be our default text when the application runs.
8. Click the Button1 object. If you are developing a VCL C++ app, find the Caption
property from the Object Inspector. If you are developing a FireMonkey C++ app find the Text
property from the Object Inspector. Change its text value to “Calculate” . Arrange their size and positions by dragging them and by using their corners as shown in the example below,
9. Double click the Button1 (Calculate Button) to create OnClick() event, inside that Button1Click event write lines as given full example below,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#include <vcl.h> #pragma hdrstop #include «Unit1.h» //————————————————————————— #pragma package(smart_init) #pragma resource «*.dfm» TForm1 *Form1; //————————————————————————— __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //————————————————————————— void __fastcall TForm1::Button1Click(TObject *Sender) { // Get Inputs float a = StrToInt(Edit1->Text); // Calculate float area = a*a; // Put Outputs Memo1->Lines->Add( u«Width of Square: « + Edit1->Text ); Memo1->Lines->Add( u«Area of Square: « + FloatToStr( area ) ); } |
Here when user clicks to Button1 (Calculate Button) it will get Input from Edit1, it will calculate the area of the square and we will add the input and output results to the lines of Memo1.
If you are beginner, you can think that inside of this Button1Click() is like the inside of the main()
function or a similar function in C++. In reality it is a method used by the Form1 object class.
10. Run the project by hitting F9 or click Run with Debugging. You can also select Run without Debugging although moat of the time you’re not going to select that while you are writing and testing your program.
This will create a Window Form with your UI elements. You can calculate the area of the square with the given width value. Change the width value to 50 and hit calculate or change to 999 and calculate. The results and the Window Form of our first C++ application should be like this below,
11. If there is an error, please check your lines of code to make sure they match those of our example. The C++ programming language is case sensitive. Also, don’t forget to put “;” (semicolon) at the end of statements and the “{” and “}” begin/end braces.
12. If all is fine then the project
13. if you check your header file you will see all your objects (Label1, Edit1, Memo1, Button1 etc.) are automatically defined as below. You don’t need to change anything here
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#ifndef MyFirstApp_Unit1H #define MyFirstApp_Unit1H //————————————————————————— #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> //————————————————————————— class TForm1 : public TForm { __published: // IDE-managed Components TEdit *Edit1; TLabel *Label1; TMemo *Memo1; TButton *Button1; void __fastcall Button1Click(TObject *Sender); private: // User declarations public: // User declarations __fastcall TForm1(TComponent* Owner); }; //————————————————————————— extern PACKAGE TForm1 *Form1; //————————————————————————— #endif |
As ın this example, modern C++ applications have a GUI (Graphical User Interface) and they should be compatible with other operating systems (Windows, MacOS, iOS, Android). FireMonkey projects are multi Device (multi-platform) applications that you can compile and run on Windows, MacOS, iOS and Android .You can try recreating the example above with as a FireMonkey (FMX) application.
More beginner’s examples can be found in the Introduction section of https://learncplusplus.org/ and in Embarcadero DocWiki https://docwiki.embarcadero.com/ example links.
Get to know the basic features of Visual Studio C++ as well as the rich collection of String operations in this article.
The latest new posts along with more examples and tutorials can be found at blogs.embarcadero.com and LearnCPlusPlus.org.
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.
Published by David Intersimone «David I»
David Intersimone, known to many as «David I», is a passionate and innovative software industry veteran who extols and educates the world on developer tools, software development and software architectures. David I joined Borland Software in 1985 where he practically invented Developer Relations. During David I’s forty-three years as a developer, development manager, developer community executive, development cheerleader, and developer advocate, he has created a thriving global developer community, thousands of articles, videos and blog posts.
Before Embarcadero acquired the developer tools business from Borland Software, David spent more than 20 years with Borland in various evangelism, engineering, and development capacities, including creating the company’s developer relations program.
Today, David I shares his visions and insights as a pioneer in developer relations with program managers, directors and developers where he gives workshops, webinars, guidance and advice on developer communities, developer advocacy and software development.
View all posts by David Intersimone «David I»
Published
10.
СОЗДАНИЕ ПРИЛОЖЕНИЙ В СРЕДЕ C++ BUILDER.
РАБОТА
С КОМПОНЕНТАМИ БИБЛИОТЕКИ VCL
Цель этого подраздела
состоит в том, чтобы научить читателя разрабатывать прикладные программы
(приложения) в среде Windows, используя язык программирования С++,
библиотеку визуальных компонентов Visual Component Lybrary VCL
и среду программирования C++ Builder.
В подразделе рассмотрена
иерархия классов библиотеки VCL, изложены вопросы
обеспечения работы приложения без сбоев, приведено большое количество примеров
разработки приложений, использующих различные компоненты библиотеки VCL.
Большинство примеров программ являются достаточно короткими, так как они
предназначены для демонстрации излагаемого материала.
Для понимания изложенного
материала читатель должен быть знаком с языком программирования С++ и
основами объектно-ориентированного программирования.
10.1.
Иерархия классов VCL
Библиотека VCL
построена на основе принципа наследования и образует иерархию классов. Основу
библиотеки VCL составляют классы, представляющие компоненты (рис. 10.1).
Каждый объект представляет некоторый набор методов, событий и свойств и имеет
специальное назначение.
Базовым классом для всех
порождаемых классов является класс TObject. Он инкапсулирует общее для всех объектов системы C++ Builder
функциональное поведение, обусловленное методами, которые обеспечивают
выполнение следующих действий:
– способность конструктора
создавать, а деструктора разрушать объект-экземпляр класса в динамической
памяти. Конструктор TObject возвращает
указатель на создаваемый объект;
– представление информации
об имени, типе производного объекта и его свойствах, которые объявлены как _published;
– поддержку обработки
сообщений
Большинство этих методов
предназначены для внутреннего использования средой C++ Builder, поэтому
не следует обращаться к ним непосредственно из программы. Часть методов класса TObject объявлены как статические (с
ключевым словом static). Это означает, что вам не нужно создавать
экземпляр данного класса для того, чтобы обратиться к его статическим методам.
Класс TPersistent непосредственно произведен от класса TObject. Этот абстрактный класс не
определяет никаких специальных свойств или событий, однако его производные
приобретают особые способности присваивания и поточности.
Класс
TPersistent определяет ряд поточных методов, используемых
разработчиками компонентов, которые могут быть перегружены производными
компонентами:
– Assign позволяет присваивать значения свойствам;
– AssignTo позволяет
присваивать содержимое одного объекта другому (например, как это делает
производный от TPersistent класс TClipboard);
– DefineProperties
позволяет определить процедуру загрузки и сохранения в потоке особых
дополнительных свойств. По умолчанию сохраняются только свойства, объявленные
как _published.
Рис.
10.1. Иерархия ключевых базовых классов библиотеки VCL
Подобно тому как TObject является базовым классом для
всех порождаемых классов, класс TComponent является базовым классом для
всех порождаемых компонентов: все компоненты должны порождаться непосредственно
от класса TComponent или от его
потомков. Этот класс определяет ряд методов, которые придают объекту право
владения другими компонентами и возможность доступа к ним посредством
инспектора объектов. Свойства и методы
класса TComponent обеспечивают поддержку для всех компонентов
библиотеки VCL
следующих действий и возможностей:
– перенос на форму из
палитры компонентов и манипуляции в окне редактора форм;
– способность владения и
обслуживания других компонентов;
– специальные характеристики
поточности, с которыми может манипулировать инспектор объектов на этапе
проектирования;
– возможность
манипулирования некоторыми невидимыми компонентами на стадии проектирования.
Невизуальные компоненты произведены
от класса TComponent. Графические компоненты, не
ассоциированные с оконными элементами управления, произведены от класса TGraphicControl.
Общие для видимых компонент
члены данных, методы и события определяет класс TControl.
Таким образом, программист создает законченное
приложение посредством интерактивного взаимодействия с интегрированной
визуальной средой C++Builder, используя компоненты VCL для
создания интерфейса программы с пользователем. Все компоненты являются прямыми
или косвенными потомками одного общего класса-прародителя TComponent.
Знание классов библиотеки VCL необходимо программисту как для успешного использования
этой библиотеки при разработке
приложений, так и для создания собственных компонент.
Ниже более подробно рассмотрены многие классы и
компоненты библиотеки VCL, а
также приведены примеры их применения.
10.2. Обеспечение бессбойной работы приложений
Среда программирования C++
Builder предусматривает специальные механизмы для обработки исключений
(ошибок), которые могут возникнуть при использовании библиотеки VCL.
C++ Builder также поддерживает обработку исключений самой операционной
системы и модель завершения работы приложения. Если исключение не будет
перехвачено нигде в программе, то оно обрабатывается методом Application – >HandleException, который обеспечивает
стандартную реакцию программы на большинство исключений и выдачу пользователю
краткой информации в окне сообщений об аварийном завершении приложения.
Некоторые наиболее часто
встречающиеся классы исключений системы C++ Builder приведены в
табл. 10.1.
Следует иметь в виду, что
при отладке программы в среде C++ Builder могут появляться сообщения
отладчика, мешающие работе. Появление этих сообщений можно отключить и тогда
приложение в процессе отладки будет вести себя так же, как и при обычном
запуске. Для отключения сообщений отладчика можно выполнить следующие действия:
1. В меню Tolls / Debugger Otions перейти на страницу Language Exception.
2. На странице Language Exception выключить опции Stop on Delphi Exception и Stop on C++ Exception.
Таблица
10.1.
Классы исключений системы C++ Bulder
Имя класса |
Причина |
EDivByZero |
Попытка |
EIntOverflow |
Переполнение при целочисленных операциях |
EZeroDivide |
Деление на нуль |
EOverflow |
Переполнение в операциях с плавающей запятой |
EOutOfMemory |
Не хватает места при |
EConvertError |
Ошибки преобразования, |
Таким образом, среда C++
Builder предоставляет в распоряжение программиста классы библиотеки VCL,
поддерживающие обработку исключительных ситуаций. В процессе отладки приложения
могут появляться мешающие работе сообщения отладчика среды C++ Builder,
однако их можно отключить.
Примеры программ, в которых
предусмотрена обработка исключений, будут представлены ниже в пп.10.3.1 и
10.3.2.
10.3.
Обработка событий в компонентах
Управление процессами в
прикладных программах производится с
помощью создания обработчиков событий.
Источником событий в приложении прежде всего
является пользователь. Многие действия пользователя: перемещение мыши, нажатие
кнопок мыши и клавиш на клавиатуре и т. д. вызывают в приложении какие-то события.
Основным приемником событий, связанных с нажатием кнопок и клавиш, является
компонент, который в данный момент находится в фокусе. Это может быть
управляющий компонент или один из компонентов отображения и ввода информации. В
любом компоненте определены события, на которые он может реагировать.
Для того чтобы написать обработчик
события какого-то компонента, нужно выделить этот компонент на форме и в окне
инспектора объектов перейти на страницу событий. В списке событий следует найти
требуемое и сделать двойной щелчок в окне, правее имени события, при этом будет
открыто окно редактора кода, в котором
уже будет занесена заготовка обработчика. В заготовке следует записать код
функции – обработчика события.
Практически во все обработчики событий
передается параметр Tobject *Sender – указатель на объект класса TОbject. Sender является указателем на тот компонент, который воспринял
происшедшее событие. Если нужно написать обработчик только для одного события,
то параметр Sender не нужен,
поскольку источник события известен. Более подробно о параметре Sender будет рассказано в пп. 10.3.2.
2.3.1. Компонент окна
редактирования Edit
Компонент окна
редактирования Edit позволяет выполнять отображение,
ввод и редактирование однострочных текстов. Его пиктограмма находится на странице Standart библиотеки VCL. Основное свойство этого
компонента – Text, имеющее тип AnsiString. Если в этот компонент
требуется занести число, то следует использовать функции StrToFloat() или StrToInt(), преобразующие
символьное изображение числа в его значение типа вещественного или целого числа.
Работу с
компонентом Edit рассмотрим на примере
разработки приложения, выполняющего деление двух действительных чисел:
1. Откройте
новое приложение, выполнив для этого команду File| New Application.
Перенесите на форму со страницы библиотеки Standart два окна редактирования Edit, одну панель Panel,
одну кнопку Button и три метки Label для надписей. Разместите все это
примерно так, как показано на рис.10.2. Выровняйте компоненты, чтобы они
располагались в горизонтальном направлении по центру окна
2. Измените надписи в метках
(свойство Caption), например, на Число 1, Число 2, Результат. Полезно задать
для меток жирный шрифт.
3. Замените свойство Caption
вашей кнопки, например, на Расчет. Очистите свойство Caption у
панели. В свойстве Тeхt (текст) окон редактирования задайте 1 для
окна Edit1 и 2 для окна Edit2 – это начальное значение
текста.
4. Попробуйте установить
такие свойства панели, как BevelInner и BevelOuter, которые
определяют вид (утопленный – byLowered или выпуклый – byRaised)
основного поля и рамки панели. Например, можете установить BevelInner = byLowered и BevelOuter
= byRaised.
Пример кода функции –
обработчика щелчка по кнопке приведен в листинге 10.3. В этом листинге вывод
результата – числа вещественного типа выполняется в компонент Panel.
Текст, отображаемый в этом компоненте, определяется его свойством Caption,
имеющим тип AnsiString. Для вывода числовой информации в свойство Caption следует использовать функции FloatToStr и IntToStr, переводящие соответственно вещественные и целые числа
в строку.
Label1 Edit1 Label2
Edit2
Рис.
10.2. Приложение в процессе проектирования
Листинг
10.3. Код функции – обработчика щелчка по кнопке Button1
void __fastcall TForm1 ::
Button1Click(TObject *Sender)
{
float a, b, c;
// контроль
преобразования строки, введенной в окно редактирования
// Edit1, в вещественное число
try
{
a = StrToFloat(Edit1 –> Text);
}
// если в
процессе преобразования строки из окна Edit1 в число возникла ошибка
catch (EСonvertError &)
{
// вывод
сообщения об ошибке
Application –> MessageBox («Вы ввели
ошибочное первое число», «Повторите ввод», MB_OK);
Edit1 –> Text = «»; //
очистка окна редактирования Edit1
return; // возврат из
функции
}
// контроль
преобразования строки, введенной в окно редактирования
// Edit2, в вещественное число
try
{
b = StrToFloat(Edit2 –> Text);
}
// если в
процессе преобразования строки из окна Edit2 в число возникла ошибка
catch (EconvertError
&)
{
Application –> MessageBox («Вы ввели
ошибочное второе число», «Повторите ввод», MB_OK);
Edit2 –> Text = «»; //
очистка окна редактирования Edit2
return ;
}
// контроль
выполнения операции деления
try
{
a / b;
}
// если была
предпринята попытка деления на нуль
catch(EZeroDivide &)
{
Application –> MessageBox («На нуль делить нельзя!», «Повторите
ввод второго числа», MB_OK);
Edit2 –> Text = «»;
return;
}
c = a / b;
// вывод
результата в панель
Panel1 –> Caption = Edit1 –>
Text + «/» + Edit2 –> Text + » = » + FloatToStr(c);
Edit1 –> Text = «»;
Edit2 –> Text = «»;
}
Если пользователь ввел неверное число (например, по ошибке нажал не
цифру, а какой-то буквенный символ), то при выполнении функции StrToFloat возникнет исключение класса EСonvertError. Соответствующий обработчик
исключения сообщит пользователю о сделанной ошибке и посоветует повторить ввод.
Аналогичная реакция возникает при вводе пользователем в качестве делителя нуля
(класс исключения EZeroDivide).
Сделаем интерфейс нашего приложения более удобным и наглядным для
пользователя. Для этого снабдим его компоненты ярлычками с подсказками, которые
будут всплывать, если пользователь задержит курсор мыши над компонентом. Для
задания текстов этих ярлычков служит свойство Нint, имеющееся
почти у всех визуальных компонентов. Выделите например, на своей форме
компонент Еdit1, и вы увидите это свойство в окне
инспектора объектов. Напишите в нем краткое пояснение назначения компонента, например,
Первое число. Это и будет текстом ярлычка. Но для того чтобы этот
ярлычок всплывал при задержке курсора мыши над компонентом, нужно еще
установить свойство ShowHint – показ
ярлычка в true. Проделайте аналогичную
операцию с другим окном редактирования, с панелью и кнопкой, помещая в них в
свойство Hint соответствующие пояснения.
Запустите приложение, и вы увидите, как всплывают ярлычки, когда пользователь
задерживает курсор мыши над соответствующим компонентом.
10.3.2.
Распознавание источника события (параметр Sender)
Параметр Sender
типа TObject передается во все обработчики событий. Этот параметр
содержит указатель на компонент, в котором произошло событие. Он не нужен, если
пишется обработчик события для одного конкретного компонента. Однако часто один
обработчик применяется для нескольких компонентов. Тогда параметр Sender
можно использовать для распознавания источника события. Однако поскольку тип TОbject не
имеет никаких полезных для пользователя свойств и методов, то объект Sender следует рассматривать как объект одного из
производных от TОbject типов.
Если требуется распознавать
только тип объекта, то можно использовать функцию ClassNameIs. Например, оператор:
if
(Sender –> ClassNameIs (“TlistBox”))
проверяет, не является ли источник события
компонентом типа TlistBox.
Если требуется распознать
источник события по имени компонента или другому его свойству, то можно
использовать операцию явного приведения типа указателя к указателю на объект
определенного класса. Например, оператор
if
(((TСomponent *)Sender –> Name == “Edit1”)
проверяет,
является ли этот компонент компонентом с именем Edit.
Если надо только проверить,
является ли Sender определенным компонентом, то можно поступить проще:
if
(Sender == Edit1)
Пример использования
параметра Sender в программе, в окне которой
расположены два компонента Edit, четыре кнопки и компонент Panel,
приведен в листинге 10.4. При работе приложения в окна редактирования вводятся
числа, с помощью кнопок выбирается выполняемая операция (сложение, вычитание,
умножение и деление), а в панель выводится результат. Ниже записан единый
обработчик событий для всех четырех кнопок. Параметр Sender используется для
распознавания источника события.
Листинг 10.4. Использование
параметра Sender
для распознавания источника события
#include <vcl.h>
#pragma hdrstop
#include «Ucalk.h»
//—————————————————————————
#pragma package(smart_init)
#pragma resource «*.dfm»
TForm1 *Form1;
float x, y, z;
// глобальные переменные
//—————————————————————————
__fastcall TForm1 ::
TForm1(Tcomponent *Owner) : TForm(Owner) {
}
// обработка события OnClick
– нажатия любой кнопки на окне приложения
//—————————————————————————
void __fastcall TForm1 ::
Button1Click(TObject *Sender)
{
try
{
x = StrToFloat(Edit1 –> Text);
}
catch (EConvertError&)
{
Application –> MessageBox («Вы ввели ошибочное первое число»,
«Повторите ввод», MB_OK);
return;
}
try
{
y = StrToFloat(Edit2 –> Text);
}
catch (EConvertError&)
{
Application –> MessageBox («Вы ввели ошибочное второе число»,
«Повторите ввод», MB_OK);
return;
}
//распознавание
источника события
if(Sender == Button1)
{
z = x + y;
}
if(Sender== Button2)
{
z=x – y;
}
if(Sender == Button3)
{
z = x * y;
}
if(Sender == Button4)
{
try
{
x / y;
}
catch (EZeroDivide&)
{
Application –> MessageBox («На нуль делить нельзя», «Повторите
ввод», MB_OK);
return;
}
z = x / y;
}
Panel1 –> Caption = FloatToStr(z);
}
//—————————————————————————
2.3.3. Радиокнопки
(компоненты RadioButton и GroupBox)
Радиокнопки представляют собой круглые
кнопки с двумя состояниями и описательным текстом, поясняющим их назначение.
Радиокнопки представляют пользователю набор взаимоисключающих вариантов –только
одна кнопка в данный момент времени может быть выбрана (отмечается внутренним
черным кружком).
Работу с радиокнопками рассмотрим на примере
разработки приложения, выполняющего перезагрузку или завершение работы Windows
в зависимости от выбора пользователя (рис. 2.3.)
Для разработки приложения выполните следующие
шаги:
1. Откройте новое
приложение, выполнив для этого команду File | New Application.
Перенесите на форму со страницы библиотеки Standart панель GroupBox.
Эта панель сама по себе пуста. Она предназначена служить контейнером для других
управляющих элементов, в частности, радиокнопок RadioButton. Перенесите на форму две радиокнопки RadioButton и две кнопки Button. С помощью радиокнопок пользователь будет делать выбор, а с
помощью кнопок – подтверждать свои действия. Разместите компоненты так, как показано на рис. 10.3.
2. Измените свойства Cарtion
радиокнопок на надпись, которая должна появиться справа от радиокнопок в окне,
а свойства Cарtion кнопок – на текст надписи на них.
3. Установите для первой радиокнопки свойство
Checked равным true. Это означает, что первая радиокнопка в
начале выполнения приложения будет выбрана по умолчанию. Следует заметить, что
свойство Checked может быть установлено в значение true только для одной радиокнопки из группы.
4. Запишите коды для обработчиков событий –
щелчков по радиокнопкам и по кнопкам.
При нажатии радиокнопки свойство компонента Checked меняется на
противоположное и возникает событие OnClick.
|
Рис.10.3. Вид окна приложения для завершения работы Windows
Коды функций – обработчиков событий приведены
в листинге 10.5. Для перезагрузки операционной системы использована функция Windows
API ExitWindowsEx, первый из параметров которой определяет способ завершения
работы Windows.
Листинг 10.5. Коды функций –
обработчиков событий приложения для перезагрузки или завершения работы Windows.
// переменная, объявленная программистом и хранящая
// индекс нажатой
радиокнопки: 0 – для первой, 1 – для второй
int Radio;
// обработка события OnClick
– нажатия кнопки Отмена
//—————————————————————————
void __fastcall TForm1 ::
Button2Click(TObject *Sender)
{
// функция, закрывающая
окно приложения – выход из приложения
Close();
}
// обработка события OnClick
– нажатия кнопки ДА
//—————————————————————————
void __fastcall TForm1 :: Button1Click(TObject
*Sender)
{
// выбор действия, в
зависимости от того, какая радиокнопка была нажата
switch (Radio)
{
case 0: // была нажата первая радиокнопка – Выключить
компьютер
// вызов функции
API для завершения работы Windows
ExitWindowsEx(EWX_SHUTDOWN,0);
break;
case 1: // была нажата вторая радиокнопка – Перезагрузить
компьютер
//вызов функции API
для перезагрузки Windows
ExitWindowsEx(EWX_REBOOT, 0 );
break;
}
}
// обработка события OnClick
– нажатия первой радиокнопки
//—————————————————————————
void __fastcall TForm1 :: RadioButton1Click(TObject
*Sender)
{
Radio = 0;
}
// обработка события OnClick
– нажатия второй радиокнопки
//—————————————————————————
void __fastcall TForm1 ::
RadioButton2Click(TObject *Sender)
{
Radio = 1;
}
//—————————————————————————
10.3.4. Таймер (компонент Timer)
Таймер в Windows является
устройством ввода информации, которое периодически извещает приложение о том,
что истек заданный интервал времени. Программа задает интервал, с которым Windows
периодически посылает приложению сообщение
WM_TIMER.
Таймер находит широкое
применение в программах, например для реализации автосохранения, завершения
демонстрационных версий программ, включения хранителя экрана, задания времени
на ответ в обучающих программах, синхронизации мультипликации и др.
Таймер – невизуальный
компонент, который может размещаться в любом месте формы. Он имеет два
свойства, позволяющие им управлять: Interval
– интервал времени в миллисекундах и Enabled
– доступность. Свойство Interval задает
период срабатывания таймера. Через заданный интервал времени после предыдущего
срабатывания, или после программной установки свойства Interval, или после запуска приложения, если значение Interval установлено во время
проектирования, таймер срабатывает, вызывая событие OnTimer.
Если задать Interval = 0 или Enabled = false, то таймер перестает работает работать.
Чтобы запустить отсчет времени нужно задать Enabled = true, если
установлено положительное значение свойства Interval. Таймер точно выдерживает заданные интервалы Interval, если они достаточно велики
– сотни и тысячи миллисекунд. А если задавать интервалы длительностью десятки
или единицы миллисекунд, то реальные интервалы времени оказываются заметно
больше вследствие различных накладных расходов, связанных с вызовами функций.
Рассмотрим последовательность разработки приложения, в котором организован вывод бегущей строки и изменение
цвета выведенной строки в процессе работы приложения.
Для разработки приложения выполните следующие
действия:
1. Откройте новое приложение, выполнив команду File | New
Application. Занесите заголовок окна приложения: Использование таймера
для движения строки в свойство Caption формы. Свойству ClientHeigt
(высота окна приложения) формы присвойте значение 288, а свойству ClientWidth
(ширина окна приложения) – значение 449. Свойство BorderStyle формы
установите равным bsDialog, чтобы запретить пользователю изменять
размеры окна в процессе работы приложения.
2. Перенесите на форму со страницы System библиотеки визуальных
компонентов компонент Timer. Установите свойство Interval таймера
равным значению 500 мс (0,5 с). Перенесите на форму
со страницы библиотеки Standart
компонент Edit и две панели GroupBox.
Перенесите на левую панель четыре радиокнопки RadioButton, на правую – две
обычные кнопки Button.
3. Для окна редактирования в свойстве Font задайте шрифт – Tahoma,
начертание – полужирный наклонный, размер – 24, цвет – черный. Очистите
свойство Тeхt (текст) окна редактирования.
4. Измените свойства Cарtion панелей,
радиокнопок и кнопок на соответствующие
надписи, как показано на рис.2.4. Установите свойство Font радиокнопок, задавая
цвет шрифта их надписей: для первой – красный, для второй – зеленый, для
третьей – синий, для четвертой – черный.
5. Установите свойство Checked для
четвертой радиокнопки в значение true. Это означает, что четвертая
радиокнопка в начале выполнения приложения будет выбрана по умолчанию.
6. Запишите коды для обработчиков событий:
события срабатывания таймера OnTimer, событий OnClick щелчков по радиокнопкам и по кнопкам. В
обработчике события OnTimer перемещение строки имитируется циклическим
сдвигом влево на 1 символ (вращением) содержимого свойства Text окна
редактирования Edit. Обычные кнопки регулируют с дискретностью 0,1 с
частоту обновления строки и, следовательно, видимую скорость ее движения. Коды
функций – обработчиков событий приведены в листинге 10.6.
7. Откомпилируйте и запустите разработанное
приложение. Сохраните файлы проекта.
|
Рис. 10.4. Форма в
приложения в процессе проектирования
Листинг 10.6. Коды функций –обработчиков
событий приложения, выводящего на экран бегущую строку
// реакция на выбор первой радиокнопки
//—————————————————————————
void
__fastcall TForm1 :: RadioButton1Click(TObject *Sender)
{
TRadioButton
*rbutton = (TRadioButton*) Sender;
// задание цвета в окне редактирования равным цвету
шрифта радиокнопки
Edit1
–> Font->Color = rbutton –> Font –> Color;
}
// реакция на выбор второй радиокнопки
//—————————————————————————
void
__fastcall TForm1 :: RadioButton2Click(TObject *Sender)
{
TRadioButton
*rbutton = (TRadioButton*) Sender;
Edit1
–> Font –> Color = rbutton –>
Font –> Color;
}
// реакция на выбор третьей радиокнопки
//—————————————————————————
void
__fastcall TForm1 :: RadioButton3Click(TObject *Sender)
{
TRadioButton
*rbutton =(TRadioButton*) Sender;
Edit1
–> Font –> Color = rbutton –> Font –> Color;
}
// реакция на выбор четвертой радиокнопки
//—————————————————————————
void
__fastcall TForm1 :: RadioButton4Click(TObject *Sender)
{
TRadioButton
*rbutton = (TRadioButton*) Sender;
Edit1
–> Font –> Color = rbutton –>
Font –> Color;
}
// обработка события таймера – истечения заданного
интервала времени
//—————————————————————————
void
__fastcall TForm1 :: Timer1Timer(TObject *Sender)
{
// буфер, содержащий строку для вывода в окне
static
char str[] =» Покрась меня … «;
// очистка
окна редактирования
Edit1 –> Clear();
// вывод в окно редактирования текста из буфера str
Edit1
–> Text = str;
//присваивание переменной first значения
первого символа
для вывода
char
first = str[0];
//организация циклического сдвига строки на один
символ влево
for(int
i = 0; i < 27; i++)
str[i]
= str[i + 1];
str[27] = first;
}
// реакция на нажатие кнопки Быстрее
//—————————————————————————
void
__fastcall TForm1 :: Button2Click(TObject *Sender)
{
if(Timer1
–> Interval <= 100)
return;
Timer1 –> Interval – = 100; //уменьшить
интервал срабатывания таймера
}
// реакция на нажатие кнопки Медленнее
//—————————————————————————
void
__fastcall TForm1 :: Button1Click(TObject *Sender)
{
if(Timer1
–> Interval –> 2000) return;
Timer1 –> Interval + = 100;
//увеличить интервал срабатывания таймера
}
//—————————————————————————
10.3.5.
Компоненты выбора из списков
Списки являются динамическими
структурами данных, размер которых может сокращаться или увеличиваться в
процессе работы программы. Запоминание объектов в списках – типичный прием
программирования. Например, программа рисования может хранить список
нарисованных объектов, а игровая программа – список игроков с наибольшим
рейтингом и параметры текущего состояния игры с тем, чтобы ее можно было продолжить.
Среда С++ Builder предоставляет такие списочные компоненты, как TListBox, TComboBox и др.
Все списки библиотеки VCL можно считать контейнерными
классами, они решают проблемы по динамическому распределению памяти под данные.
При использовании списков размер контейнера автоматически меняется, реагируя на
добавление или удаление своих элементов.
Разработаем приложение для
работы со списком. Откройте новый проект и разместите на форме компоненты ListBox,
Button и Edit, как показано на рис. 10.5.
Рис.10.5. Форма приложения
во время проектирования
Основное свойство компонента
ListBox – Items, имеющее тип TStrings (список строк). Во время выполнения программы можно работать с этим
свойством, пользуясь свойствами и методами этого класса, например Clear
(очистить список), Add (добавить строку в конец списка),
AddStrings (добавить группу строк в
список). Производный от класса TStrings класс TStringList добавляет следующие свойства:
– Sorted (выполнить
сортировку строк списка);
– Duplicates (запретить хранение дубликатов строк);
Текст файла реализации
модуля для работы со списком приведен в листинге 10.7.
Листинг 10.7. Текст файла
реализации модуля для работы со списком
//—————————————————————————-
#include <vcl.h>
#pragma hdrstop
#include «Unit1.h»
//—————————————————————————
#pragma package(smart_init)
#pragma resource «*.dfm»
TForm1 *Form1;
// создание
объекта MyList
производного от TStrings
класса TStringList
TStringList *MyList = new TStringList;
//—————————————————————————
// определение конструктора формы
__fastcall TForm1 :: TForm1(TComponent*
Owner : TForm(Owner)
{
// добавить элемент к концу списка
MyList –> Add(«Информатика»);
MyList –> Add(«Физика«);
MyList –> Add(«Математика»);
// игнорировать дубликаты
MyList –> Duplicates = dupIgnore;
// сортировать
список
MyList –> Sorted = true;
// добавить к
концу списка группу строк и отобразить их
ListBox1 –> Items –> AddStrings (MyList);
}
//—————————————————————————
// обработчик
щелчка по кнопке Добавить
void __fastcall TForm1 ::
Button1Click(TObject *Sender)
{
if(Edit1 –> Text ! =
«») // если строка в окне
редактирования не пустая
{
MyList –> Add(Edit1
–> Text); // добавить строку к списку
ListBox1 –> Clear(); // очистить список
ListBox1 –> Items –> AddStrings(MyList);
// отобразить список
}
}
// обработчик
события OnClose, возникающего при закрытии формы
//—————————————————————————
void __fastcall TForm1 ::
FormClose(TObject *Sender,
TCloseAction & Action)
{
delete MyList; // уничтожить объект
ShowMessage(«Список класса TStringList уничтожен«);
}
//—————————————————————————
Строки списка можно читать
из файла и сохранять в файле. Для этого следует использовать методы LoadFromFile и SaveToFile класса TStrings. Для демонстрации работы с этими методами внесем изменения в
разработанное нами приложение. Добавим на форму приложения вторую кнопку,
назвав ее, например, Сохранить. Для компонента ListBox1
установите свойство Sorted в true,
чтобы список выводился в отсортированном виде. Определения функций –
обработчиков событий в файле реализации модуля приведены в листинге 10.8.
Листинг
10.8. Определения функций – обработчиков событий
// создание
обекта MyList
производного от TStrings
класса TStringList
TStringList *MyList = new TStringList;
// конструктор формы
//—————————————————————————
__fastcall TForm1 :: TForm1(Tcomponent *Owner)
: TForm(Owner)
{
// считать из файла строки и отобразить их в
списке ListBox1
ListBox1 –> Items –> LoadFromFile(«names.txt»);
}
//—————————————————————————
// обработчик щелчка по кнопке Добавить
void __fastcall TForm1 :: Button1Click(TObject
*Sender)
{
if(Edit1 –> Text ! =
«») // если в окно
редактирования введен текст
{ //
добавить строку из окна редактирования в список
MyList
MyList –> Add(Edit1 –> Text);
ListBox1
–> Clear(); // очистить список
// добавить строку из списка MyList в список ListBox1
ListBox1 –> Items –> AddStrings(MyList);
}
}
//—————————————————————————
// обработчик события OnClose для
формы
void __fastcall TForm1 :: FormClose(TObject
*Sender, TCloseAction &Action)
{ // освободить память,
delete MyList;
ShowMessage(«Список класса TStringList
уничтожен»);
}
//—————————————————————————
// обработчик щелчка по кнопке Сохранить
void __fastcall TForm1 :: Button2Click(TObject
*Sender)
{
// сохранить список в файле
ListBox1 –> Items –>
SaveToFile(«names.txt»);
}
//—————————————————————————
Таким образом, проектирование приложений в среде C++
Builder сводится практически к
размещению компонентов на форме, заданию их свойств и написанию обработчиков
событий. С каждым компонентом библиотеки VCL связан определенный набор
событий, на которые он может реагировать. Каждому событию соответствует своя
функция – обработчик этого события. Список всех функций – обработчиков событий
можно увидеть на вкладке Events окна инспектора объектов.
Во время проектирования формы и размещения на ней компонентов среда C++
Builder автоматически генерирует
коды программы, включая в нее соответствующие фрагменты, описывающие компоненты
и заголовки функций – обработчиков событий.
Для отображения текста на форме могут использоваться такие компоненты,
как Label и Panel.
Ввод и одновременное редактирование информации позволяет выполнять компонент Edit,
а задавать в приложении интервалы времени можно с помощью компонента Timer.
Для работы с такой динамической структурой данных, как список следует использовать
компонент ListBox.
Ниже будут рассмотрены вопросы проектирования интерфейса пользователя,
а также приведены другие примеры разработки приложений, использующих как
компонент таймер, так и компоненты ввода и отображения информации.
10.4. Разработка интерфейса пользователя
Разрабатываемое
приложение не должно выбиваться из общего стиля Windows ни общим видом, ни
способом взаимодействия с ним. Для
пользователя большим преимуществом является то, что большинство приложений
выглядят и ведут себя сходным образом.
Среда
С++ Builder предоставляет разработчику приложения широкие возможности быстрого и
качественного проектирования графического интерфейса пользователя – различных
окон, кнопок, меню.
Рассмотрим далее вопросы проектирования таких наиболее
часто используемых интерфейсных элементов, как меню, панели инструментов и диалоговые
окна.
10.4.1. Прикрепление меню
Меню – это наиболее
распространенный элемент управления в Windows. Все главные окна
приложений имеют связанные с ними меню.
В среде С++ Builder для создания
меню используется специальный редактор, обладающий следующими возможностями:
–
создание как главного, так и контекстных меню;
– обеспечение оперативного доступ к редактору
кода для обработки событий OnClick,
соответствующих пунктам меню;
–
вставка меню из шаблонов или файлов ресурсов;
– сохранение
пользовательских меню в виде шаблонов.
Работу с редактором меню рассмотрим на
примерах разработки приложений для просмотра текстовых файлов и многооконного
текстового редактора.
Откройте новое
приложение и перенесите на форму компонент МаinМеnu
(главное меню) со страницы Standart (вторая пиктограмма слева). В
результате откроется окно, вид которого представлен на рис. 2.6. В этом окне вы
можете спроектировать свое меню.
Компонент МаinМеnu потребуется нам, чтобы создать
в приложении меню, являющееся обязательным атрибутом любого приложения Windows.
В нашем приложении мы хотим создать всего одно выпадающее меню Файл с
двумя разделами Открыть и Сохранить, которые соответственно
открывают файл текстового документа и сохраняют его на диске после редактирования.
Рис. 2.6. Форма с помещенным на нее компонентом MainMenu
Компонент МаinМеnu – невизуальный, т. е. место
его размещения на форме в процессе проектирования не имеет никакого значения
для пользователя, который все равно увидит не сам компонент, а только меню,
сгенерированное им.
Основное
свойство компонента МаinМеnu – Items. Его заполнение производится с
помощью редактора меню (рис.10.7), вызываемого двойным щелчком на компоненте МаinМеnu или нажатием кнопки с многоточием
рядом со свойством Items в окне
инспектора объектов.
При работе в
окне редактора меню новые разделы можно вводить, помещая курсор в рамку из
точек, обозначающую место расположения нового раздела. Если при этом раздел
ввелся не там, где вам было нужно, вы можете отбуксировать его мышью туда, куда
вам надо. Другой путь ввода нового раздела – это использование контекстного
меню, всплывающего при щелчке правой кнопкой мыши. Если вы предварительно
выделите какой-то раздел меню и
выберете из контекстного меню команду Insert, то рамка нового раздела
вставится перед ранее выделенным разделом.
При выборе
нового раздела вы увидите в окне инспектора объектов множество свойств данного
раздела. Дело в том, что каждый раздел меню (каждый элемент свойства Items) является объектом типа TMenuItem,
обладающим своими свойствами, методами, событиями. Рассмотрим их.
|
Рис. 10.7. Окно редактора меню
Свойство Name задает имя объекта,
соответствующего разделу меню. Основное свойство раздела – Caption обозначает надпись раздела. В надписях можно предусматривать
использование клавиш ускоренного доступа к разделу меню, выделяя для этого один
из символов надписи. Перед символом, который должен соответствовать клавише ускоренного
доступа, ставится символ амперсанда (&). Этот символ не появляется в
надписи, но следующий за ним символ оказывается подчеркнутым. Тогда
пользователь вместо выбора меню может нажать клавишу Аlt совместно с
клавишей выделенного символа. Если меню раскрылось, то клавишей Аlt и
соответствующим символом можно выбрать раздел меню.
Свойство ShortCut определяет клавиши быстрого
доступа к разделу меню – клавиши, с помощью которых пользователь, даже не
заходя в меню, может в любой момент вызвать выполнение процедуры, связанной с
данным разделом. Чтобы определить клавиши быстрого доступа, следует открыть
выпадающий список свойства ShortCut
в окне инспектора объектов и выбрать из него нужную комбинацию клавиш.
Выполните
проектирование меню. Сделайте двойной щелчок на компоненте МainМеnu вашего приложения, выделите мышью пунктирную рамку,
перейдите в окно инспектора объектов и в свойстве Caption напишите &Файл. В окне конструктора меню
появится надпись Файл (см. рис. 10.7). Щелкните на этой надписи. Ниже
нее появится пунктирная рамка, в которую вы аналогичным образом введете надпись
второго раздела Открыть… (многоточие после имени раздела говорит
пользователю, что будет открыто диалоговое окно). Введите и третий раздел меню
–Сохранить как…. Задайте для этого раздела «горячие» клавиши например,
F2. В окне конструктора меню рядом с соответствующим разделом, как
показано на рис. 10.7, появится указание на эту клавишу. В заключение закройте
окно конструктора меню его системной кнопкой. Вверху формы вашего приложения
возникнет надпись спроектированного вами меню. Присвойте свойству Caption
формы приложения значение Просмотр и редактирование текстов.
Разместите на форме окно
редактирования RichEdit (рис. 10.8) со страницы библиотеки Win32
(четвертая пиктограмма слева). Это многострочное окно редактирования, позволяющее
работать как с текстовыми файлами в формате АSСII, так и с текстовыми файлами
в обогащенном формате RTF.
Рис.10.8. Форма с
размещенным на ней окном редактирования RichEdit
Желательно, чтобы окно RichEdit
занимало всю площадь формы, причем не только в процессе проектирования, но и
при изменении пользователем в процессе работы размеров окна приложения. Для
этой цели следует использовать свойство Allign
(выравнивание). По
умолчанию оно равно alNone. Это означает, что выравнивание не
осуществляется. Свойство Align можно
задать равным аlТор
или аlВоttоn, или аlLeft или
allRight, это значит, что компонент
должен занимать всю верхнюю, или нижнюю, или левую, или правую часть клиентской
области компонента-контейнера. Под клиентской областью понимается вся свободная
площадь формы или другого контейнера, в которой могут размещаться включенные в
этот контейнер компоненты. Можно также задать свойству компонента Align значение аlClient, что приводит к заполнению
компонентом всей свободной клиентской области. Во всех этих случаях размеры
компонента будут автоматически изменяться при изменении размеров контейнера. В
нашем случае окно редактирования должно занимать всю площадь формы. Поэтому
задайте для него значение Align равным аlClient
и окно немедленно закроет всю вашу форму,
кроме заголовка меню.
Основное свойство компонента RichEdit – Lines (строки текста).
Нажмите кнопку с многоточием в строке
Lines окна RichEdit, и вам откроется окно редактирования
списков строк. Вы можете редактировать или вводить текст непосредственно в этом
окне или нажать кнопку СоdeEditor и работать в обычном окне редактора
кода. В этом случае, завершив работу с текстом, выберите из контекстного меню,
всплывающего при щелчке правой кнопкой мыши, команду Сlоsе
Раgе и
ответьте утвердительно на вопрос, хотите ли вы сохранить текст в
соответствующем свойстве окна редактирования. В нашем
примере в окне ничего записывать не нужно. Наоборот, в этом окне надо стереть
текст RichEdit1 –
занесенное в него имя
компонента.
Теперь нам
требуется предоставить пользователю стандартные диалоги Windows для
открытия текстового файла и его сохранения под заданным именем. Для этого
перенесите на форму компоненты
ОреnDialog (диалог Открыть файл) и SaveDialog (диалог Сохранить файл). Эти компоненты, как и
другие диалоги, расположены в библиотеке VCL на странице Dialogs. Компоненты ОреnDialog и SaveDialog – невизуальные, их можно размещать в любом месте формы (рис. 10.9).
Рис.10.9. Форма приложения в процессе проектирования
Компоненты ОреnDialog и SaveDialog инкапсулируют стандартные диалоги Windows. Среди множества свойств этих
компонентов следует задать только свойство
Filter, определяющее типы
файлов, появляющиеся в диалоге в выпадающем списке. Это свойство проще всего
задать с помощью редактора фильтров, который вызывается нажатием кнопки с многоточием
около имени свойства Filter в окне
инспектора объектов. При этом открывается окно редактора фильтров Filter Editor (рис. 10.10).
Вызов любого
диалога осуществляется методом Ехесutе.
Этот метод возвращает значение true (истина), если пользователь, работая
с диалогом, произвел необходимый выбор. Если же пользователь в диалоге нажал
кнопку Отмена или клавишу Еsс, то возвращается значение false (ложь). Имя выбранного пользователем файла возвращается значением
свойства FileName диалогов ОреnDialog и SaveDialog.
Напишем код, соответствующий разделу Открыть нашего меню.
Откройте на форме спроектированное меню Файл и выберите его раздел Открыть.
Вы попадете в окно редактора кода на текст
void_fastcall
Tform1 : : N2Click (TObject *Sender)
{
}
В левой панели Filter Name В правой панели Filter записываются
|
Рис. 10.10. Окно редактора фильтров компонентов OpenDialog и SaveDialog
|
Это заготовка обработчика щелчка на
данном разделе. Занесите в него между фигурными скобками оператор
if (OpenDialog1 –> Execute())
RichEdit1 –> Lines –> LoadFromFile(OpenDialogl –> FileName);
Этот оператор
вызывает метод Ехесute компонента ОреnDialog1, анализирует результат, и если результат равен true (пользователь выбрал файл), то в
строки Lines окна редактирования RichEdit1 методом LoadFromFile с помощью
оператора ОреnDialog1 –> FileName заносится
содержимое файла, выбранного пользователем.
В обработчик щелчка пользователя в
разделе Сохранить как необходимо занести оператор
if (SaveDialog1 –> Execute ())
RichEdit1 –> Lines
–> SaveToFile(SaveDialog1 –> FileName);
Дайте имя форме
(свойство Name), отличное от имени
по умолчанию, например имя FDoc. Это
нужно делать тогда, когда вы намереваетесь использовать форму в своих будущих
проектах (форма FDoc используется в
проекте, создание которого описано ниже в п. 10.4). Модуль формы сохраните с
именем UDoc. Выполните приложение
(приготовьте для этого текст в формате RTF) и поработайте с ним. Вы
можете увидеть, что в вашем окне редактирования автоматически реализованы
многие функции, свойственные текстовым редакторам: выделение слова при двойном
щелчке мыши, возможность перемещения выделенного фрагмента текста в другое
место файла, «горячие» клавиши Ctrl-C (копировать выделение в буфер
обмена Clipboard), Ctrl-X (вырезать в Clipboard), Ctrl-V
(копировать из Clipboard), Ctrl-Z (отменить последнюю операцию
редактирования). Приложение вызывает стандартные диалоги Windows
открытия и сохранения файлов.
10.4.2. Создание панели инструментов
Большинство современных
приложений Windows имеют панели инструментов. Создание панели инструментов
выполняется поэтапно: вначале создается контейнер панели инструментов на форме
приложения, а затем выполняется заполнение панели необходимыми кнопками.
Создадим панель инструментов для приложения, выполняющего просмотр текстовых
файлов, процесс разработки которого был описан в п. 10.4.1.
Для создания контейнера
панели инструментов на форме выполните следующие шаги:
1. Скопируйте файлы проекта
в другую папку (нужно копировать только файлы *.dfm, *.bpr, *.cpp,
*.h).
2. Откройте файл проекта
приложения для просмотра текстовых файлов.
3. Выберите компонент Panel
из палитры компонентов и поместите его на форму в любом месте.
4. Измените значение
свойства Name панели на ToolBar.
5. Установите значение
свойства Height равным 32.
6. Сотрите значение свойства
Caption.
7. Измените значение
свойства Allign на alTop. Панель инструментов переместится
наверх.
Для размещения кнопок на
панели инструментов сделайте следующие
шаги:
1. Щелкните на вкладке Additional
палитры компонентов и выберите компонент SpeedButton (кнопка быстрого
доступа) и поместите ее на панель, не беспокоясь о точном размещении.
2. Измените значение
свойства Name компонента SpeedButton на FileOpenBtn.
3. Установите значение
свойства Left равным 5.
4. Выберите в главном меню
пункт View | Alignment Palette. Щелкните на кнопке Center Vertically in Window.
5. Найдите свойство Glyph,
щелкните в столбце, в результате откроется окно редактора изображений.
6. Нажмите кнопку Load.
На экране появится диалоговое окно Load picture. Перейдите в подкаталог …\
Program Files \ Common Files
\ Borland Shared \ Image \ Buttons и выберите файл fileopen.bmp. Нажмите кнопку OK.
7. Повторите последние шесть
шагов, чтобы добавить кнопку File
Save. Поместите ее справа от кнопки File Open. Дайте ей имя FileSaveBtn и используйте файл filesave.bmp для
свойства Glyph.
В результате форма должна
принять вид, показанный на рис.10.11.
|
Рис. 10.11. Форма с размещенной на ней
панелью инструментов
Запишите коды обработчиков событий – щелчков на кнопках панели
инструментов. Эти коды можно скопировать из функций – обработчиков щелчков по
перечисленным выше пунктам меню. Откомпилируйте и запустите приложение на
исполнение. Убедитесь, что с помощью кнопок панели инструментов действительно
можно выполнить те же действия что и с помощью пунктов меню. Прикрепите
всплывающие подсказки к кнопкам панели инструментов (как это сделать было показано
в п. 10.3.1).
10.4.3. Многооконный текстовый редактор
Все предыдущие
примеры имели по одной форме в проекте. Рассмотрим, как можно строить проекты с
несколькими формами. Сначала построим приложение, которое ничего не выполняет,
но имеет вторую форму – форму информации о программе, а затем превратим это
ничего не выполняющее приложение в многооконный редактор текстов.
Начните новый
проект и назовите (свойство Name) его форму именем main. Это желательно сделать, поскольку в нашем проекте будет несколько
форм и, назвав их непонятными именами, мы рискуем в них запутаться. Задайте
окну формы (свойство Сарtion) заголовок
Многооконный редактор. Сохраните проект сразу, дав сохраняемому
модулю имя Umain, а проекту – имя РМDM. Осмысленные
имена модулям полезно давать с той же целью: потом в проекте будет три модуля,
а с их стандартными именами Unit1,
Unit2, Unit3 мы рискуем запутаться, который из них к какой форме относится.
Перенесите на
форму уже знакомый вам компонент
МainMenu – главное меню (см. п. 10.4.1). Введите с его помощью меню Справка
с единственным разделом О программе (рис. 10.12). Если пользователь выберет
этот раздел, то ему должна быть показана форма, содержащая информацию о
программе, поэтому нам нужно включить в проект еще одну форму.
Рис10.12. Начальный вариант
главной формы приложения
Выполните
команду File | New Form. В ваш проект включится новая форма. Дайте ей
имя Аbout и заголовок О программе.
Сохраните файл модуля этой формы (команда File | Save), дав ему имя UAbout. Эта форма будет содержать
информацию о вашей программе. Размер формы имеет смысл значительно уменьшить,
так как информационные окна обычно небольшие. Стиль формы (свойство BorderStyle)
следует установить в bsDialog, так
как пользователь не должен иметь возможность изменять ее размеры. Свойство
формы Position установите в poScreenCenter, чтобы форма появлялась в центре экрана.
Если вы решили
украсить свою форму графикой, то перенесите на нее компонент Image. Установите его свойство AutoSize равным true, в результате
этого размер компонента Image будет
автоматически подстраиваться под размер загруженного в него изображения.
Основное свойство компонента
Image
– Picture. В это свойство можно
загрузить любой графический файл. Для загрузки можно сделать двойной щелчок на
компоненте
Image или нажать кнопку с многоточием около свойства Picture в окне инспектора объектов. Вы
попадете в окно загрузки изображения, но сначала оно будет пустым. Нажмите
кнопку Load и в открывшемся окне выберите интересующий вас файл. Со
средой С++ Builder поставляется много файлов изображений, помещенных в
подкаталоги каталога Program Files \ Common Files \ Borland Shared \ Images. Щелкните на кнопке ОК, и изображение
загрузится в компонент Image. Измените размеры изображения на форме
так, чтобы оно занимало примерно половину окна формы и установите свойство AutoSize
компонента Image в значение false. Это послужит запретом для
дальнейших изменений размеров изображения в окне About. Теперь в другой
половине окна можно разместить любой текст. В результате форма может выглядеть
например, так, как показано на рис. 10.13, где изображена загрузка файла
пиктограммы Program Files \ Common Files \ Borland Shared \ Images \ Splasht \ 16 color \ skyline.bmp.
Для размещения текста в окне About используйте компонент Memo, для чего щелкните
на вкладке Standart палитры компонентов и выберите компонент Memo.
Поместите его справа от изображения на форме.
Рис.10.13. Пример формы с информацией
о программе
Для размещения и
форматирования текста в компоненте Memo выполните следующие
действия:
1. Измените значение
свойства Name на Memo.
2. Дважды щелкните в столбце
Value рядом со свойством Lines. Откроется окно редактора строк (String
List Editor). Введите в это окно текст.
3. Установите значение
свойства Alignment равным ta Center. Текст надписи будет выровнен
по центру внутри компонента Memo.
4. Установите значение
свойства Enabled равным false для того, чтобы его было невозможно
изменить в процессе работы приложения.
5. Установите значение
свойства Color равным ClbtnFace, задайте размер шрифта 12
пунктов, начертание – полужирный.
6. Сохраните результаты
проектирования этой формы.
Теперь в нашем проекте две
формы и следует задать, какая из них будет главной. Главная форма отличается от прочих рядом свойств. Во-первых,
именно этой форме передается управление в начале выполнения приложения.
Во-вторых, закрытие пользователем главной формы означает завершение выполнения
приложения. В-третьих, главная форма так же, как и любая другая, может быть
спроектирована невидимой (свойство Visible), но если все остальные формы
закрыты, то главная форма в любом случае становится видимой (иначе пользователь
не смог бы продолжать работать с приложением и даже не смог бы его завершить).
По умолчанию главной
становится форма, которая была создана
в проекте первой, поэтому в нашем проекте главная форма main. Но если бы мы
начали проект с создания формы About, то именно она стала бы главной.
В среде С++ Builder имеется инструмент,
который позволяет управлять формами и, в частности, задавать главную из числа
форм, имеющихся в проекте. Выполните команду Project | Options и в
открывшемся окне опций проекта перейдите на страницу Forms. В верхнем выпадающем списке Main forms вы можете выбрать главную
форму среди имеющихся в проекте. Пользуясь двумя нижними окнами, можно установить,
какие формы должны создаваться автоматически, а какие не должны. Например, если
нужно исключить форму FDoc из списка
автоматически создаваемых, то следует выделить ее в левом окне (Аuto-creat
forms) и с помощью кнопки со стрелкой, направленной вправо, переместить
в правое окно доступных форм (Availabel forms).
Проверьте в этом окне, что
главной является форма main. Вернувшись
в проект, проверьте также, что форма
Аbout невидима: ее свойство Visible
должно быть установлено равным false, так как форма должна становится
видимой только при выборе пользователем раздела меню О программе.
Теперь нам осталось только
написать оператор, который делает форму
Аbout видимой при выборе пользователем раздела О программе. Перейдите
в своем проекте на форму main,
раскройте меню, щелкните на разделе О программе и в открывшуюся в окне редактора
кода заготовку обработчика этого щелчка внесите оператор
Аbout
–> Show();
Этот оператор с помощью
метода Show делает форму Аbout видимой. Если вы попробуете
откомпилировать программу, то вам будет выдано замечание undefined symbol
About. Дело в том, что форма Аbout
недоступна из модуля Umain.
Чтобы модуль UАbout, содержащий форму Аbout, стал
доступен из модуля Umain, в модуль Umain следует внести директиву препроцессора
#include “UAbout.h”
Это можно сделать вручную, а
можно, находясь в окне редактора кода в модуле Umain, выполнить
команду File | Include Unit Hdr и в открывшемся окне выбрать из списка в
нижней части окна модуль UAbout. Тогда указанная выше директива include занесется в текст
автоматически.
Сохраните приложение,
выполните его и убедитесь, что при выборе соответствующего раздела меню на
экране появляется форма с информацией о программе.
Превратим наше
приложение в многооконный редактор
текстов – так называемое приложение МDI – это приложение с множеством
документов типа Word, Excel и т. п. В приложении МDI
имеется родительская (первичная) форма и ряд дочерних форм
(называемых также формами документов). Окна документов могут создаваться
самим пользователем в процессе выполнения приложения с помощью команд типа Окно,
Новое. Число дочерних окон заранее неизвестно, так как пользователь
может создать их столько, сколько ему потребуется. Окна документов
располагаются в клиентской области родительской формы. Чтобы там было больше
места для документов, по умолчанию родительскую форму часто делают развернутой
на весь экран. Для этого ее свойство
WindowState нужно установить в
wsMaximized.
В нашем примере
родительской будет форма main, а в
качестве окна документов воспользуемся формой текстового редактора,
разработанной вами ранее в п. 10.4.1.
Скопируйте из
папки, в которой находится проект, созданный в
п. 10.4.1 файл UDoc.cpp (в нем
хранится код модуля формы текстового редактора), файл формы UDoc.dfm и
заголовочный файл UDoc.h. Выполните
команду Project | Add to Project или нажмите соответствующую быструю
кнопку и выберите в открывшемся окне файл Udoc.cpp, в котором хранится модуль вашей
формы текстового редактора. Сошлитесь так же, как вы делали это выше с помощью
директивы include в модуле Umain, на модуль UDoc, содержащий форму UDoc. Задайте для
формы Main, как было указано выше,
WindowState = wsMaximized.
Теперь в нашем
приложении уже три формы. При этом форма FDoc не должна создаваться
автоматически. Поэтому с помощью
страницы Forms окна опций проекта перенесите форму FDoc из списка автоматически создаваемых в список доступных.
Нам нужно
указать, что наша форма main –
родительская, а формы FDoc –
дочерние. Для этого в окне инспектора объектов задайте свойство FormStyle формы main равным fsMDIForm
(родительская), а аналогичное свойство формы FDoc – fsMDIChild (дочерняя).
Поскольку из
родительской формы необходимо управлять дочерними окнами, меню формы main следует пополнить еще одним меню
–Окно с разделами Новое, Каскад, Упорядочить по
горизонтали, Упорядочить по вертикали, Упорядочить значки
(рис. 10.14). Сделайте это с помощью компонента MainMenu. Поскольку
у нас теперь много разделов меню и с их именами по умолчанию мы далее можем
запутаться, то назовите объекты каждого раздела более осмысленно. Для этого
выделите поочередно каждый раздел меню в окне конструктора меню и в окне
инспектора объектов задайте им соответственно имена MNew, MCascade,
MHor, MVert, MPict. На эти имена мы и будем ссылаться при
дальнейшем изложении.
Рис.10.14. Главная форма приложения – окончательный
вариант.
В приложениях MDI
меню окна документа автоматически объединяется с меню родительской формы. В
нашем случае в дочерней форме имеется меню Файл, которое должно
встраиваться в меню родительской формы, причем, как это принято во всех приложениях
Windows, меню Файл должно быть первым. Последовательность
встраивания определяется свойствами GroupIndex разделов меню. До сих пор
это свойство во всех разделах было равно нулю. Но при объединении меню это
недопустимо, поскольку последовательность встраивания одного меню в другое
определяется именно этим свойством. Следовательно, оставив это свойство равным
нулю в меню Файл, надо с помощью конструктора меню просмотреть все
разделы меню Окно и Справка и задать для меню Окно и его
разделов свойство GroupIndex равным 1, а для меню Справка и его
раздела равным 2. Тогда объединение меню будет происходить без особых проблем.
Нам осталось
написать обработчики для разделов меню Окно. Для раздела MNew (Новое)
обработчик приведен в листинге 10.8.
Листинг 10.8. Код
обработчика для раздела Новое меню Окно
void _fastcall
Tmain :: MNewClick(TObject *Sender)
{ / * объявление указателя ТF на создаваемый
объект формы ТFDoc и создание нового объекта формы * /
TFDoc *TF = new
TFDoc(Application) ;
// возврат из функции, если объект не удалось
создать
if (! TF) return;
// формирование уникального заголовка нового
окна
TF –> Caption
= «Окно » +
IntToStr(MDIChildCount);
// отобразить вновь созданное окно
TF –> Show();
}
В приведенный текст внесены
комментарии, поясняющие каждый оператор. Первый оператор объявляет локальную
(временную) переменную TF как указатель на объект класса TFDoc –
это класс формы FDoc. Этот же оператор создает операцией new новый объект формы документа.
Следующий оператор проверяет, создался ли объект, и если не создался, то он
обеспечивает выход из обработчика оператором return. Третий оператор
задает заголовок окна нового документа, формируя его из слова Окно и
порядкового номера дочернего окна. Этот номер определяется свойством
родительской формы MDIChildCount. Его не следует искать в окне инспектора
объектов, так как это свойство времени выполнения, т. е. оно доступно только во
время выполнения и автоматически возрастает при создании каждого нового
дочернего объекта. Последний оператор при помощи метода Show отображает
окно созданного документа на экране.
Тексты остальных
обработчиков щелчков на разделах меню Окно приведены в листинге 10.9.
Листинг
10.9. Коды обработчиков
щелчков на разделах меню Окно
//—————————————————————————
// упорядочивание окон каскадом (пункт меню Каскад)
void _fastcall Tmain ::
MHorClick(TObject *Sender)
{ Cascade(); }
//—————————————————————————
// упорядочивание окон по горизонтали (пункт меню
// Упорядочить по горизонтали)
void_fastcall Tmain ::
MHorClick(TObject *Sender)
{ TileMode = tbHorizontal;
Tile () ;
}
//—————————————————————————
// упорядочивание окон по вертикали (пункт меню
// Упорядочить по вертикали)
void _fastcall Tmain ::
MVertClick(TObject *Sender)
{
TileMode = tbVertical;
Tile();
}
//—————————————————————————
// упорядочивание пиктограмм свернутых окон
void_fastcall Tmain ::
MPictClick(TObject *Sender)
{ ArrangeIcons
(); }
//—————————————————————————
Сохраните приложение и
опробуйте его в работе. При запуске приложения в нем не будет ни одного окна
документа и будут видны только два меню: Окно и Справка. Выполнение
команды Окно | Новое создаст окно документа. В этот момент вы увидите в
полосе главного меню раздел Файл. В дальнейшем каждое выполнение команды
Окно | Новое будет приводить к созданию следующего окна документа, в
каждом из которых вы можете написать свой текст или загружать текстовые файлы.
10.4.4. Прикрепление к приложению формы–заставки
Пользователь при загрузке
многих приложений Windows перед открытием главного
окна программы, как правило, видит форму–заставку, содержащую логотип
приложения и сведения о программе или ее разработчике. Эта форма должна
открываться как модальная.
Модальная форма приостанавливает выполнение вызвавшей ее процедуры до тех пор,
пока пользователь не закроет эту форму. Модальная форма также не позволяет пользователю
переключить фокус курсором мыши на другие формы данного приложения, пока форма
не будет закрыта.
Добавим заставку к одному из
разработанных ранее приложений. Для этого
выполните следующие шаги:
1. Создайте новую папку и
дайте ей имя, например zastavka. Скопируйте в эту папку все файлы одного
из созданных вами работающих проектов. Откройте проект, дважды щелкнув по файлу
проекта.
2. Добавьте в приложение новую
форму (File | New Form). Это будет
форма–заставка. Назовите ее Flog (свойство Name). Уменьшите размеры формы- аставки. Установите
следующие свойства:
– BorderStyle bsNone (отсутствие полосы заголовка и кнопок);
– Position poScreenCenter (форма будет появляться в центре экрана);
– Visible должно иметь значение false.
Разместите на форме–заставке
компонент Memo и поместите в него текст заставки. Можно разместить на
форме и рисунок (используя компонент Image).
3. Напишите следующие
обработчики событий для формы-заставки, которые при любом действии закрывали бы
форму:
– события onKeyDown
(нажатие клавиши на клавиатуре) и onMouseDown (нажатие кнопки мыши) –
обработчики должны содержать оператор Close();
– свойство KeyPreview установите в значение true, чтобы
форма перехватывала все связанные с нажатием клавиш события компонентов.
4. Сделайте так, чтобы и при
отсутствии действий со стороны пользователя форма закрывалась сама, например,
через 5 с. Для этого добавим на форму компонент Timer со страницы System.
Зададайте значение свойства Interval
равным 5 000. В обработчике события таймера OnTimer напишите
единственный оператор Close().
5. Освободите память,
занимаемую формой-заставкой, для чего в событие формы-заставки OnClose
запишите оператор
Action = caFree;
6. Cохраните проект, дав имя
модулю формы-заставки UFlog. Выполните для модуля главной формы приложения команду File |
Include Unit Hdr и укажите в
диалоге имя включаемого модуля UFLog.
7. Для главной формы
приложения напишите обработчик события формы OnShow
FLog ->
ShowModal();
Событие OnShow
наступает до того, как форма действительно станет видимой. Во время обработки
этого события главная форма еще не видна. Оператор открывает форму FLog как модальную, передает ей
управление, и дальнейшее выполнение программы в главном модуле останавливается
до тех пор, пока модальная форма не будет закрыта.
В заключение
откомпилируйте и запустите приложение.
10.4.5. Прикрепление к приложению формы–пароля
Форму с окном для ввода пароля можно добавить
к приложению, если вы хотите защитить его от несанкционированного
использования. Для этого выполните следующие действия:
1. Откройте существующий
проект. Добавьте новую форму. Назовите ее FPSW (свойство Name), сохраните ее модуль под именем UPSW.
Уменьшите размеры формы. Установите следующие свойства:
– BorderStyle bsNone (отсутствие полосы заголовка и кнопок);
– Position poScreenCenter (форма будет появляться в
центре экрана).
В свойстве Caption напишите Введите пароль
и нажмите Enter.
2. В центре формы FPSW поместите окно
редактирования Edit, в котором пользователь будет вводить пароль.
Очистите его свойства Text,
а в свойство PasswordChar внесите символ *, тогда символы
вводимого пользователем в окно Edit пароля будет отображаться в
виде звездочек, что повысит уровень защиты вашего приложения. В обработчике
события OnKeyDown этого компонента запишите
оператор
if(Key == VK_RETURN) // если была
нажата клавиша Enter
Close(); // закрытие формы с запросом пароля
После нажатия пользователем
клавиши Enter считается, что пользователь завершил ввод пароля и
форма для ввода пароля должна быть закрыта. При закрытии формы наступает целая
последовательность событий, которые можно обрабатывать. Первым возникает
событие onCloseQuery. В его обработчик передается
по ссылке булева переменная CanClose, определяющая, должно ли продолжаться закрытие формы. По умолчанию
значение CanClose равно true, что означает продолжение
закрытия. Если форму закрывать не нужно, то параметру CanClose должно быть присвоено значение
false. Тогда последующих событий,
связанных с закрытием формы, не будет.
Если обработчик события onCloseQuery отсутствует или если в его обработчике сохранено
значение true для CanClose, то затем наступает событие OnClose.
3. В событие onClose формы FPSW вставьте оператор
if(Edit1 –> Text == «qwerty»)
ModalResult = 6;
Этот оператор сличает
введенный текст с паролем. Если введен правильный пароль (qwerty), то свойству ModalResult присваивается некоторое условное число,
например 6. Можно присвоить и любое
другое число, кроме 0 или 2.
4. Выполните для модуля главной формы приложения команду File | Include Unit Hdr и укажите в диалоге
имя включаемого модуля UPSW. В обработчике события OnShow после других
операторов добавьте операторы
if(FPSW –> ShowModal() ! =6
)
{ ShowMessage («Ваш пароль неверный»);
// закрытие
главной формы приложения (т. е. всего приложения)
Close();
}
else
{
ShowMessage («Ваш пароль верный»);
delete FPSW;
}
10.4.6.
Многостраничные панели
Многостраничные панели
позволяют экономить пространство окна приложения, размещая на одном и том же
месте страницы разного содержания. Работу с многостраничными компонентами
рассмотрим на примере компонента PageControl.
Откройте новый проект и
разместите на форме компонент PageControl со страницы Win32. Этот
компонент отображает стопку страниц с частично перекрывающими друг друга
вкладками. Щелкните на форме правой кнопкой мыши на компоненте PageControl
и во всплывшем меню выберите команду NewPage (создать новую страницу). Каждая
создаваемая страница является объектом
типа TTabSheet. Это панель, на которой можно размещать любые управляющие
компоненты. Увеличьте мышью размеры страницы примерно так, как показано на рис.
10.15.
В свойство Caption
панели занесите надпись Телефоны. Аналогично создайте еще три страницы и
введите надписи, которые будут появляться на ярлычках закладок.
Рис. 10.15. Форма с
размещенным на ней с компонентом Page Control
Выделите страницу с
названием E-mail моих знакомых.
Разместите на этой странице компоненты RichEdit, Memo, Edit,
два компонента Label и кнопку Button
(рис.10.16). Занесите текст в метки, удалите текст из компонентов RichEdit,
Memo и Edit.
В обработчик OnCick
щелчка на кнопке занесите код, приведенный в листинге 10.10.
Рис. 10.16.
Приложение с выделенной страницей E-mail моих знакомых
Листинг
10.10. Обработчик щелчка по кнопке OK на странице E-mail моих знакомых
// переменная
для сохранения ответа пользователя ввести пароль повторно
int btn;
AnsiString
pass = «123-456-789»; // строка, содержащая пароль
// строка,
считанная из окна редактирования
AnsiString type =
Edit1->Text.c_str();
Edit1 –> Clear(); //
очистка окна редактирования для ввода пароля
Edit1 –> SetFocus(); //
передача фокуса ввода в окно редактирования
if ( type ! = pass ) //если считанная в строка не
соответствует паролю
{
// вывод
стандартного диалогового окна Windows с запросом о повторе ввода
btn = Application –> MessageBox(«Неверный пароль! Повторить?»,
«Ввод пароля», MB_YESNO);
// если отказ
от ввода пароля идет повторно, то
//
активизировать следующую страницу
if (btn
== IDNO)
{
PageControl1->SelectNextPage(true);
return;
}
if (btn == IDYES)
return;
// подтверждение желания ввести пароль повторно
}
//введен
правильный пароль
try
// контроль ошибок открытия файла
{
RichEdit1 –> Lines –> LoadFromFile(«Pages.rtf»);
}
catch (…)
{
Application –> MessageBox(«Ошибка чтения файла
PAGES.RTF», NULL, MB_OK);
}
// поместить
информацию на секретную страницу
RichEdit1 –> Lines –> Append(«1.
Lewis A.
WordWeb@netword.demon.co.uk»);
RichEdit1 –> Lines –> Append(«2.
Roache J. johnroache@aol.com»);
RichEdit1 –> Lines- –> Append(«3.
Лозинский Д. loz@dials.msk.su»);
RichEdit1 –> Lines –> Append(«4.
Данилов И. id@sald.spb.su»);
RichEdit1 –> Lines –> Append(«5.
Шамис В. vshamis@ass.iki.rssi.ru»);
Выделите страницу с
названием Календарь Разместите на этой странице компоненты CCalendar со страницы Samples и метку Label.
В обработчик события OnChange (событие наступает сразу после переключения на страницу) для компонента Page Control
занесите код, который позволит поместить в метку Label текст, содержащий название
дня, месяца и года:
Label3 –> Caption = «Сегодня» + FormatDateTime («dddd
mmmm,yyyy», CCalendar1 –> CalendarDate);
В обработчик события OnCreate формы вставьте код, позволяющий
активизировать страницу c номером 3:
PageControl1 –> ActivePage =
TabSheet3;
Таким образом, чтобы пользователю созданного приложения
было понятно, как с ним работать, приложение должно иметь простой и наглядный
интерфейс. Для проектирования интерфейса приложения можно использовать следующие
компоненты библиотеки VCL:
– MainMenu, позволяющий создавать строку меню с разделами главного меню и
раскрывающимся списком команд;
– ToolBar, обеспечивающий создание
инструментальной панели быстрых кнопок, дублирующих основные разделы меню;
– PageControl, предоставляющий возможность выполнить перелистывание страниц на
главной форме.
Помимо перечисленных выше
элементов, интерфейс приложения может включать в себя контекстные меню, полосу
состояния, файл справки и др. Для получения информации по их применению можно
воспользоваться литературой [10],[11].
2.5.
Запуск внешних программ и создание дочерних процессов
В ряде случаев программисту
может понадобиться запускать из своей программы другие программы. Это могут
быть стандартные архиваторы, калькуляторы, текстовые, графические редакторы,
программы, ранее разработанные для среды DOS, которые представлены
только своим исполняемым модулем. Запуск одной программы из другой называется порождением
дочернего процесса.
Запуск внешней программы в
среде C++ Builder можно сделать с помощью
нескольких функций API Windows,
примеры применения которых приведены ниже
1. С помощью функции WinExec():
– запуск программы Пасьянс
WinExec(«sol.exe»,SW_RESTORE);
– запуск стандартной программы Блокнот
WinExec(«notepad.exe»,SW_RESTORE);
– запуск собственной программы
WinExec(«C:\\bcb6_user\\calculator\\Project2.exe»,
SW_RESTORE);
Параметр
SW_RESTORE
означает, что окно запускаемого приложения активизируется и отображается на
экране.
2.С помощью функции ShellExecute():
– запуск стандартной программы Блокнот
ShellExecute(Handle,
«open», «notepad.exe», NULL, NULL, SW_RESTORE);
– запуск собственной программы
ShellExecute(Handle,
«open», «C: \\ bcb6_user \\ calculator \\ Project2.exe»,
NULL, NULL, SW_RESTORE);
Здесь Handle – дескриптор
родительского окна (32-разрядное целое), open – выполняемая операция (открыть
запускаемое приложение).
3. С помощью функции CreateProcess().
Эта функция является более современной, чем
функция WinExec. Функция CreateProcess рекомендуется для 32
разрядных приложений. В программе, использующей эту функцию, следует выполнить
объявления:
// структура, определяющая
основное окно дочернего процесса
STARTUPINFO StartInfo = {sizeof(TStartupInfo)};
PROCESS_INFORMATION ProcInfo;
LPCTSTR s;
StartInfo.cb = sizeof(StartInfo);
StartInfo.dwFlags = STARTF_USESHOWWINDOW;
StartInfo. WShowWindow = SW_SHOWNORMAL;
Приведем пример применения
функции CreateProcess для запуска собственного
приложения:
CreateProcess(NULL,
«C: \\ bcb5_user \\ calculator \\ Project2.exe», NULL, NULL, false,
HIGH_PRIORITY_CLASS, NULL, NULL, &StartInfo, &ProcInfo);
Таким образом, если задача
программиста может состоит в разработке пользовательского интерфейса для ранее
разработанной программы, которая представлена только своим выполняемым модулем.
При этом исходный текст программы может быть неизвестен или написан на языке,
отличающемся от языка С++. Такая задача может быть решена путем запуска выполняемого модуля
программы из приложения–интерфейса.
Контрольные вопросы и задания
1. Назовите основные классы библиотеки VCL
и поясните их назначение.
3. Какие классы предусмотрены в среде С++ Builder
для обработки исключительных ситуаций?
4. Как отключить сообщения об исключениях,
выводимые отладчиком среды С++ Builder?
5. Каким образом происходит обработка событий
в компонентах библиотеки VCL?
6. Каким образом можно распознать источник
события, если для нескольких компонентов используется один обработчик события?
7. Какой компонент можно использовать для
ввода и отображения текстовой информации?
8. Какие функции предназначены для
преобразования текстовой информации в число и обратного преобразования? Какие
исключительные ситуации могут возникнуть в процессе этих преобразований?
9. Разработайте приложение, содержащее
компоненты, позволяющие выполнять ввод и отображение текстовой информации (см.
п. 2.3.1).
10. Какие возможности можно представить
пользователю, если в приложении использованы радиокнопки?
11. Какие структуры данных в языке С++
называют динамическими? Назовите компонент среды С++ Builder,
поддерживающий работу с такой динамической структурой, как список.
12. Разработайте приложение, в котором для
представления данных используется список (см. п. 2.3.5).
13. Какие компоненты библиотеки VCL предназначены
для загрузки стандартных диалогов открытия и сохранения файлов?
14. Каким образом прикрепить к компонентам окна
всплывающие подсказки?
15. Каким образом можно прикрепить меню к
окну приложения?
16. Как задать «горячие клавиши» при
проектировании пунктов меню?
17. Для чего предназначена панель инструментов? Как выполнить ее
создание?
18. Как можно установить высоту и ширину окна
в процессе проектирования приложения?
19. В каких случаях в приложении следует
использовать компонент Timer? Перечислите свойства и
события, связанные с этим компонентом.
20. Разработайте приложение, выводящее на
экран бегущую строку (см. п. 2.3.4).
21. Как добавить к приложению новую форму?
22. Какой стиль должен быть задан для формы,
содержащей информацию о программе?
23. Разработайте приложение для просмотра
текстовых файлов, содержащее меню и панель инструментов (см. п. 2.4.1 и п. 2.4.2).
24. Какой компонент следует использовать для
загрузки в него изображений?
25. Как в приложении с несколькими формами
задать главную форму? Как получить информацию о том, сколько форм имеется в
приложении?
26. Какие значения свойства FormStyle должны быть у родительской и дочерних
форм?
27. Как
выполнить объединение меню родительской и дочерней форм?
28.
Разработайте приложение выполняющее функции многооконного текстового редактора
(см. п. 2.4.3).
29.
Какая форма называется модальной?
30.
Каковы особенности работы с модальной формой?
Как сделать видимой модальную форму?
31. Какой компонент
позволяет разместить на одном месте страницы разного содержания?
32. Какой процесс
называется дочерним? Назовите функции для создания дочерних процессов.
Упражнения
1. Напишите программу,
выполняющую изменение цвета фона окна через каждую секунду. Например: красный, желтый, зеленый (clRed,
clYellow, clGreen).
2. Напишите программу –
простейший калькулятор для выполнения арифметических действий сложения, вычитания,
умножения и деления. Пример окна программы показан на рис.10.17.
Предусмотрите в · ·
|
.
Рис.10.17. Окно программы–калькулятора
3. Напишите программу–тест, позволяющую
контролировать, правильно ли пользователь умеет выполнять сложение целых чисел.
Вид формы приложения показан на
рис.10.18.
Программа должна удовлетворять
следующим требованиям:
·
она должна предлагать пользователю
выполнить сложение двузначных чисел, выбранных случайным образом;
·
пользователь не должен иметь
возможности изменять предлагаемые ему числа.
Рис.10.18. Форма приложения
«Сложение целых чисел»
Кроме
того, время работы программы должно быть ограниченным например 30 с, а по окончании тестирования пользователь должен
получить информацию о результатах тестирования:
оценку отлично, если он не сделал ни одной ошибки; оценку хорошо,
если ошибок не более 5; оценку удовлетворительно, если сделано не более
10 ошибок; оценку неудовлетворительно в других случаях.
4. Используя пример, разработка которого
описана в п. 10.4.1 создайте приложение для просмотра графических файлов.
Продублируйте команды созданного вами меню с помощью быстрых кнопок,
размещенных на панели инструментов (см. п. 10.4.2). Добавьте к приложению окно О
программе.
Указание. На форме следует
разместить компонент Image.
Установите свойство AutoSize этого компонента в
значение true. Для открытия и
сохранения графических файлов следует использовать компоненты OpenPictureDialog и SavePictureDialog.
Для тестирования приложения можно использовать
файлы, расположенные в папке Program
Files \ Common Files \ Borland Shared.
Программа должна удовлетворять следующим требованиям:
–по сигналу от таймера кнопка должна менять положение
в окне;
– пользователь должен иметь возможность
управлять скоростью перемещения кнопки по окну;
– если пользователь поймал кнопку, щелкнув по
ней мышью, кнопка должна перестать прыгать и стать недоступной, а в
заголовок окна должна быть выведена строка Игра окончена.
5.
Напишите программу, содержащую «прыгающую кнопку». Форма приложения приведена
на рис.10.19.
Рис. 10.19.
Форма приложения
«Прыгающая кнопка»
6.
Разработайте приложение с компонентом PageControl (см. п.10.4.6) и
внесите в него следующие изменения:
– cоздайте с помощью
стандартной программы Блокнот текстовый файл с нужными вам телефонами. В
одной строке файла – одна запись, например:
Горгаз – 22–33–44. Сохраните файл в той же папке, в которой вы создали
приложение;
– выделите страницу Телефоны.
Разместите на ней компоненты RichEdit и Button. Добавьте в
приложение код, позволяющий отображать на странице Телефоны при переключении
на нее содержимое созданного вами файла, а при нажатии на кнопку – сохранять
файл с изменениями, которые пользователь внесет в свою записную книжку;
– выделите страницу Календарь.
Разместите на этой странице компоненты CCalendar со страницы Samples
и метку Label. В обработчик события OnChange (событие наступает сразу после переключения на страницу) для
компонента Page Control
занесите код, который позволит поместить в метку Label текст, содержащий название
дня, месяца и года:
Label –> Caption = «Сегодня» + FormatDateTime («dddd
mmmm, yyyy», CCalendar1 –> CalendarDate);
Добавьте страницу О
программе, в которую поместите информацию о версии программного продукта,
авторских правах.
7. Напишите программу-игру
«Угадай число». Программа запоминает в в целочисленной переменной случайное
число и предлагает пользователю его угадать. Игра заканчивается, если
пользователь угадал число. Примерный вид окна программы показан на рис. 10.20.
Требования к программе:
·
Вывод номера попытки угадать число;
·
Сообщение пользователю о результатах попытки, напримерМое число меньше
·
Мое число больше
·
Вы угадали
·
Наличие меню с возможностями начать игру заново или выйти из программы
Добавьте в меню пункт О
программе
Рис. 20.Примерный вид
окна программы «Угадай число»
8. Напишите программу, содержащую два выпадающих меню:
–
меню, содержащее пункты для запуска игр, входящих в состав стандартных программWindows, например Пасьянс,
Сапер;
–
меню, содержащее пункты для запуска приложений, созданных вами ранее, например
приложения, выводящего рисунок, приложения, выводящего часы.
9. Используя материал, изложенный в п.п.
10.4.5 и 10.4.6, добавьте к любому из разработанных вами приложений
форму–заставку и форму для ввода пароля. Измените код, позволяющий вводить
пароль так, чтобы пользователю предоставлялось три попытки для ввода
правильного пароля, после чего приложение должно закрываться, если пароль был
введен неверно.
C++ Builder, developed by Embarcadero Technologies, offers two primary frameworks for building applications: the Visual Component Library (VCL) and the FireMonkey (FMX) framework. Both frameworks are powerful tools for developing applications, but they serve different purposes and have distinct features. This article introduces the VCL and FMX frameworks to help you understand their key differences and use cases.
Visual Component Library (VCL)
What is VCL?
The Visual Component Library (VCL) is a framework for developing Windows-based applications using C++. It provides a rich set of visual and non-visual components that simplify the creation of user interfaces and application logic. VCL is tightly integrated with the Windows API, making it an excellent choice for native Windows development. If you’re learning how to use C++ Builder IDE, VCL’s integration with the Windows environment is a fundamental aspect to grasp.
Key Features of VCL
- Windows-Specific: VCL is designed specifically for Windows applications, providing deep integration with the Windows operating system and its features.
- Rich Component Set: VCL offers a wide range of components, including standard controls like buttons, labels, edit boxes, and advanced components for database access, networking, and multimedia.
- Rapid Development: The visual design environment in C++ Builder, combined with VCL’s components, allows for rapid application development (RAD). Developers can drag and drop components onto forms and set properties visually.
- Native Performance: Applications built with VCL are compiled into native Windows executables, offering high performance and responsiveness.
Use Cases for VCL
- Desktop Applications: VCL is ideal for creating traditional desktop applications with rich user interfaces.
- Business Software: VCL’s robust component library is well-suited for developing business applications that require database access, reporting, and complex user interactions.
- Legacy Systems: VCL is often used to maintain and update legacy Windows applications due to its long-standing presence and compatibility.
FireMonkey (FMX)
What is FMX?
FireMonkey (FMX) is a cross-platform framework for developing applications that run on multiple operating systems, including Windows, macOS, iOS, and Android. FMX allows developers to write a single codebase and deploy it across different platforms, making it a versatile solution for modern application development.
Key Features of FMX
- Cross-Platform: FMX supports multiple platforms, enabling developers to create applications for Windows, macOS, iOS, and Android from a single codebase.
- Modern UI: FMX offers advanced graphics capabilities, including 2D and 3D graphics, allowing developers to create visually appealing and modern user interfaces.
- Flexible Styling: FMX provides a flexible styling system that lets developers customize the appearance of their applications to match different platforms and user preferences.
- Multi-Device Support: FMX applications can adapt to different screen sizes and resolutions, ensuring a consistent user experience across desktops, tablets, and smartphones.
Use Cases for FMX
- Mobile Applications: FMX is well-suited for developing mobile applications that need to run on both iOS and Android.
- Cross-Platform Software: Developers can use FMX to create applications that need to be deployed on multiple platforms without rewriting code for each target OS.
- Graphically Intensive Applications: FMX’s support for advanced graphics makes it an excellent choice for applications that require rich visual elements, such as games and multimedia software.
Comparing VCL and FMX
VCL is tailored for native Windows applications, making it a perfect choice for traditional desktop software and business applications that rely on Windows-specific features. Its deep integration with the Windows API ensures high performance and responsiveness.
On the other hand, FMX excels in creating cross-platform applications with a single codebase, making it suitable for modern applications that need to run on multiple platforms. FMX’s advanced graphics capabilities and flexible styling system allow for the development of visually appealing and modern user interfaces.
Conclusion
Both VCL and FMX frameworks offer powerful tools for application development in C++ Builder, each catering to different needs. VCL is the go-to choice for native Windows applications with a focus on business software and legacy systems, while FMX excels in creating cross-platform applications with modern user interfaces and advanced graphics. Understanding the strengths of each framework will help you choose the right tool for your project.
This entry was posted in Beginner Tutorials. Bookmark the permalink.
The C++ Builder CE Community Edition is a free version of professional C++ Builder that you can develop GUI based desktop and mobile applications in C++. In this post, we will give you five simple C++ console examples to help you understand how C++ Builder 11 CE runs applications.
The latest C++ Builder 11 CE was released in April 2023. If you are a start-up developer, student, hobbyist or just interested in learning to code then C++ Builder Community Edition may well be just the thing for you. Read the FAQ notes on the CE license and then simply fill out the form and download C++ Builder 11 CE.
If you download C++ Builder Community Edition (or RAD Studio CE version) or any Professional, Architect, Enterprise versions of C++ Builder. Install it on your windows computer and run RAD Studio or C++ Builder. Beginners and students normally start to learn C++ with simple code. Let’s create a new C++ application for Windows by using VCL framework in C++ Builder CE.
How to develop C++ VCL applications in C++Builder CE?
If you download and install the C++ Builder CE Community Edition then we can start to coding,
RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs. VCL applications focus only Windows, if you want to develop same app for multiple-OS’es you can use FMX. Let’s start to develop a C++ app with GUI using VCL framework.
1. Choose File->New-> “Windows VCL Application – C++ Builder” menu.
This will create a New C++ Project for Windows. This will allow you develop C++ apps with VCL UI elements. If you don’t need UI Elements, this means you don’t need VCL or FMX frameworks, you create a console application too. Modern applications have a GUI’s and skinned Styles. Note that VCL projects are Windows only and FireMonkey projects are Multi Device (multi-platform) applications that you can compile and run on Windows, MacOS, iOS and Android.
2. Save all Unit files and Project file to a folder.
3. Drag components to your form design
Simply drag and drop components from the Palette window on the right side; Memo (TMemo) and Button (TButton) to your form design. Arrange their width, height and position. You can edit each of their properties from the Object Inspector on the left side.
Note that you can switch between the GUI Design mode to Code Mode by pressing F12, or vice versa. If you want, you can switch to your header file (.h) of your cpp file (.cpp) from the button tabs. You can change your Build Configuration from the left Project window by setting it to Debug or Release mode.
//————————————————————————— #include #pragma hdrstop #include “Unit1.h” //————————————————————————— #pragma package(smart_init) #pragma resource “*.dfm” TForm1 *Form1; //————————————————————————— __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } |
4. Double click to Button1 to create OnClick() event for this button. Add these lines into Button1Click() event, between { and } brackets as given below,
void __fastcall TForm1::Button1Click(TObject *Sender) { String str = “Hello World”; Memo1->Lines->Add(str); } |
This example above is a modern “Hello World” example for Windows which runs with C++ Builder.
5. Now you can compile this C++ code; just press the F9 key or just click the Run button in the center of top bar. This will let the IDE check your code and compile both the Unit and project files and link them together. You can also use the Run menu from the top to run your application. You should see this below as a form application
If you get an error, check your code – it’s easy to mistype or have the braces (“}” characters) in the wrong place. Note that C++ is case sensitive, so upper and lower characters should be also same. Then press the F9 key or just click the Run button again.
You can change the font property of Memo, here we used Consolas 9 font that has fixed width.
From this point, you can add more codes or you can switch back to design mode by pressing F12. And you can add more components, then more code. This is how modern C++ coding works with an UI Toolkit.
How to do calculations in C++ VCL applications?
As in same example above, now lets do another simple calculation. We have a price of a product and there is VAT percentage, then we want to calculate total price of this product. To do this, we should set price and VAT, then we can calculate VATprice and at the final we need to print price and VATprice as a total to the Memo as below,
void __fastcall TForm1::Button1Click(TObject *Sender) { float price = 100; float VAT = 10; float VATprice = price*VAT/100; Memo1->Lines->Add( “TotalPrice = “ + FloatToStr(price+VATprice) ); } |
Now you can compile this C++ code; just press the F9 key or just click the Run button in the center of top bar. This will let the IDE check your code and compile both the Unit and project files and link them together.
How to enhance C++ VCL applications with C++Builder CE?
As in the same example above, now lets do a simple calculation. We have a price of a product and there is VAT percentage, then we want to calculate total price of this product. To do this, we should set price and VAT, and we need to calculate VATprice and totalprice too. So we can define these variables below,
float price = 100; // price of a product float VAT = 10.0; // percentage of VAT 10% float VATprice, totalprice; |
We can define a UnicodeString
to set formated texts, then we can print this. UnicodeString has a printf function in modern C++ as in classic C function. Thus, we can print inputs and calculate totalprice as below,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
void __fastcall TForm1::Button1Click(TObject *Sender) { float price = 100; // price of a product float VAT = 10.0; // percentage of VAT 10% float VATprice, totalprice; UnicodeString ustr; Memo1->Lines->Add(“Inputs:”); ustr.printf(L“Price = $%8.2f”, price); Memo1->Lines->Add(ustr); ustr.printf(L“VAT = %8.2f%”, VAT); Memo1->Lines->Add(ustr); Memo1->Lines->Add(“”); Memo1->Lines->Add(“Calculation:”); VATprice = price*VAT/100; // VAT price addition ustr.printf(L“VAT Price = $%8.2f”, VATprice); Memo1->Lines->Add(ustr); totalprice= price+VATprice; ustr.printf(L“Total Price = $%8.2f”, totalprice); Memo1->Lines->Add(ustr); } |
Now you can compile this C++ code; just press the F9 key or just click the Run button in the center of top bar. This will let the IDE check your code and compile both the Unit and project files and link them together. You can also use the Run menu from the top to run your application. You should see this below as a form application.
How to accept input in C++ VCL applications?
Lets continue to same example. Let’s add more components to get inputs from user. Todo this, drag 2 Labels (TLabel) and 2 Edits (TEdit) components, and we will have a Memo (TMemo) and a Button (TButton) as below,
Double click to Button1, first we need to define our variables. Then we can get the price and VAT values from the Text of Edit1 and Edit2. We should convert Text to float values by using StrToFloat() function as below,
float price, VAT, VATprice, totalprice; price = StrToFloat(Edit1->Text); VAT = StrToFloat(Edit2->Text); |
and other calculations and printing will be same as examples above. Thus, all Button1Click() event will be as below,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void __fastcall TForm1::Button1Click(TObject *Sender) { float price, VAT, VATprice, totalprice; price = StrToFloat(Edit1->Text); VAT = StrToFloat(Edit2->Text); UnicodeString ustr; Memo1->Lines->Add(“Calculation:”); VATprice = price*VAT/100; // VAT price addition ustr.printf(L“Price = $%8.2f”, price); Memo1->Lines->Add(ustr); ustr.printf(L“VAT Price = $%8.2f”, VATprice); Memo1->Lines->Add(ustr); totalprice= price+VATprice; ustr.printf(L“Total Price = $%8.2f”, totalprice); Memo1->Lines->Add(ustr); } |
Now you can compile this C++ code; just press the F9 key or just click the Run button in the center of top bar. This will let the IDE check your code and compile both the Unit and project files and link them together. You can also use the Run menu from the top to run your application. You should see this below as a form application. This time our application is able to calculate different values.
How to use loops in C++ VCL applications?
We can create another example to calculate the price of many different product counts. Here is how you can use for() loop,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
void __fastcall TForm1::Button1Click(TObject *Sender) { float price, VAT, VATprice, totalprice; price = StrToFloat(Edit1->Text); VAT = StrToFloat(Edit2->Text); UnicodeString ustr; for (int i = 0; i < 1000; i++) { ustr.printf(L“count=%4d Price = $%6.2f Total Price=$%6.2f”, i, price, i*price*(1+VAT/100)); Memo1->Lines->Add(ustr); } } |
Now you can compile this C++ code; just press the F9 key or just click the Run button in the center of top bar. This will let the IDE check your code and compile both the Unit and project files and link them together. You can also use the Run menu from the top to run your application. This time our application is able to calculate different values of counts in a loop. You should see this below as a form application.
C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.