Using C++Builder to list all available VCL styles in a ComboBox and apply a selected style using the ComboBoxChange event

Back in June a developer asked a C++Builder question on StackOverflow. The question was “How can I list all the available VCL styles in a combo box and in the ComboBoxChange event, apply that style in C++ Builder?” I answered the question and gave the example code.

One of my favorite RTL features for the VCL and FMX frameworks is the ability to customize the look and feel of your applications using Styles. The first step is to create a C++Builder VCL project and select a few of the VCL Styles in the Project | Options | Application | Appearance settings. The C++Builder 10.4 Sydney DocWiki explains that “the VCL Styles architecture has been significantly extended to support High-DPI graphics and 4K monitors. In 10.4 Sydney all graphical elements are automatically scaled for the proper resolution of the monitor the element is displayed on. This means that the scaling depends on the DPI resolution of the target computer or the current monitor, in case of multi-monitor systems.”

The C++ Application User Interface

For the application user interface I have a TButton (has code to populate the ComboBox with selected application styles) and a TComboBox (to display and allow selection of a style).

The C++ code

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

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
#include <Vcl.Themes.hpp>
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// populate the ComboBox with VCL styles that are selected
	//    in Project | Options | Application | Appearance
	ComboBox1->Items->BeginUpdate();
    try
    {
		ComboBox1->Items->Clear();

		DynamicArray<String> styleNames = Vcl::Themes::TStyleManager::StyleNames;

        for(int i = 0; i < styleNames.Length; ++i)
        {
            String styleName = styleNames[i];
			ComboBox1->Items->Add(styleName);
        }
    }
    __finally
    {
		ComboBox1->Items->EndUpdate();
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBox1Change(TObject *Sender)
{
	// set the style for the selected combobox item

	Vcl::Themes::TStyleManager::TrySetStyle(ComboBox1->Items->Strings[ComboBox1->ItemIndex],false);
}
//---------------------------------------------------------------------------

The Application in Action

TComboBox populated with VCL styles selected
Application Style Changed by TComboBox selection

References

VCL Styles Overview

Project Options Application Appearance

VCL Styles Support for High-DPI Graphics

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.

Multithreaded Sorting with C++Builder and the Parallel Programming Library (PPL)

The Parallel Programming Library (PPL) is one of my favorite features in C++Builder runtime library. PPL allows developers to create tasks that run in parallel to take advantage of multi-core processors.

Using the PPL, you can: 1) speed up loops with a Parallel For, 2) run multiple tasks in parallel using TTask, and 3) use Future Objects to allow a process run with your program focused on other work until the future value is set.

To showcase the TTask feature of the PPL, I’ve created a C++Builder VCL application (build and tested using the C++Builder 10.4 Sydney release) that runs three sort algorithms in separate tasks – Bubble Sort, Shell Sort and the ISO C++ standard Sort (which implements the Quicksort algorithm).

The User Interface

The VCL user interface for my application includes a TButton, two TMemos, and four TLabels. The TButton onClick event handler creates a vector of integers, creates three TTasks (for the sort algorithms) and waits for the sort tasks to complete using the TTask::WaitForAll method.

The Code

MainUnit.h:

#ifndef MainUnitH
#define MainUnitH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
	TButton *Button1;
	TLabel *SortingStatusLabel;
	TLabel *BubbleSortLabel;
	TMemo *Data_Memo;
	TMemo *SortResult_Memo;
	TLabel *ShellSortLabel;
	TLabel *STDSortLabel;
	void __fastcall Button1Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

MainUnit.cpp:

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

