Two VCL Example Applications that Use C++Builder and the C++ Boost Libraries

Boost is a set of open source C++ libraries that build on the ISO C++ programming language. In some cases, the Boost library functionality has become part of recent ISO C++ standards. RAD Studio allows you to install a subset of Boost that has been fully tested and preconfigured specifically for C++Builder. Use the GetIt Package Manager to install the Boost libraries for the Win32 classic C++ compiler, Win32 Clang-enhanced C++ compiler and Win64 Clang-enhanced compiler.

Boost libraries available in C++Builder’s GetItPackage Manager

boost::filesystem and std:filesystem VCL example

The ISO C++ std::filesystem evolved from the Boost filesystem library. The Filesystem library started in Boost, then became an ISO C++ Technical Specification and was finally merged into the ISO C++17 standard. The first example shows how to create a C++Builder VCL application using the Boost filesystem and the ISO C++ filesystem.

The VCL form contains two TButton, one TEdit and two TMemo components. The TEdit is used to set a path to files and directories on your hard drive. One button OnClick event handler will use the boost::filesystem functions to display the contents of the path. The other button OnCLick event handler will use the std::filesystem functions to display the contents of the same path. Why use both libraries? You may have an application and compiler than does not support the latest C++17 filesystem library standard. There are additional boost library versions available to support a wider range of platform filesystem operations.

VCL form for Boost and Std filesystem libraries application

C++Builder VCL application after using the boost and std filesystem library buttons