#include <vcl.h>
#include <System.Threading.hpp>
#include <vector>
#include <algorithm>
#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{

	_di_ITask My_Tasks[3];
	const int max_data = 15000;   // number of random numbers to create

	int LoopValue = 0;

	Button1->Enabled = false;
	Button1->Update();
	BubbleSortLabel->Caption = "Bubble Sort";
	BubbleSortLabel->Update();
	ShellSortLabel->Caption = "Shell Sort";
	ShellSortLabel->Update();
	STDSortLabel->Caption = "std::sort";
	STDSortLabel->Update();

	SortingStatusLabel->Caption = "Sorting "+IntToStr(max_data)+" integers!";
	SortingStatusLabel->Update();

	// Windows GetTicks() start and stop for each sort method
	int StartBubble,StopBubble;
	int StartShell,StopShell;
	int StartSTD,StopSTD;

	Data_Memo->Lines->Clear();
	SortResult_Memo->Lines->Clear();

	// create a vector of data that all sort algorithms will use
	std::vector<int> my_data;

	// populate the vector with integers
	for (int i = 1; i <= max_data; i++) {
		int random_value = Random(max_data);
		my_data.push_back(random_value);
		// Data_Memo->Lines->Add(IntToStr(random_value));
	}

	// copy data vector to sort vectors
	std::vector<int> bubble_data = my_data;
	std::vector<int> shell_data = my_data;
	std::vector<int> std_data = my_data;

	// First Task - Bubble Sort
	My_Tasks[0] = TTask::Create([&](){
		// Set Bubble Sort Windows GetTickCount()
		StartBubble = GetTickCount();
		// body of Bubble Sort
		bool swapp = true;
		while(swapp){
			swapp = false;
			for (size_t i = 0; i < bubble_data.size()-1; i++) {
				if (bubble_data[i]>bubble_data[i+1] ){
					bubble_data[i] += bubble_data[i+1];
					bubble_data[i+1] = bubble_data[i] - bubble_data[i+1];
					bubble_data[i] -=bubble_data[i+1];
					swapp = true;
				}
			}
		}
		// Set the Bubble Sort Stop GetTicks()
		StopBubble = GetTickCount();
	});
	// Start the Bubble Sort Task
	My_Tasks[0]->Start();


	// Second Task - Shell Sort
	My_Tasks[1] = TTask::Create([&](){
		// Set Shell Sort Windows GetTickCount()
		StartShell = GetTickCount();
		// body of the Shell Sort
		for (int gapSize = shell_data.size() / 2; gapSize > 0; gapSize /= 2) {
			for (int currentIndex = gapSize; currentIndex < shell_data.size(); currentIndex++) {
				// save the currentIndex
				int currentIndexCopy = currentIndex;
				// save the value of the currentIndex
				int item = shell_data[currentIndex];
				while (currentIndexCopy >= gapSize && shell_data[currentIndexCopy - gapSize] > item) {
					shell_data[currentIndexCopy] = shell_data[currentIndexCopy - gapSize];
					currentIndexCopy -= gapSize;
				}
				shell_data[currentIndexCopy] = item;
			}
		}
		// Set the Shell Sort Stop GetTicks()
		StopShell = GetTickCount();
	});
	// Start the Shell Sort
	My_Tasks[1]->Start();


	// Third Task - std::sort
	My_Tasks[2] = TTask::Create([&](){
		// Set std::sort Windows GetTickCount()
		StartSTD = GetTickCount();
		// Body of the std::sort
		std::sort(std_data.begin(),std_data.end());
		// Set the std::sort Stop GetTicks()
		StopSTD = GetTickCount();
	});
	// Start the Shell Sort
	My_Tasks[2]->Start();

	// wait until all of the sorting tasks complete
	TTask::WaitForAll(My_Tasks, sizeof(My_Tasks)/sizeof(My_Tasks[0])-1);

	SortingStatusLabel->Caption = "Sorting All done!";

	BubbleSortLabel->Caption = "Bubble Sort Time: "
		+ IntToStr(StopBubble - StartBubble)
		+ " ms";
	BubbleSortLabel->Update();

	ShellSortLabel->Caption = "Shell Sort Time: "
		+ IntToStr(StopShell - StartShell)
		+ " ms";
	ShellSortLabel->Update();

	STDSortLabel->Caption = "std::sort: "
		+ IntToStr(StopSTD - StartSTD)
		+ " ms";
	STDSortLabel->Update();

	// if you want to see the sort results un-comment
	// one of the for loops and the sort result memo statement
	// for(int n : std_data) {
	// for(int n : bubble_data) {
	// for(int n : shell_data) {
		// SortResult_Memo->Lines->Add(IntToStr(n));
	// }

	// clear the vectors
	my_data.clear();
	bubble_data.clear();
	shell_data.clear();
	std_data.clear();

	Button1->Enabled = true;
}
//---------------------------------------------------------------------------

The form after sorting 15,000 integers

References

PPL – Parallel Programming Library – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_the_Parallel_Programming_Library

Using TTask – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TTask_from_the_Parallel_Programming_Library

Using TParallel::For – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TParallel.For_from_the_Parallel_Programming_Library

Using TTask::IFuture – http://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_TTask.IFuture_from_the_Parallel_Programming_Library

Algorithms Library – https://en.cppreference.com/w/cpp/algorithm

std::sort – https://en.cppreference.com/w/cpp/algorithm/sort

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.