Filesystem VCL app mainunit.h:

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *BoostButton;
	TEdit *Edit1;
	TMemo *Memo1;
	TButton *Cpp17Button;
	TMemo *Memo2;
	void __fastcall BoostButtonClick(TObject *Sender);
	void __fastcall Cpp17ButtonClick(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Filesystem VCL App MainUnit.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>

/*
	https://en.cppreference.com/w/cpp/filesystem
	The filesystem library was originally developed as boost.filesystem,
	was published as the technical specification ISO/IEC TS 18822:2015,
	and finally merged to ISO C++ as of C++17.

	https://www.boost.org/doc/libs/1_70_0/libs/filesystem/doc/index.htm
*/

#include <boost/filesystem.hpp>
namespace Boostfs = boost::filesystem;

#include <filesystem>
namespace Cpp17fs = std::filesystem;

#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::BoostButtonClick(TObject *Sender)
{

	// Boost Filesystem verion

	Memo1->Lines->Clear();
	// use the Boost FileSystem to get directories and files using path in editbox
	Boostfs::path directoryPath = Edit1->Text.c_str();
	for (const auto& entry : Boostfs::directory_iterator(directoryPath)) {
		Boostfs::path p = entry.path();
		// test if the path is a file
		if (is_regular_file(p)) {
			int fsize = file_size(p);
			std::string s = p.string() + " : size = ";
			Memo1->Lines->Add(s.c_str() + IntToStr(fsize));
		}
		// test if the path is a directory
		else if (is_directory(p)) {      // is p a directory?
			std::string s = p.string() + " : directory";
			Memo1->Lines->Add(s.c_str());
		}
		// otherwise it is something else :)
		else {
			std::string s = p.string() + " not a file or directory";
			Memo1->Lines->Add(p.c_str());
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Cpp17ButtonClick(TObject *Sender)
{
	// C++17 FileSystem version

	Memo2->Lines->Clear();
	// use C++17 std FileSystem library to get directories given a path in the editbox
	Cpp17fs::path directoryPath = Edit1->Text.c_str();
	for (const auto& entry : Cpp17fs::directory_iterator(directoryPath)) {
		Cpp17fs::path p = entry.path();
		if (Cpp17fs::is_directory(p)) {
			std::string s = p.string() + " : directory";
			Memo2->Lines->Add(s.c_str());
		}
		else if (Cpp17fs::is_regular_file(p)) {
			int fsize = Cpp17fs::file_size(p);
			std::string s = p.string() + " : size = ";
			Memo2->Lines->Add(s.c_str() + IntToStr(fsize));
		}
		else {
			std::string s = p.string() + " not a file or directory";
			Memo2->Lines->Add(p.c_str());
		}
	}
}
//---------------------------------------------------------------------------

boost::circular_buffer VCL example

The boost circular buffer (also known as a ring or cyclic buffer) library allows for the storing of data. The boost is designed to support fixed capacity storage. When the buffer is full, additional elements will overwrite existing elements at the front and back of the buffer (depending on the operations used).

The VCL form contains three TButton, one TSpinEdit and one TMemo components. One TButton OnClick event handler shows the contents of the circular buffer (originally populated by the Form’s OnShow event handler. The other two TButton OnClick event handlers use the boost circular buffer push_front and push_back public member functions.

Boost circular buffer C++Builder VCL form
C++Builder VCL form with Circular Buffer populated by OnShow event handler
Application showing contents of Circular Buffer after Add to front button is clicked
Application showing contents of Circular Buffer after Add to back button is clicked
Circular Buffer VCL app mainunit.h:

//---------------------------------------------------------------------------

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.Samples.Spin.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *AddToCircularQueueFrontButton;
	TSpinEdit *SpinEdit1;
	TMemo *Memo1;
	TButton *ShowCircularBufferButton;
	TButton *AddToCircularQueueBackButton;
	void __fastcall FormShow(TObject *Sender);
	void __fastcall ShowCircularBufferButtonClick(TObject *Sender);
	void __fastcall AddToCircularQueueFrontButtonClick(TObject *Sender);
	void __fastcall AddToCircularQueueBackButtonClick(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

Circular Buffer VCL app mainunit.cpp:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <boost/circular_buffer.hpp>
#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;

// Create a circular buffer with a capacity for 3 integers.
boost::circular_buffer<int> cb(3);

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	// initialize circular buffer with 3 integers
	cb.push_back(1);
	cb.push_back(2);
	cb.push_back(3);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ShowCircularBufferButtonClick(TObject *Sender)
{
	int circularbuffersize = cb.size();
	Memo1->Lines->Clear();
	Memo1->Lines->Add("Circular Buffer Size = "+IntToStr(circularbuffersize));
	Memo1->Lines->Add("Items:");
	// display items in the circular buffer
	for (int i : cb)
		Memo1->Lines->Add("  "+IntToStr(i));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AddToCircularQueueFrontButtonClick(TObject *Sender)
{
	cb.push_front(SpinEdit1->Value);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::AddToCircularQueueBackButtonClick(TObject *Sender)
{
	cb.push_back(SpinEdit1->Value);
}
//---------------------------------------------------------------------------

References

Boost C++Builder DocWiki

Boost C++ Libraries home page

Boost version 1.70

Converting from Boost to std::filesystem by Scott Furry as a guest post on Bartlomiej Filipek (Bartek) blog.

boost::filesystem library documentation

C++ std::filesystem documentation

boost::circular_buffer documentation

boost and std filesystem VCL app source code project (zip file)

boost circular buffer VCL app source code project (zip file)

C++Builder Product Information

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.

Building a C++Builder RSS Feeds VCL Application with XMLDocument, NetHTTPClient, NetHTTPRequest and WebBrowser Components

I have many favorite prebuilt components that are included with C++Builder 10.4 Sydney. In this blog post I’ll show you how to create an RSS Feeds VCL (you can also use the same approach for a FireMonkey FMX) application using the XMLDocument, NetHTTPClient, NetHTTPRequest and WebBrowser components.

Start by creating a C++Builder VCL application. Set the form’s WindowState property to wsMaximized. Add a Panel, Button, ListBox (used to hold the list of RSS feed URLs to process) and a few labels and align them to the top of the form. Add Memo (to display the Feed XML), ListBox (to contain the title and URL for each article found in the feeds) and WebBrowser (to display the web page when you click on an item in the articles list box) components to the rest of the form.

Main Form
The RSS Feed application’s main form.

To populate the Panel’s listbox, I use a text file, “FeedsList.txt”, which contains a number of RSS feed URLs. The panel listbox is populated in the Form’s OnShow event handler.

Clicking on the button will process all of the RSS feed URLs and add each article and URL item found into the list box of articles found.

The XMLDocument component has a DOMVendor property to select the DOM implementation to use for parsing and manipulating the XML document.

DOMVendor choices

Clicking on an item in the articles list box uses the OnClick event handler to call the WebBrowser Navigate method  for the selected article URL. In C++Builder 10.4 Sydney there is a new property added to the WebBrowser component that lets you choose which browser engine will be used on Windows. I’ve chosen the EdgeIfAvailable engine.

SelectedEngine

Here is the contents of the FeedsList.txt file:

https://isocpp.org/blog/rss
https://herbsutter.com/feed/
http://feeds.hanselman.com/scotthanselman
http://feeds.dzone.com/home
https://news.ycombinator.com/rss
http://www.odbms.org/feed/
https://www.techmeme.com/feed.xml
https://techcrunch.com/feed/
http://feeds.feedburner.com/oreilly/radar/atom
http://feeds.feedburner.com/appdevelopermagazine
https://www.infoworld.com/index.rss
https://newsroom.ibm.com/announcements?pagetemplate=rss
https://www.computerworld.com/index.rss
https://techxplore.com/rss-feed/
https://sdtimes.com/feed/
https://www.geeksforgeeks.org/feed/
https://feeds.feedburner.com/venturebeat/SZYF
http://feeds.feedburner.com/ProgrammableWeb

Here is a bitmap of the running application:

Finally here is the source code for the application:

//---------------------------------------------------------------------------

#include <vcl.h>
#include <fstream>
#pragma hdrstop

#include "MainFeedUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm2 *Form2;
//---------------------------------------------------------------------------
__fastcall TForm2::TForm2(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm2::ArticlesFoundListBoxClick(TObject *Sender)
{
	// for the ListBox item clicked - get the URL and Browse to the article
	LabelStatus->Caption = ArticlesFoundListBox->Items->Names[ArticlesFoundListBox->ItemIndex];
	ArticleWebBrowser->Navigate(ArticlesFoundListBox->Items->Values[ArticlesFoundListBox->Items->Names[ArticlesFoundListBox->ItemIndex]]);
}
//---------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
	// Find and save Title and URL for items found
	std::ofstream fs (AnsiString(FormatDateTime("yyyy-mm-dd-hhnnss",Now())+"_RSSFound.txt").c_str());
	fs << AnsiString("RSS Feed for: "+ NetHTTPRequest1->URL).c_str() << std::endl;
	fs << AnsiString(FormatDateTime("dddd mmmm dd, yyyy @ hh:nn:ss",Now())).c_str() << std::endl;
	fs << std::endl;

	// Clear the Articles Found List Box to prepare for the title and URL of articles
	ArticlesFoundListBox->Clear();
	FeedsItemsCountLabel->Caption = "Items Found = 0";

	// get all articles and URLs in all feeds
	for (int i = 0; i < FeedsListBox->Count; i++) {
		// Get the RSS feed URL string from the ListBox
		NetHTTPRequest1->URL = FeedsListBox->Items->Strings[i];

		UrlLabel->Caption = "Feed URL: "+NetHTTPRequest1->URL;
        UrlLabel->Update();

		// Use NetHTTPRequest Execute method to get the RSS Feed XML
		UnicodeString FeedString = NetHTTPRequest1->Execute()->ContentAsString();

		// copy the XML string to the Memo
		MemoFeedXML->Lines->Clear();
		MemoFeedXML->Lines->Text = FeedString;
		MemoFeedXML->Update();

		// load the RSS Feed XML into the XMLDocument
		XMLDocument1->LoadFromXML(FeedString);
		XMLDocument1->Active = True;

		LabelStatus->Caption = "Processing RSS for "+NetHTTPRequest1->URL;
		LabelStatus->Update();

		// find the RSS feed channel node
		_di_IXMLNode ChannelNode = XMLDocument1->DocumentElement->ChildNodes->FindNode ("channel");
		// test to make sure the ChannelNote is found
		if (ChannelNode != NULL) {
			for (int I=0;I<ChannelNode->ChildNodes->Count;I++) {
				// iterate through child nodes
				_di_IXMLNode ItemNode = ChannelNode->ChildNodes->Get(I);
				// if child node is an item then get the title, pubDate and URL
				if (ItemNode->NodeName == "item") {
					LabelStatus->Caption = "Processing Node " + IntToStr(I);
					LabelStatus->Update();
					UnicodeString title = ItemNode->ChildValues ["title"];
					UnicodeString pubDate = ItemNode->ChildValues ["pubDate"];
					// author := ItemNode.ChildValues ['author'];    // could be nil
					UnicodeString url = ItemNode->ChildValues ["link"];

					// populate the articles found ListBox with the pair of title and URL
					ArticlesFoundListBox->Items->AddPair(title,url);
					ArticlesFoundListBox->Update();
					FeedsItemsCountLabel->Caption = "Items Found = "+IntToStr(ArticlesFoundListBox->Count);
					FeedsItemsCountLabel->Update();

					// write the Title, pubDate and URL to the text file
					fs << AnsiString(title).c_str() << std::endl;
					fs << AnsiString(pubDate).c_str() << std::endl;
					fs << AnsiString(url).c_str() << std::endl;
					fs << std::endl;
				}
			}
		}

	}

	fs << std::endl;
	fs << AnsiString("Items Found = "+IntToStr(ArticlesFoundListBox->Count)).c_str() << std::endl;
	fs << "end of file" << std::endl;
	fs.close();   // close the text file
	LabelStatus->Caption = "RSS Processing Done!";
    UrlLabel->Caption = "";
}
//---------------------------------------------------------------------------
void __fastcall TForm2::FormShow(TObject *Sender)
{
	// load RSS Feeds ListBox with the "FeedsList.txt" text file
    // I put the text file in the same folder as the app .EXE file
	FeedsListBox->Items->Clear();
	FeedsListBox->Items->LoadFromFile("FeedsList.txt");
	LabelStatus->Caption = "RSS Feed Urls Loaded = "+IntToStr(FeedsListBox->Count);
	LabelStatus->Update();

}
//---------------------------------------------------------------------------

References

Using TXMLDocument

Using the Document Object Model

Using an HTTP Client

System.Net.HttpClientComponent.TNetHTTPClient

System.Net.HttpClientComponent.TNetHTTPRequest

Using TEdgeBrowser Component and Changes to the TWebBrowser Component

RSS 2.0 Specification

Download Source Code ZipFile for RSSFeedListsUsingTextFileVCLCpp

C++Builder Product Information

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.