Quantcast
Channel: Programming - Embarcadero Community
Viewing all 167 articles
Browse latest View live

Foren-Tage 2017 in Hamburg: Tickets für den Community Abend

$
0
0

Die Foren-Tage sind eine mehrtägige Community-Konferenz für Software-Entwickler. Veranstaltet werden die Foren-Tage von den drei Delphi-Foren „Entwickler-Ecke“ und „Delphi-Treff“ und „Delphi-PRAXiS“ zusammen mit Embarcadero. Wir sind im Wesentlichen das Team, das von 2005 bis 2015 die Delphi-Tage realisiert hatte. Von der Community für die Community! Wir freuen uns auf Euch am 21.-23. September 2017 in Hamburg In diesen Jahren haben wir Erfahrungen gesammelt, die wir in die Foren-Tage einfließen lassen, die aus unserer Sicht nun die Weiterentwicklung dieser Veranstaltungsreihe darstellen. Die zentrale Idee dieser Veranstaltung ist es, der (deutschsprachigen) Delphi- und C++-Community eine Möglichkeit zu eröffnen, sich live und von Angesicht zu Angesicht auszutauschen. An mehreren Tagen werden wir Workshops und interessante Vorträge erleben, Spaß und gegenseitiger Austausch von Wissen werden dabei im Mittelpunkt stehen

Die Veranstaltung ist soweit in trockenen Tüchern und die Tickets sind nun für die Foren-Tage in Gänze verfügbar:

Hauptveranstaltung am Samstag:
https://www.xing-events.com/forentage.html

Community Abend am Freitag Abend:
https://en.xing-events.com/community_abend_forentage.html

Workshop-Tage am Donnerstag/Freitag:
https://en.xing-events.com/WorkshopsForenTage2017.html

Weitere Infos:
https://forentage.de

Agenda (vorläufig):
https://forentage.de/index.php/veranstaltung/agenda/

 


Tech Tipp #7: Eine kleine UDF in InterBase

$
0
0

Frage: Ich vermisse die Funktion XYZ in InterBase. Warum gibt es die nicht?

Antwort: In der Tat gibt es einige Funktionen in InterBase (für die DML) in InterBase, die man vielleicht von anderen Datenbanken her kennt, die aber in InterBase nicht vorhanden sind.....

Aber es gibt eine (einfache!) Lösung: Man schreibt sich diese Funktion(en) selbst.

Ein gutes Video von meinem Kollegen Stephen Ball findet man dazu auch hier: https://www.youtube.com/watch?v=9bfaU5mdlaY

Daraus erstmal zwei wichtige Regeln:

  • Eine UDF sollte simple und schnell sein
  • Eine UDF sollte niemals den Status der Datenbank direkt manipulieren

Ein kleines Beispiel: In MS SQL Server/T-SQL gibt es einen ISNULL() oder auch im MySQL ein IFNULL(). Diese kann man zwar auch mit einem CASE umschreiben, macht es aber unter Umständen weniger gut lesbar:

Interbase Original:

SELECT
    (CASE
    WHEN column IS NULL
    THEN 'Alternative Value'
    ELSE column
    END) AS column
FROM
    table

Der Wunsch könnte sein:

SELECT
    ISNULL(column,'Alternative Value') AS column
FROM
    table

Sieht besser aus.... ist aber in InterBase nicht direkt möglich. Dafür gibt es UDFs (User Defined Functions).

Wie baut man das jetzt ein? Über eine DLL (32/64 Bit) bzw ein SO (Shared Object für Linux/Mac), die man in das passende InterBase Verzeichnis kopiert (hier: Windows, 64 Bit): C:\\Program Files\\Embarcadero\\InterBase\\UDF

Schritt für Schritt:

  • Delphi starten (oder C++Builder)
  • Datei | Neu | Weitere
  • Dynamische Link-Bibliothek
  • Date | Neu | Unit - Delphi
  • Hier, in der Unit, implementiert man dann die Funktionen im Interface- und Implementation-Teil der neuen Unit
  • Zielplattform wählen/ergänzen (32/64 Bit, Windows/Linux/Mac)
  • Export der Funktionen
  • DLL erzeugen

Quelltext der DLL  / Unit

library myUDFs;

uses
  System.SysUtils,
  System.Classes,
  UUDFFunctions in 'UUDFFunctions.pas';

{$R *.res}

begin
end.
unit UUDFFunctions;

interface

function IsNull(s1, s2: PChar): PChar; cdecl;

exports IsNull name 'IsNull';

implementation

function IsNull(s1, s2: PChar): PChar; cdecl;
begin
  if string(s1) = '' then // es gibt keinen NULL String
    result := s2
  else
    result := s1;
end;

end.

 

Wichtige Bemerkungen bei der Variablenübergabe:

  • Alle Variablen werden von InterBase als Referenzparameter übergeben
  • Ausnahme: PChar (Zeichenketten werden generell als PChar übergeben), die damit schon selbst eine Referenz darstellen.
    Also ein function irgendwas(var i:Integer;s:PChar)

Der Import mittels SQL-Befehl in iSQL / IBConsole:

DECLARE EXTERNAL FUNCTION IsNull
  CSTRING(256) CHARACTER SET NONE,
  CSTRING(256) CHARACTER SET NONE
RETURNS CSTRING(256) CHARACTER SET NONE
ENTRY_POINT 'IsNull' MODULE_NAME 'MyUDFs';

Bemerkungen zu den Funktionsnamen und der UDF selbst

  • Der Funktionsname und der Entry-Point können gleich heissen! Müssen aber nicht (hier heisst alles "IsNull")
  • IsNull heisst die Funktion in der Delphi-Unit, die als "IsNull" exportiert wird und auch dem InterBase-System wird diese als IsNull bekanntgegeben.
  • Der DLL-Name kann ohne den Zusatz ".DLL" angegeben werden
  • Die UDF sollte/kann im \UDF-Verzeichnis der InterBase-Installation liegen, kann aber auch in eine spezifiziertem Verzeichnis ("EXTERNAL_FUNCTION_DIRECTORY Parameter der IBCONFIG liegen)
  • Die DECLARE gilt immer nur für die verbundene Datenbank! Jede UDF muss in jeder Datenbank(Datei) deklariert werden
  • Die Funktionen sieht man auch in der IBConsole:

Anschliessend funktioniert auch ein IsNull in InterBase

SELECT isnull(A."SPALTE",'Nix drin') AS RESULT
FROM
"TABELLENNAME" A;

Die Möglichkeiten sind damit (fast) unendlich.....

Source: myUDFs

RAD Studio 10.2 Tokyo Release 1 ist verfügbar (10.2.1)

$
0
0

Release Notes:

http://docwiki.embarcadero.com/RADStudio/Tokyo/de/10.2_Tokyo_-_Release_1

Download ISO:

https://cc.embarcadero.com/item/30786  (jedermann/frau) oder

https://cc.embarcadero.com/Item/30785  (registrierte Benutzer)

(Beide ISOs sind gleich.... )

Download Webinstaller:

https://cc.embarcadero.com/Item/30783

Beschreibung / Neuerungen

10.2 Tokyo – Release 1 ist ein Update für Delphi 10.2 Tokyo, C++Builder 10.2 Tokyo und RAD Studio 10.2 Tokyo, das für alle Kunden mit einem aktiven Update-Abonnement erhältlich ist.

10.2 Tokyo – Release 1 enthält die folgenden neuen Leistungsmerkmale, Verbesserungen und Fehlerkorrekturen:

  • Leistungsverbesserungen für den Delphi-Linux-Server für RAD Server und DataSnap.
  • Updates für Delphi- und C++-Compiler und -Linker, die Probleme beim Laden von Packages, insbesondere beim Debugging, auf Windows 10 Creators Update beheben.
  • Unterstützung für die neuesten Versionen von iOS und Xcode (iOS 10.3 und XCode 8.3.2) für den iOS App Store.
  • FireDAC-Unterstützung für MSSQL 2012, 2014, 2016 und ODBC-Treiber 13.
  • Wichtige Verbesserungen für den C++-Linker für das Linken großer Projekte.
  • Korrekturen und Verbesserungen für die Laufzeitbibliothek und die VCL.
  • Weitere Android-Verbesserungen zu Rendering und Leistung von Steuerelementen und Korrekturen von Problemen mit TEdit bei Android N.
  • FireDAC-Unterstützung für Exclusive Isolation Level (EN) und Transaction Wait Time (EN) von InterBase 2017.
  • Korrekturen für mehr als 140 von Kunden in Quality Portal berichtete Probleme.

Release 1 enthält auch Verbesserungen für "Tokyo Toolchain Hotfix" (veröffentlicht am 3. Mai 2017) und "Android Compatibility Patch" (veröffentlicht am 22. Juni 2017). Klicken Sie hier, um eine vollständige Liste der Features und Fehlerkorrekturen anzuzeigen.

Hinweis: Das 10.2 Tokyo – Release 1 kann nur von Kunden mit einem aktiven Update-Abonnement heruntergeladen und installiert werden.

Installation:

De/Neuinstallation mit der Möglichkeit die Einstellungen zu behalten.

Tech Tipp #8: iOS und macOS SDK Versionen

$
0
0

Frage: Ich habe das neueste Xcode installiert (hier: 8.3.3) und das Release 1 von Tokyo 10.2. Dennoch wird mir beim Importieren des SDKs nur angezeigt

  • iPhoneOS 10.3.1 bzw
  • MacOSX 10.12.4

Mein iPhone/iPad/iOS-Gerät hat aber die iOS Version 10.3.3 bzw macOS ist auf Version 10.12.6.

Das verwirrt mich!

Antwort: Das verwirrt mich auch. Die Lösung ist aber relativ einfach: Die Xcode-Version korreliert nicht mit der iOS/macOS-SDK-Version. Es gibt zur Zeit kein neueres SDK innerhalb von Xcode (veröffentlichte Versionen). Auch, wenn sich die Betriebssystemversion (iOS/macOS) erhöht, heisst das nicht zwangsläufig, daß es eine neuere SDK Version gibt.

Auf der Mac-Seite kann man das (im Terminal) schnell und leicht feststellen:

Last login: Wed Aug  9 09:13:59 on ttys000
MacBookPro:~ meissing$ xcodebuild -sdk -version

Was eine solche Ausgabe erzeugt (gekürzt):

iPhoneOS10.3.sdk - iOS 10.3 (iphoneos10.3)
SDKVersion: 10.3
Path: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.3.sdk
PlatformVersion: 10.3
PlatformPath: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform
ProductBuildVersion: 14E8301
ProductCopyright: 1983-2017 Apple Inc.
ProductName: iPhone OS
ProductVersion: 10.3.1

MacOSX10.12.sdk - macOS 10.12 (macosx10.12)
SDKVersion: 10.12
Path: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk
PlatformVersion: 1.1
PlatformPath: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform
ProductBuildVersion: 16E185
ProductCopyright: 1983-2017 Apple Inc.
ProductName: Mac OS X
ProductUserVisibleVersion: 10.12.4
ProductVersion: 10.12.4

Also alles im grünen Bereich.

Apple hat die Xcode/SDK-Versionen hier dokumentiert:
https://developer.apple.com/library/content/releasenotes/DeveloperTools/RN-Xcode/Chapters/Introduction.html

Ältere Xcode Versionen und die damit enthaltenen SDKs findet man hier:
https://developer.apple.com/download/more/?name=Xcode

Pro-Tipp: Im Ordner Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/ finden sich alle SDKs der installierten Xcode-Version (normalerweise nur eins). Hier kann man (unsupported! Apple möchte, daß man immer mit dem aktuellsten SDK entwickelt) auch ältere SDKs aus älteren Xcode Versionen unterschieben (dazu muss man das alte Xcode installiert haben und die SDKs aus diesem extrahieren (Time Machine, separater Mac, macOS-VM, Kollege, ...)

Tech Tipp #9: InterBase local, RAD Studio und "unavailable database"

$
0
0

Frage: Ich nutze ein lokal installiertes InterBase. Ich möchte über Datenbankzugriffskomponenten darauf zugreifen. Aber sowohl FireDAC, als auch InterBase Express/IBX geben mir diese Nachricht:

FireDAC:

InterBase Express/IBX:

Folgende Beobachtungen habe ich gemacht:

  • Das passiert nur in der IDE - In der IBConole kann ich auf die Datenbanken zugreifen
  • Die Dateien sind definitiv vorhanden
  • Benutzernamen und -kennwort habe ich richtig eingegeben
  • Stelle ich in IBX auf "Remote" um (mit "localhost") funktioniert es
  • Stelle ich in FireDAC auf "TCPIP" um (mit server=localhost) funktioniert es

Wodran liegt das?

Antwort: Das liegt wahrscheinlich an den Umgebungsvariablen in der IDE vom RAD Studio/Delphi/C++Builder. Es gibt zwei Variablen, die hier zum Tragen kommen und vom RAD Studio für die Verbindung genommen werden. 

  • INTERBASE - Das Verzeichnis der InterBase Installation; 
  • IB_PROTOCOL - Der Instanzname; normalerweise/default "gds_db". Dies ist auch hier weiter dokumentiert. Faktisch ist das die Port-Nummer default:3050) von InterBase

Normalerweise sind diese nicht gesetzt; können aber (gerade bei Mehrfach-Instanzen von InterBase) das Ganze etwas durcheinander bringen. Man muss dann die Variablen setzen bzw ändern.

Generell können die Variablen unter "Tools | Optionen | Umgebungsoptionen | Umgebungsvariablen" gesetzt werden. Normalerweise ist dies nicht nötig, da es nur eine Instanz von InterBase gibt, aber das RAD Studio/Delphi/C++Builder kann man für die Standardwerte hier anpassen

INTERBASE
C:\Program Files\Embarcadero\InterBase
IB_PROTOCOL
gds_db

Nach dem Ändern der Umgebungsvariablen ist ein Neustart der IDE notwendig!


 

Eine andere Möglichkeit für den "unavailable database" Fehler kann InterBase selbst sein: Wenn man die "Developer-Edition" benutzt, nimmt diese nach 48 Stunden keine Verbindungen mehr an. Ein Neustart des InterBase Servers behebt dann auch das Problem.

 

Tech Tipp #10: ClearType von Delphi aus/einschalten

$
0
0

Frage: Ich möchte (aus welchen Gründen auch immer) für den aktuell angemeldeten Benutzer das ClearType von Windows ausschalten. Wie geht das?

Antwort: ClearType lässt sich unter Windows 7/8/10 mittels ClearType-Textoptimierungs-Program (cctune.exe) über die Bordmittel von Windows ein- bzw ausschalten und konfigurieren:

Dabei handelt es sich um eine Pro-User-Einstellung. Microsoft selbst stellt dafür den WinAPI-Befehl SystemParametersInfo bereit; mittels passender Aktion kann man hier das ClearType Verhalten beeinflussen.

Quick-and-Dirty Lösung (bitte weiter lesen!):

Ausschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING,0,0,0);
  InvalidateRect(0, nil, True);

Einschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING,1,0,0);
  InvalidateRect(0, nil, True);

Das jeweilige Absetzung von InvalidateRect(0, nil, True); erzeugt dabei einen kompletten Screen-Refresh....

Die Original-Paramter sind

BOOL WINAPI SystemParametersInfo(
  _In_    UINT  uiAction,
  _In_    UINT  uiParam,
  _Inout_ PVOID pvParam,
  _In_    UINT  fWinIni
);

Man kann, sollte das etwas besser gestalten

Einschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING, Cardinal(true), 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);
  SystemParametersInfo(SPI_SETFONTSMOOTHINGTYPE, FE_FONTSMOOTHINGCLEARTYPE, 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);

Ausschalten:

  SystemParametersInfo(SPI_SETFONTSMOOTHING, Cardinal(false), 0, SPIF_UPDATEINIFILE OR SPIF_SENDCHANGE);

Dadurch erreicht man beim Einschalten vier Dinge:

  • Cardinaltype wird richtig/leserlicher gesetzt
  • Durch SPIF_UPDATEINIFILE wird das auch persistent in der Windows-Umgebung gespeichert
  • Durch SPIF_SENDCHANGE wird auch gleich die Message zur Aktualisierung der Oberfläche gesendet (ein InvalidateRect ist nicht mehr nötig)
  • Durch eine zusätzliche "Action" SPI_SETFONTSMOOTHINGTYPE wird der Type des ClearType gesetzt (siehe MSDN-Doku-Link weiter oben)

Beim Ausschalten erreicht man nur bessere/konformere Lesbarkeit und das senden der Window-Message zur Aktualisierung.

 

 

Neue Videoreihe / Video Tutorial #1: AQTime

$
0
0

Im Zuge meiner Arbeit wird es alle paar Tage (10<n<20) ein Kurzvideo geben; rund um das RAD Studio / Delphi / C++Builder.

Dauer ist maximal 5 Minuten und stellt (ohne Folien) ein Thema kurz dar. Es hat keinen Anspruch auf einen allumfassenden Einblick, sondern nur auf eine kurze Einführung.

Hier das erste Video:


[YoutubeButton url='https://www.youtube.com/watch?v=OZzY_2JqdGY']

An Overview of Elements of Functional Programming in C++ (continuation)

$
0
0

Part II

Where it is told about closures and "functional containers" - data structures that can store pointers to functional objects of various types

std::function

While the functional paradigm proclaims that "everything is a function," in imperative programming we sometimes encounter the need to manipulate functions like with ordinary objects. Usually this happens by creating a pointer to the address of the procedure or method. However, in this case and others, high-level languages leave it up to us the use of the function pointer, the care of the accordance to the call signature, the passed parameters and other low-level pleasures. Naturally, if we intend to manipulate variables that store pointers to procedures or methods, functors and lambda functions, we inevitably run into headaches due to the different intrinsic nature of these objects. Meanwhile, we would like to think about our algorithm, and not to unravel the puzzles that the compiler tosses us. All of the above objects have only one, but extremely important, common  property - they are callable. Is there a way to refer to them in a uniform style?

STL says: "Yes", and this way is the using of  std::function.

Instances of std::function can store, copy, and invoke any callable target functions, lambda expressions, bind expressions, or other function objects, as well as pointers to member functions and pointers to data members

cppreference says. This is what needed for our “functional” purposes - we can think of this (and use it) as a variable in the our “functional” world.

C++ is to this day is a strongly typed language. Together with std::function we can refuse to use arbitrary pointers for tricks with references to our functions, functors, member functions, and lambdas. In the world of function pointers, this is something like the legalization of types for such entities. We can define a template, declare a variable of a callable type and assign necessary values to them when we want.

Syntax

Class template std::function is a general-purpose polymorphic function wrapper.

template< class > class function;

or

template< class R, class... Args > class function<R(Args...)>

 

Example

Let's look at the example of a console application which generates a vector of integers and calculates a number of occurrences in a specified diapason.

We will use  std::for_each  and std::count_if  algorithms from STL to сircumvent all elements (in particular, for print) and to count special condition.

The functor class Adder will be used to fill a vector with integer elements. A definition of its operator()method differs from functor Generator considered in one of the previous examples in Part I. Here we add vector elements ourselves in a for loop, and don’t use std::generate. In the operator of the functor an argument from the outside is given to calculate the new element. Thus, we do not need to store it inside.

class Adder {

...

public: void operator()(int val) { _vec->push_back(val); }

...

};

 

Pay attention to how we pass the vector to the inside of the constructor of the Adder functor, and store the pointer to it in a private field.

private: vector<int>* _vec;

...

Adder(vector<int>& vec) { _vec = &vec; };



We can not declare a vector variable directly in a private field because even if we pass the original vector by reference into the constructor, this field will be assigned a local copy, to which elements will be added.

...

Adder add(v);

...

 

Note that actions stored in the  std::function variable can be of a completely different nature,  matching by the required call signature only. We can combine heterogeneous actions in this role, and it is possible to think about applications when one can consider not the consistent act of the same operation to set of objects, but the impact of an ordered (or unordered!) set of operations to the same object.

Let's look at the example of a conveyor belt in terms of trash sorting, the subject is an employee or an automated machine performing such sorting. If we consider the assembly line of airplanes, it may be more convenient to consider the sequence of operations for each airplane separately. In fact, we are dealing with the product of sets of objects and operations, and this statement of the problem determines the angle of view on the situation. The std::function gives us the ability to naturally manipulate operations - it already smells like true functional programming!

Returning to our example we declare a variable for the abstract operation:

function<void(int)> operation;

 

We can assign to this variable functor Adder, which knows how to add a passed value as a new element into the vector and later re-assign it to the  lambda expression that print all passed values.

Checking the condition requires passing a predicate. Now we are not limited in the choice of tools regarding what this predicate must be, and std::function gives us additional flexibility here.

Firstly, define a functor named Predicator that will store a border of ranges in its private fields and return result to check its operator().

Alternatively,  we can declare the predicate as a lambda expression where checking the value passed an  argument, while diapason borders are passed via capture scope. Looks rather natural, doesn’t it? We don’t want to remember border values every time while performing a check for some number. At the same time, we don’t use global variables in an uncontrolled manner.

In this code, you will see how a variable of type

function<bool(int)> predicate


and the assignment of lambda performed. Later we use the ability to assign this variable a functional object. However, we can define a lambda right at the location of calling count_if, if this makes the code visible and the following is done too.

 

#pragma hdrstop

#pragma argsused

#ifdef _WIN32
#include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;

class Adder {
	private: vector<int>* _vec;
	public: void operator()(int val)
	{
		_vec->push_back(val);
		cout << val << " inserted" << endl;
	}
	public: Adder(vector<int>& vec) { _vec = &vec; };
};

class Predicator {
	private:
		int _a;
		int _b;
	public:
	bool operator()(int n)
	{
		return (_a <= n) && (n < _b);
	}
	Predicator(int a, int b)
	{
		_a = a;
		_b = b;
	}
};



typedef void (*prfn)(int value);
prfn printfn = [](int value){ cout << value << " "; };



 int _tmain(int argc, _TCHAR* argv[])
 {
	vector<int> v;
	int m;
	cout << "Enter array size: ";
	cin >> m;


	Adder add(v);
	function<void(int)> prn = printfn;

	function<void(int)> operation;



	operation = add;
	for (int val = 0; val < m; val++)
	{
		operation(val); /*add(val);*/
	}

	operation = prn;
	cout << "Content of array: ";
	for_each(v.begin(), v.end(), operation);  /*prn*/
	cout << endl;;

	int lowerBound = 0, upperBound = 0;
	cout << "Enter the bounds of the range: ";
	cin >> lowerBound >> upperBound;

	cout << "Number of elements in the interval [" << lowerBound << ", " << upperBound << ")" << endl;
	int result;

	//using of lambda-expression
	result = count_if(v.begin(), v.end(),
		[lowerBound, upperBound] (int _n)
		{
			return lowerBound <= _n && _n < upperBound;
		}
	);
	cout << "Calculated with lambda-expression: " << result << endl;

	//using of functor
	Predicator prdobj = Predicator(lowerBound, upperBound);
	result = count_if(v.begin(), v.end(), prdobj);
	cout << "Calculated with functor: " << result << endl;

	//std::function predicate based on the lambda-expression
	function<bool(int)> predicate =  [lowerBound, upperBound] (int _n)
		{
			return lowerBound <= _n && _n < upperBound;
		}
	;
	result = count_if(v.begin(), v.end(), predicate);
	cout << "Calculated with std::function predicate based on the lambda-expression: " << result << endl;

	//std::function predicate based on the functional object
	predicate =  prdobj;
	result = count_if(v.begin(), v.end(), predicate);
	cout << "Calculated with std::function predicate based on the functional object: " << result << endl;

	cin.ignore(2);
	return EXIT_SUCCESS;

 }

 

 

 

 It is possible that these are far-fetched examples and you are not very impressed. That said, there is a case where it's not easy to do without using std::function.

What makes functional programming functional is that a function can return a function, and does so in many cases. Likewise, a lambda can generate a lambda. In addition, the role of closures, of course, is not to make code more concise although for imperative programming this is a serious argument.

Each lambda function has some context at the time of its call. In the body of a lambda, we have access to some variables of the calling code, accordingly to its capture-list. With the help of these variables we can define a new lambda function and return it as a result. After that, the calling code section can exit the scope, but the generated lambda function continues to live its life and can be called at any time!

At the same time, the variables that are “closed” in this way must be available all this time. Even after we forget about the origin of our lambda function! There are interesting effects, which can be very specific for each language that supports closures.

Let's try to solve the well-known problem of computing the number of elements of a vector that belong to a given interval using lambdas, but we will try to do it without global variables.

After the familiar code responsible for initializing the vector, we are faced with the definition of the lambda function:

auto lambdagen = [](bool including)->function<bool(int)>

 

This is exactly the definition that we could not make previously when we considered the possibility of generating a lambda function as a result! Note that the auto keyword here doesn’t define the type of the result of the lambda function, but the type of the variable that will store the reference to such a function. At the same time the lambda function will return a variable of a new type for us - function<bool(int)> and this type is the required predicate type!

Next, in the body of the lambdagen function we declare lowerBound  and upperBound variables which represent the borders of the interval. Note, that they are local variables inside the body of the lambda-function only!

It’s assumed here that including the parameter of the lambdagen  allows us to interpret the interval type as closed  [lowerBound, upperBound] when it’s included and as open ]lowerBound, upperBound[ otherwise.

Our goal is that our lambda is able to generate another lambda accordingly to the options which could be used as std::count_if predicate:

return [lowerBound, upperBound, including](int val)->bool { ... }

You have already learned how to use the capture list, and you will not be surprised at the use of variables in the formula for calculating the value of the predicate:

((lowerBound < val)&&(val < upperBound))||(including && (val == lowerBound || val == upperBound))

What happens after we assign the result of the generated lambda function to an external predicate variable?

predicate = lambdagen(false);

lambdagen already returned  its result and generated a lambda assigned to the predicate variable. In a functional language Haskell, we are dealing with currying and lazy execution, and it was not anything extraordinary. Here, however, we are dealing with C++ where the instructions are executed strictly sequentially. Thus,  lambdagen internal scope no longer exists! What do you think, what variables will appear in this formula after the call:

result = count_if(v.begin(), v.end(), predicate);

It's amazing, but it works without error! The function is dead, but some of its local variables are still alive! This is called capturing (I would call these “ghost variables” - although Philip van der Decken  was not a programmer, ha-ha!)

Incidentally, the closure allowed us to keep these ghost variables in the ghost state of the ghost object. Within the framework of functional programming, closures allow for simulating the passing of an internal state for subsequent processing.

Note that we actually have a parameterized generation of the lambda function. So we can receive a predicate for the closed interval case:  

predicate = lambdagen(true);

Do not be offended if you have to enter the limits of the range twice—this is inevitable—because they are entered inside the generated lambda every time it’s called.

#pragma hdrstop
#pragma argsused

#ifdef _WIN32
#include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>

using namespace std;


 int _tmain(int argc, _TCHAR* argv[])
{
	int m;

	cout << "Enter array size: ";
	cin >> m;
	vector<int> v(m);
	int k = 0;



	generate(v.begin(), v.end(), [&](){return k++;});

	cout << "Content of array: ";
	for_each(v.begin(), v.end(), [](int value){ cout << value << " "; });
	cout << endl;



	function<bool(int)> predicate;

	auto lambdagen =
		[](bool including)->function<bool(int)>
		{
			int lowerBound = 0, upperBound = 0;
			cout << "Enter the bounds of the range: ";
			cin >> lowerBound >> upperBound;
			return [lowerBound, upperBound, including](int val)->bool
			{
				return ((lowerBound < val)&&(val < upperBound))||(including && (val == lowerBound || val == upperBound));
			};
		};



	int result;

	predicate = lambdagen(false);
	result = count_if(v.begin(), v.end(), predicate);
	cout << "Number of elements in the open interval: " << result << endl;


	predicate = lambdagen(true);
	result = count_if(v.begin(), v.end(), predicate);
	cout << "Number of elements in the closed interval: " << result << endl;

	cin.ignore(2);
	return EXIT_SUCCESS;
}

C++ Builder __closure keyword

Our presentation could not be considered complete without mention of the keyword __closure, which appeared in Borland C++ Builder at the turn of the century, long before we could even dream of the functional features of C++ in a serious way.

A keyword ahead of its time

A function pointer allows make reference to a global function and call it when necessary. However, for Class member functions (methods) it is not sufficient because two pointers are required: one for the originating object and the second for the method address. There is a need to create "2-in-1" pointers to methods and the __closure keyword allows us perform that task.

 

The Role in the VCL

When building a UI, instead of manually creating each window element, you use a graphical designer and then just write the handler for the event you are interested in. How can this be implemented in practice? Since you use standard window elements, you need to override the behavior of such a component for a particular event, i.e. create its descendant, as it’s done in classic OOP.

Suppose we have 2 buttons. They are two instances of the same TButton class that have a different behaviors. The first one prints “Yes” when pressed, second one prints “No.” In the case of the traditional OOP approach with the absence of delegation, the solution would be to create classes TButtonYes and TButtonNo with a redefined behavior at the click event, then create one instance of each class. This is contrary to our intuition that there is a single class, and that there are the discrepant instances of that class only!

VCL opened up another pathway here offering an elegant solution. Instead of defining behavior in the class for each visual component in your application, just delegate the processing of the relevant event to the interested class. Therefore, the buttons always remain just buttons, regardless of what kind of work the handler of their click performs!

It sounds promising, but how do you implement it in practice if the VCL developer does not know which class will delegate the right to process the click? Note, “pure” C++ only had plain function pointers, not object-method pointers. At the same time the delegate here is the class method and it is the pointer to the class member-function that is required.

Look at the following definition:

typedef void __fastcall (__closure *TNotifyEvent)(System::TObject* Sender);

This is the type of the event notification signature. Sender contains a pointer to the object in which the event occurred (because there are many buttons that can be presented on the form), in order for the delegate to have access to the properties and methods of the object. It represents a kind of feedback while TNotifyEvent is the declared type whose variable can contain a reference to a delegate. Thus, if a visual component has a property of TNotifyEvent type, it can be assigned a reference to a handler, which is a method of the interested class that will be executed as soon as the notification of the event that has occurred is received.

The declaration of the member-function-pointer with the __closure keyword allows to delegate the implementation of the member-function to any arbitrary class, rather than a descendant of a specific one.

Syntax

typedef <type> ( __closure * <id> ) (<param list>);

where

id - the identifier of the pointer to the function-member of some class

Examples

Let's compare what the VCL application would look like with and without __closure. To show this we will create a small demo project. Please, create an empty VCL Forms application as shown:

 

After it put TMemo component on the form.

First, we try to create two buttons which will print “Yes” or “No” when pressed. Our goal is to achieve this without using VCL event mechanisms (onClick property).

Nevertheless, we do not need to implement self-handling messages from the mouse.  We have already a parent class TButton in our hands with implemented dynamic Click() method which called every time when left mouse key pressed. Normally, it perform some additional actions and call handler assigned to TButton::onClick property.  But taking into account our obligations, we can override his standard behavior for each of the required cases (printing “Yes” and printing “No”) .

So we had to create two separate classes TButtonYes and TButtonNo with behavior accordingly to our task:

class TButtonYes : public TButton{

public: virtual __fastcall  TButtonYes(TComponent* Owner) : TButton(Owner)

{

Caption = L"Yes";

}

 

void __fastcall printYes()

{

((TForm1*)(GetParentForm(this, true)))->Memo1->Lines->Add(L"Yes"); // this->Parent

 

}

 

DYNAMIC void __fastcall Click(void)

{

printYes();

}

};

 

class TButtonNo : public TButton{

public: virtual __fastcall  TButtonNo(TComponent* Owner) : TButton(Owner)

{

Caption = L"No";

}

 

void __fastcall printNo()

{

((TForm1*)(GetParentForm(this, true)))->Memo1->Lines->Add(L"No");

 

}

DYNAMIC void __fastcall Click(void)

{

printNo();

}

};

As you can see, Click() method is overridden thus to call the member function print.. of the button class for processing instead of passing the execution to the delegate specified in the onClick property as doing by default. In addition, the size and location of the each button on the TForm1 form are described here, since we will create it dynamically at run-time.

Now we can declare pointers to these two buttons objects:

TButton *ButtonYes;

TButton *ButtonNo;

Next can double-click in the main form and put followed code in the constructor of the TForm1:

ButtonYes = new TButtonYes(this);

ButtonNo = new TButtonNo(this);

and (remember, our buttons are created in runtime!) determine the place that these components will occupy on the form:

ButtonYes->Top = 48;

ButtonYes->Left = 8;

ButtonYes->Parent = this;

ButtonNo->Top = 48;

ButtonNo->Left = 88;

ButtonNo->Parent = this;

 

Finally, you can run the application now and see the results.

Again: we did what we had to do within the framework of the concept of "pure" OOP, without resorting to the use of delegation. Quite a lot of code for the task of creating just two different buttons, isn’t it?

But You can use the OnClick property in a much more convenient way and __closure keyword allows for it. You can create new project, but to feel the difference let's continue working with this project.

Keep in mind! The following example may seem confusing if you just read it. But in order to understand how it works it will only need to compile it and try to click on the buttons. Our goal now is to demonstrate that the __closure keyword makes it easy to juggle with ease button handlers in runtime.

Suppose that we have two buttons located on the surface of our form. Each button click has its own handler. This handler will write an asterisk on the surface of the button, and will assign a special procedure as a handler of this button click (instead of himself).

This special procedure (implemented in a separate class) will compare the assigned button handlers and exchange them in places, but in the case where both buttons have the same handler (this exchange is meaningless), this procedure will return the assigned handlers to their original state.

Signatures on the surface of buttons are initialized by their names, this is done for better remembering by the user who launched the program for the first time, but does not press anything. These names change during operation and do not return to their original state but they receive the "Yes" and "No" captions.

Place two TButton’s onto the form (not at the same place where ButtonYes and ButtonNo appear, if you are continue previous example) and from the Events tab double-click on the ‘OnClick’ property field. Thus, TForm1::Button1Click and TForm1::Button2Click handlers templates will be created.

Type the following code for this handlers:

void __fastcall TForm1::Button1Click(TObject *Sender)

{

Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");

Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"

+L"\t Handler: ''TForm1::Button1Click''");

 

((TButton*) Sender)->OnClick = &delegate.ExternalClickHandler;

((TButton*) Sender)->Caption = L"*";

Form1->Memo1->Lines->Add(((TButton*) Sender)->Name+L"->OnClick property was now assigned to external handler");

Form1->Memo1->Lines->Add(L"----------------------------------------------------");

}



and

 

void __fastcall TForm1::Button2Click(TObject *Sender)

{

Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");

Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"

+L"\t Handler: ''TForm1::Button2Click''");



((TButton*) Sender)->OnClick = &delegate.ExternalClickHandler;

((TButton*) Sender)->Caption = L"*";

Form1->Memo1->Lines->Add(((TButton*) Sender)->Name+L"->OnClick property was now assigned to external handler");

Form1->Memo1->Lines->Add(L"----------------------------------------------------");

}

If you open the .dfm file now you can right-click on the form and select “View as Text” or save project changes and open .dfm in any text viewer. You should see something like the following:

object Button1: TButton

   Left = 8

   Top = 16

...

   OnClick = Button1Click

 end

 object Button2: TButton

   Left = 104

   Top = 16

   ...

   OnClick = Button2Click

 end

You can see that the OnClick handler is assigned to the TForm1 method automatically and it’s much easy now to create a derived class of button and override its behavior, isn’t it? But don’t be confused that you can only use VCL component methods as handlers. Let's create our own class, whose method can act as a delegate:

class Delegator{

public:

void _fastcall ExternalClickHandler(TObject *Sender)

{

Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");

Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"

+L"\t Handler: ''Delegator::ExternalClickHandler''");

 

if  (Form1->Button1->OnClick == Form1->Button2->OnClick)

{

Form1->Memo1->Lines->Add(L"Restore click handlers...");

 

Form1->Button1->OnClick = Form1->Button1Click;

Form1->Button2->OnClick = Form1->Button2Click;

 

Form1->Button1->Caption = L"YES";

Form1->Button2->Caption = L"NO";

 

Form1->Memo1->Lines->Add(L"From Delegator: OnClick properties was restored to default Form handlers");

}

else

{

Form1->Memo1->Lines->Add(L"Exchange click handlers...");

 

TNotifyEvent event;

event =  Form1->Button1->OnClick;

Form1->Button1->OnClick = Form1->Button2->OnClick;

Form1->Button2->OnClick = event;

 

UnicodeString buf = Form1->Button1->Caption;

Form1->Button1->Caption = Form1->Button2->Caption;

Form1->Button2->Caption = buf;

}

 

Form1->Memo1->Lines->Add(L"----------------------------------------------------");

}

};

 

and declare its instance:

Delegator delegate;

Our handlers operate with pointers to delegates in a completely arbitrary style. Let's try to understand the functionality of this code.

We have two handlers TForm1::Button1Click and TForm1::Button2Click which acts likely way. But notice that matching the names of the handlers to the names of the components whose events they process are not necessarily! Generally speaking, this restriction is dictated only by common sense, but if necessary we can manipulate it arbitrarily.

First, prints to the log  the caption of the button that was pressed. Second, prints  the Name of the button - this is the only thing that always remains in place. Third, external handler assigns to the button onClick property and finally button caption changes to the “*” symbol.

Now a few words about the external handler. It is a ExternalClickHandler method of the Delegator class. When called it prints  the caption of the button that was pressed into the log too. Next it compare the handlers of the buttons Button1::OnClick and Button2::OnClick both. If it is the same handler (i.e. ExternalClickHandler because it is not called otherway) then both handlers was changed from initial and it restores the init values and captions. Else one button has external handler for onClick property and ExternalClickHandler exchange handlers (and captions) of the Button1::OnClick and Button2::OnClick.

In a sense, this task resembles the next chain of states:

Each state includes the values of the caption (signed on the button surface) and handler (in the rectangle from below) for each of the buttons Button1 (on the left) and Button2 (on the right). For compactness the handlers TForm1::Button1Click and TForm1::Button2Click are signed as Button1Click and Button2Click respectively, and the Delegator::ExternalClickHandler handler is designated as external.

Note that the chain of states is not closed, and the transitions shown in the following figure are possible from the lower state:


Thus, the second state diagram can be viewed as a continuation of the first, but if you initialize the Button1 and Button2 button captions as "YES" and "NO" respectively, the top diagram will turn into the bottom one. You can do this by changing the Caption property of both buttons at the design stage, or at runtime in the TForm1 constructor. I saved the default button names in order to remember the location of the components TForm1::Button1 and TForm1::Button2 (but note that this values can be exchanges and in some states Button1 has caption “Button2”).

It's not so difficult to understand if you play with this program yourself.

Now we can try to reproduce the following log:

 

Yes

No

========== Button1 click ==========

Sender: ''Button1'' Handler: ''TForm1::Button1Click''

Button1->OnClick property was now assigned to external handler

----------------------------------------------------

========== * click ==========

Sender: ''Button1'' Handler: ''Delegator::ExternalClickHandler''

Exchange click handlers...

----------------------------------------------------

========== Button2 click ==========

Sender: ''Button1'' Handler: ''TForm1::Button2Click''

Button1->OnClick property was now assigned to external handler

----------------------------------------------------

========== * click ==========

Sender: ''Button2'' Handler: ''Delegator::ExternalClickHandler''

Restore click handlers...

From Delegator: OnClick properties was restored to default Form handlers

----------------------------------------------------

========== NO click ==========

Sender: ''Button2'' Handler: ''TForm1::Button2Click''

Button2->OnClick property was now assigned to external handler

----------------------------------------------------

========== * click ==========

Sender: ''Button2'' Handler: ''Delegator::ExternalClickHandler''

Exchange click handlers...

----------------------------------------------------

========== YES click ==========

Sender: ''Button2'' Handler: ''TForm1::Button1Click''

Button2->OnClick property was now assigned to external handler

----------------------------------------------------

========== * click ==========

Sender: ''Button2'' Handler: ''Delegator::ExternalClickHandler''

Restore click handlers...

From Delegator: OnClick properties was restored to default Form handlers

----------------------------------------------------

 

First, we clicked created at run-time “Yes” and “No” buttons for which we has implemented the  different behaviors using inheritance  instead delegation mechanism, as you remember. Next, we can press a sequence of buttons corresponding to one of the paths in the state graph.

After it the main form of our application will looks as follows:

 I'm forced to bring here the contents of the header file: this way in case something goes wrong - so that you could understand the cause of the problem.

Unit1.h:

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

#ifndef Unit1H
#define 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
	TMemo *Memo1;
	TButton *Button1;
	TButton *Button2;
	void __fastcall Button1Click(TObject *Sender);
	void __fastcall Button2Click(TObject *Sender);
private:	// User declarations
public:		// User declarations
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

 

The full content of the Unit1.cpp source is:

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

#include <vcl.h>
#pragma hdrstop

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

class TButtonYes : public TButton{
	public: virtual __fastcall  TButtonYes(TComponent* Owner) : TButton(Owner)
	{
		Caption = L"Yes";
	}

	 void __fastcall printYes()
	{
		((TForm1*)(GetParentForm(this, true)))->Memo1->Lines->Add(L"Yes");

	}

	DYNAMIC void __fastcall Click(void)
	{
		printYes();
	}
};

class TButtonNo : public TButton{
	public: virtual __fastcall  TButtonNo(TComponent* Owner) : TButton(Owner)
	{
		Caption = L"No";
	}

	 void __fastcall printNo()
	{
		((TForm1*)(GetParentForm(this, true)))->Memo1->Lines->Add(L"No");

	}
	DYNAMIC void __fastcall Click(void)
	{
		printNo();
	}
};

TButton *ButtonYes;
TButton *ButtonNo;
//----------------------------------------------------------------------
class Delegator{
	public:
	void _fastcall ExternalClickHandler(TObject *Sender)
	{
		Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");
		Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"
								+L"\t Handler: ''Delegator::ExternalClickHandler''");

		if  (Form1->Button1->OnClick == Form1->Button2->OnClick)
		{
			Form1->Memo1->Lines->Add(L"Restore click handlers...");

			Form1->Button1->OnClick = Form1->Button1Click;
			Form1->Button2->OnClick = Form1->Button2Click;

			Form1->Button1->Caption = L"YES";
			Form1->Button2->Caption = L"NO";

			Form1->Memo1->Lines->Add(L"From Delegator: OnClick properties was restored to default Form handlers");
		}
		else
		{
			Form1->Memo1->Lines->Add(L"Exchange click handlers...");

			TNotifyEvent event;
			event =  Form1->Button1->OnClick;
			Form1->Button1->OnClick = Form1->Button2->OnClick;
			Form1->Button2->OnClick = event;

			UnicodeString buf = Form1->Button1->Caption;
			Form1->Button1->Caption = Form1->Button2->Caption;
			Form1->Button2->Caption = buf;
		}

		Form1->Memo1->Lines->Add(L"----------------------------------------------------");
	}
};

Delegator delegate;


//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	ButtonYes = new TButtonYes(this);
	ButtonYes->Top = 48;
	ButtonYes->Left = 8;
	ButtonYes->Parent = this;//!(TForm1*)(Owner);

	ButtonNo = new TButtonNo(this);
	ButtonNo->Top = 48;
	ButtonNo->Left = 88;
	ButtonNo->Parent = this;//!(TForm1*)(Owner);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");
	Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"
								+L"\t Handler: ''TForm1::Button1Click''");

	((TButton*) Sender)->OnClick = &delegate.ExternalClickHandler;
	((TButton*) Sender)->Caption = L"*";
	Form1->Memo1->Lines->Add(((TButton*) Sender)->Name+L"->OnClick property was now assigned to external handler");
	Form1->Memo1->Lines->Add(L"----------------------------------------------------");
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
	Form1->Memo1->Lines->Add(L"========== "+((TButton*) Sender)->Caption + L" click ==========");
	Form1->Memo1->Lines->Add(L"Sender: ''"+((TButton*) Sender)->Name+L"''"
								+L"\t Handler: ''TForm1::Button2Click''");


	((TButton*) Sender)->OnClick = &delegate.ExternalClickHandler;
	((TButton*) Sender)->Caption = L"*";
	Form1->Memo1->Lines->Add(((TButton*) Sender)->Name+L"->OnClick property was now assigned to external handler");
	Form1->Memo1->Lines->Add(L"----------------------------------------------------");
}
//---------------------------------------------------------------------------

 In addition, you can compare the resulting file of your form with the following:

object Form1: TForm1
  Left = 0
  Top = 0
  BorderStyle = bsSingle
  Caption = 'Form1'
  ClientHeight = 498
  ClientWidth = 603
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 120
  TextHeight = 16
  object Memo1: TMemo
    Left = 181
    Top = 0
    Width = 422
    Height = 498
    Align = alRight
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -10
    Font.Name = 'Tahoma'
    Font.Style = []
    Lines.Strings = (
      '')
    ParentFont = False
    ScrollBars = ssVertical
    TabOrder = 0
  end
  object Button1: TButton
    Left = 8
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Button1'
    TabOrder = 1
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 88
    Top = 8
    Width = 75
    Height = 25
    Caption = 'Button2'
    TabOrder = 2
    OnClick = Button2Click
  end
end

 

After experimenting with this code, you will not think about VCL event properties as something mysterious. Despite that, it still may not obvious what role the __closure mechanism plays here since it is hidden inside the TNotifyEvent type definition. Perhaps its place is only inside VCL?

Let's assume that we again need to count the number of elements of a vector in a certain range. We have a hierarchy of classes representing the base interval Diapasoner, subtypes of this interval such as open OpenInterval, and closed ClosedInterval.

The Diapasoner class has a virtual CheckCondition member-function which always returns true and must be overridden in derived classes.

 

How can I use its  member-function as predicate in the std::count_if algorithm?

We can try to assign a method address to a pointer to a global function, but this does not work of course:

bool (*predicate)(int);//predicate is a pointer to a global function

// predicate = &Diapasoner::CheckCondition;

// [bcc32c Error] File1.cpp(89): assigning to 'bool (*)(int)' from incompatible type 'bool (Diapasoner::*)(int)'

Next, we can create an object of the Diapasoner type and use its trivially defined CheckCondition  method:

bool (Diapasoner::*conditfun)(int); //conditfun is a member-function pointer

conditfun = &Diapasoner::CheckCondition;

This type of pointer can be used for subclasses:

intervalObj = new ClosedInterval(lowerBound, upperBound);

conditfun = &Diapasoner::CheckCondition;

We cannot use this variable to point to member-functions declared in subclasses or in third-party classes:

conditfun = &ClosedInterval::CheckCondition;

compile-time error raised: “assigning to 'bool (Diapasoner::*)(int)' from incompatible type 'bool (ClosedInterval::*)(int)': different classes ('Diapasoner' vs 'ClosedInterval')

OR

conditfun = &ClosedInterval::inClosed;

failed too due Diapasoner class have no inClosed method so conditfun cannot to point to it;

OR

bool (ClosedInterval::*conditfun_)(int); //declare conditfun_ as a member-function pointer to methods of the ClosedInterval class

...

conditfun_ = &OpenInterval::CheckCondition;

compile-time error raised: “assigning to 'bool (ClosedInterval::*)(int)' from incompatible type 'bool (OpenInterval::*)(int)': different classes ('ClosedInterval' vs 'OpenInterval')

Naturally, all these methods did not work, because we must monitor not only the coincidence of the method call signature but also the compatibility of the classes to which these methods belong. I.e. the child-class possesses the necessary information about its ancestor, however, it can not know anything about the internal arrangement of its descendants, brothers or even more unrelated classes.

 

But, perhaps, I can use a pointer to the member function directly in the STL call? All I need is to have a declared pointer to the member function of my class

Unfortunately, everything turned out to be different from the ideal world. When I try to compile

result = count_if(v.begin(), v.end(), intervalObj->*conditfun );

I receive a rather strange "internal compiler error." I did not come up with an exit better than using a ordinary loop for counting:

result = 0;

for (int val: v)

{

(intervalObj->*conditfun)(val) ? result++ : result=result;

}

 

I want to show how __closure offers us a more common solution: it is type-compatible based on the method signature not the class type - unlike, say, std::bind. In fact, why think about the type of object if all I want to focus on its member function? It would be cool, if in some cases we could work on the method, not on the class type, which is how it can work as a delegate.

Let’s declare the next variable:

bool (__closure *predicateX)(int value);

 

Now we can assign to it the method of any class, but only if  this method has the bool (int value) call signature:

predicateX = intervalObj->CheckCondition;

and in another place later reassign predicateX variable:

interval0Obj = (OpenInterval*)intervalObj;

predicateX = interval0Obj->inHalfOpenLeft;

 

And, of course, you are free to use it in std::algorithm

result = count_if(v.begin(), v.end(), predicateX);

 

The trick is that the predicateX variable now contains the pair (&intervalObj, &CheckCondition), so it's enough data to recover the member-function within their object inside count_if.

 

Note, if this statement is taken out of context you can not determine from the object which method will be called here. This is not a std::function, but without going beyond the boundaries of the OOP it provides the flexibility: you can save a single pointer to the class method along with the class itself, which saves the headache of determining a specific pointer for each class.

#pragma hdrstop
#include <iostream>
#include <vector>
#include <algorithm>
#pragma argsused

#ifdef _WIN32
#include <tchar.h>
#else
  typedef char _TCHAR;
  #define _tmain main
#endif

using namespace std;


class Diapasoner
{
	protected:
		int _a;
		int _b;
	public:
		virtual bool CheckCondition(int n) { return true; };
		Diapasoner(int a, int b)
		{
			_a = a;
			_b = b;
		}
};


class ClosedInterval : public Diapasoner{
	public: ClosedInterval (int a, int b)  : Diapasoner(a, b) {}
		virtual bool CheckCondition(int n)
		{
			return inClosed(n);
		}

		bool inClosed(int n)
		{
			return (_a <= n) && (n <= _b);
		}

};

class OpenInterval : public Diapasoner{
	public: OpenInterval (int a, int b)  : Diapasoner(a, b) {}

		virtual bool CheckCondition(int n)
		{
			return  inOpen(n);
		}
		bool inOpen(int n)
		{
			return (_a < n) && (n < _b);
		}

		bool inHalfOpenRight(int n)
		{
			return (_a <= n) && (n < _b);
		}
		bool inHalfOpenLeft(int n)
		{
			return (_a < n) && (n <= _b);
		}
};

 int _tmain(int argc, _TCHAR* argv[])
 {

	int m;
	cout << "Enter array size: ";
	cin >> m;
	vector<int> v;

	for (int val = 0; val < m; v.push_back(val++));

	cout << "Received array: ";
	for_each(v.begin(), v.end(), [v](int value){ cout << value << " ";});
	cout << endl;


	int lowerBound = 0, upperBound = 0;
	cout << "\nEnter the borders of the range: ";
	cin >> lowerBound >> upperBound;
    cout << endl;
	int result = 0;

	bool (*predicate)(int);
//	predicate = &Diapasoner::CheckCondition;
// [bcc32c Error] File1.cpp(83): assigning to 'bool (*)(int)' from incompatible type 'bool (Diapasoner::*)(int)'

	bool (Diapasoner::*conditfun)(int);
	conditfun = &Diapasoner::CheckCondition;


	Diapasoner *intervalObj = new Diapasoner(lowerBound, upperBound);

	result = 0;
	for (int val: v)
	{
		(intervalObj->*conditfun)(val) ? result++ : result=result;
	}

	cout << "Number of elements in diapason " << lowerBound << ".." << upperBound << " and outside" << endl;
	cout << "Calculated with base class member-function pointer: " << result << endl;
	cout << endl;
	delete intervalObj;
 //------------------------------------------------------------
	intervalObj = new ClosedInterval(lowerBound, upperBound);
	conditfun = &Diapasoner::CheckCondition;
	result = 0;
	for (int val: v)
	{
		(intervalObj->*conditfun)(val) ? result++ : result=result;
	}

	cout << "Number of elements in diapason [" << lowerBound << ", " << upperBound << "] and outside " << endl;
	cout << "Calculated with derived class overrided member-function pointer: " << result << endl;
	cout << endl;
	delete intervalObj;
 //------------------------------------------------------------
 // try...
	intervalObj = new ClosedInterval(lowerBound, upperBound);
//	conditfun = &ClosedInterval::CheckCondition;
// [bcc32c Error] File1.cpp(115): assigning to 'bool (Diapasoner::*)(int)' from incompatible type 'bool (ClosedInterval::*)(int)': different classes ('Diapasoner' vs 'ClosedInterval')

//	conditfun = &ClosedInterval::inClosed;

	ClosedInterval* interval_Obj = new ClosedInterval(lowerBound, upperBound);
	bool (ClosedInterval::*conditfun_)(int);
	conditfun_ = &ClosedInterval::CheckCondition;
	result = 0;
	for (int val: v)
	{
		(interval_Obj->*conditfun_)(val) ? result++ : result=result;
	}

	cout << "Number of elements in diapason [" << lowerBound << ", " << upperBound << "]" << endl;
	cout << "Calculated with ClosedInterval class member-function pointer: " << result << endl;
	cout << endl;
	delete  interval_Obj;
//---------------------------------------------------

//try...
	OpenInterval* interval0Obj = new OpenInterval(lowerBound, upperBound);
//	conditfun_ = &OpenInterval::CheckCondition;
//[bcc32c Error] File1.cpp(137): assigning to 'bool (ClosedInterval::*)(int)' from incompatible type 'bool (OpenInterval::*)(int)': different classes ('ClosedInterval' vs 'OpenInterval')

//----------------------------------------------------
	bool (__closure *predicateX)(int value);


	intervalObj = new Diapasoner(lowerBound, upperBound);
	predicateX = intervalObj->CheckCondition;
	result = 0;
	for (int val: v)
	{
		predicateX(val) ? result++ : result=result;
	}
	cout << "Number of elements in diapason " << lowerBound << ".." << upperBound << " and outside" << endl;
	cout << "Calculated for base Diapasoner object with predicateX pointer (trivial): " << result << endl;
	cout << endl;
	delete intervalObj;

	intervalObj = new ClosedInterval(lowerBound, upperBound);


	predicateX = intervalObj->CheckCondition;
	result = 0;
	for (int val: v)
	{
		predicateX(val) ? result++ : result=result;
	}
	cout << "Number of elements in diapason [" << lowerBound << ", " << upperBound << "]" << endl;
	cout << "Calculated for ClosedInterval object with predicateX pointer: " << result << endl;
	cout << endl;
	delete intervalObj;

	intervalObj = new OpenInterval(lowerBound, upperBound);
	predicateX = intervalObj->CheckCondition;
	result = 0;
	for (int val: v)
	{
		predicateX(val) ? result++ : result=result;
	}
	cout << "Number of elements in diapason (" << lowerBound << ", " << upperBound << ")" << endl;
	cout << "Calculated for OpenInterval object with predicateX pointer: " << result << endl;
	cout << endl;

	interval0Obj = (OpenInterval*)intervalObj;
	predicateX = interval0Obj->inHalfOpenLeft;
	result = count_if(v.begin(), v.end(), predicateX);

	cout << "Number of elements in half-open diapason (" << lowerBound << ", " << upperBound << "]" << endl;
	cout << "Calculated in count_if for OpenInterval class with predicateX pointer: " << result << endl;

	predicateX = interval0Obj->inHalfOpenRight;
	result = count_if(v.begin(), v.end(), predicateX);

	cout << "Number of elements in half-open diapason [" << lowerBound << ", " << upperBound << ")" << endl;
	cout << "Calculated in count_if for OpenInterval class with predicateX pointer: " << result << endl;
	cout << endl;

	delete intervalObj;

	std::cin.ignore(2);
	return EXIT_SUCCESS;

 }



 

Perhaps, the presentation of this material seemed somewhat vague to you, and examples were far-fetched. Indeed, you can use VCL, and without even thinking about the details of the implementation of TNotifyEvent , and for storing of the function-members, we now have std::function. Nevertheless, if you want to feel the essence of the problem of working with pointers to class methods, I recommend you read Mohammad Nasim’s article where this material is presented very talently and succinctly:  “C++ Delegates and Borland's C++ Builder Event Handling” -- Part I and Part II.

 

Fun fact: Borland was forced to use a functional style approach in C++Builder VCL by introducing the use of a __closure keyword to create the infrastructure of a classical object-oriented language (such as C++) many years before the functional elements were included in standard! Something similar (in conceptual sense) is happening now with the possibility of using functors and lambda expressions together with the algorithms of STL. This suggests that although you can never write programs purely in the functional paradigm using C++ (because it’s an imperative language and not intended for such a thing) functional elements can enhance the capabilities of object-oriented languages and embellish them.

Today it gives us a powerful tool for manipulating member-functions to care only about the correspondence of their signatures, and not their owner classes. Nevertheless, in modern C ++, there are mechanisms for manipulating the signature of the call, just as in the functional paradigm the function itself is an object of influence, and soon we will see it.


Video Tutorial #2/#3: CodeSite Express / Beyond Compare

$
0
0

Zwei weitere Videos aus meiner Video-Tipp-Reihe:


[YoutubeButton url='https://www.youtube.com/watch?v=EgZLt5l0mHM']

[YoutubeButton url='https://www.youtube.com/watch?v=QbkuOluQw2k']

Wi-Fi management from applications using C++Builder

$
0
0

Using C++Builder 10.2 Tokyo, explain how to switch Wi-Fi on Android.

Manage Wi-Fi switching using JWifiManager

I use di_JWifiManager which wrapped WifiManager.
di_JWifiManager is the Delphi interface.
Set the variable. _di_JWifiManager f_WifiManager; use it like this.

Required headers

Header file for using WifiManager.

#include <Androidapi.JNI.Net.hpp>
#include <Androidapi.Helpers.hpp>
#include <Androidapi.JNI.GraphicsContentViewText.hpp>
#include <Androidapi.JNIBridge.hpp>

Display design

It is a design for displaying on Android.


TEditTSwitchTTimerTLabel, was placed.

 

When the main form creation

Create _di_JWifiManager using TJWifiManager.

//---------------------------------------------------------------------------
void __fastcall Tfm_main_wifistatus::FormCreate(TObject *Sender)
{
    //Form creation.Using TAndroidHelper, get the WIFI_SERVICE.
    _di_JObject obj = TAndroidHelper::Activity->getSystemService(TJContext::JavaClass->WIFI_SERVICE);
    if (obj != nullptr)
    {
        //Wrap to TJWifiManager.
        f_WifiManager = TJWifiManager::Wrap(_di_ILocalObject(obj)->GetObjectID());
        if (f_WifiManager != nullptr)
        {
            Timer1->Enabled = true;
        }
    }
}

Monitor Wi-Fi status at Timer1 event.

void __fastcall Tfm_main_wifistatus::Timer1Timer(TObject *Sender)
{
    //Use a timer event to monitor the Wi-Fi state.
    //Write state change to Edit1->Text. and It also reflects Switch1->IsChecked.
    Timer1->Enabled = false;
    if (f_WifiManager != nullptr)
    {
        Switch1->IsChecked = f_WifiManager->isWifiEnabled();
        UnicodeString wifistr;
        (Switch1->IsChecked)?wifistr = "true": wifistr = "false";
        Edit1->Text = "f_WifiManager->isWifiEnabled() = " + wifistr;
    }
    Timer1->Enabled = true;
}

When you tap the Switch1.

Change the Wi-Fi status when tapping the Switch1.
This uses the setWifiEnabled() function.

void __fastcall Tfm_main_wifistatus::Switch1Switch(TObject *Sender)
{
    //This is a Switch1 change event.
    Timer1->Enabled = false;
    //Set the value of Switch1->IsChecked to setWifiEnabled()
    f_WifiManager->setWifiEnabled(Switch1->IsChecked);
    TThread::CreateAnonymousThread([this]()
    {
        sleep(1);
        TThread::Synchronize(TThread::CurrentThread, [this]()
        {
            Timer1->Enabled = true;
        });
    })->Start();
}

 

https://github.com/mojeld/cpp_builder_firemonkey_wifi

 

New in 10.2.1: Debug visualisers for Delphi generics

$
0
0

Debug visualisers are a type of IDE plugin that allows you to change the display of a variable in the various debug windows (Local Variables, Watches, Inspector, and Evaluate/Modify.) For example, the TDateTime visualiser takes the double value that represents time and instead displays that time converted to a string. You register a debug visualiser for a type, so all variables of that type, and optionally descendants of that type, go through your visualiser.

In previous versions, this type was specified by a plain string, such as 'TComponent', and there was no way to handle a generic type. If you registered 'MyGeneric<T>', the visualiser would never be called, because the concrete instantiations of that type do not use T - they might be 'MyGeneric<Integer>', 'MyGeneric<TButton>', and so forth.

In 10.2.1, we have introduced support for registering a visualiser for a generic type. Your visualizer can implement IOTADebuggerVisualizer250 as well as the prior IOTADebuggerVisualizer, where the GetSupportedType method allows you to specify that the type string is a generic:

 

.
  IOTADebuggerVisualizer250 = interface(IOTADebuggerVisualizer)
    ['{DC0C8D82-B783-4205-B3F4-D325BA8B3EEB}']
    { Return the Index'd Type.  TypeName is the type.  AllDescendants indicates
      whether or not types descending from this type should use this visualizer
      as well. IsGeneric indicates whether this type is a generic type. }
    procedure GetSupportedType(Index: Integer; var TypeName: string;
      var AllDescendants: Boolean; var IsGeneric: Boolean); overload;
  end;

This means you can register for MyGeneric<T> and your visualiser will be called for all MyGeneric<>s. This is all generic types, ie interfaces as well as classes. 

One note is that we do not yet support registering for descendants of a generic type, meaning that if you have MyDesc<T> = class(MyGeneric<T>) or MyDesc = class(MyGeneric<T>), you need to register a visualiser for MyDesc separately. This is because of some complexities in the internal evaluator.

Generics are widely used, especially for collections like dictionaries and lists, and in third-party libraries like Spring4D. We hope you will find visualiser support for generics useful!

Update: here is a code snippet demonstrating a template visualizer

To get the NetworkInfo using the ConnectivityManager of Android

$
0
0

 

Using ConnectivityManager with C++Builder

With C++Builder 10.2 Tokyo Android ConnectivityManager class is available.
Use the ConnectivityManager, you can get NetworkInfo
NetworkInfo see various network information.
inside that, The getType() function is Reports the type of network.
The getType() function return is int.

int type
0x00000000 TYPE_MOBILE
0x00000001 TYPE_WIFI
0x00000006 TYPE_WIMAX
0x00000009 TYPE_ETHERNET
0x00000007 TYPE_BLUETOOTH

I tried ways to get NetworkInfo.

Declare _di_JConnectivityManager variable.

_di_JConnectivityManager is the ConnectivityManager class interface.

 _di_JConnectivityManager    f_ConnectivityManager;

It creates to use '_di_JConnectivityManager'.

template <typename T1, typename T2> void __fastcall Tfm_main_wifistatus::getService(_di_JObject obj, T1& iobj)
{
    if (obj != nullptr)
    {
        iobj = T2::Wrap(_di_ILocalObject(obj)->GetObjectID());
    }
}
void __fastcall Tfm_main_wifistatus::FormCreate(TObject *Sender)
{
    //Form creation.Using TAndroidHelper, get the CONNECTIVITY_SERVICE.
    getService<_di_JConnectivityManager, TJConnectivityManager>(
        TAndroidHelper::Context->getSystemService(TJContext::JavaClass->CONNECTIVITY_SERVICE), f_ConnectivityManager);
}

Get the _di_JNetworkInfo using the getActiveNetworkInfo() function.

//TJConnectivityManager::JavaClass->TYPE_WIFI;
#define TYPE_WIFI 0x00000001
//TJConnectivityManager::JavaClass->TYPE_MOBILE;
#define TYPE_MOBILE 0x00000000
//TJConnectivityManager::JavaClass->TYPE_VPN;
#define TYPE_VPN 0x00000011
//TJConnectivityManager::JavaClass->TYPE_WIMAX;
#define TYPE_WIMAX 0x00000006

void __fastcall Tfm_main_wifistatus::Timer1Timer(TObject *Sender)
{
        UnicodeString net_str;
        _di_JNetworkInfo n_info = f_ConnectivityManager->getActiveNetworkInfo();
        if (n_info != nullptr)
        {
            switch (n_info->getType())
            {
            case TYPE_WIFI:
                net_str = L"(TYPE_WIFI)";    break;
            case TYPE_MOBILE:
                net_str = L"(TYPE_MOBILE)";  break;
            case TYPE_VPN:
                net_str = L"(TYPE_VPN)"; break;
            }
        }
        else
            net_str = L"(nullptr)";
}

You can get the status of a network interface.

Save Paradox Blob format to a file using BDE

$
0
0

C++Builder 10.2 Tokyo does not have BDE installed.
So, Install BDE separately in C++Builder 10.2 Tokyo.
It is after the end of the all of the installation.

 

Download BDE Installer for RAD Studio, Delphi, C++Builder 10.2 Tokyo

Download the installer from the URL below.
ID: 30752, BDE Installer for RAD Studio, Delphi, C++Builder 10.2 Tokyo 

 

Check the Paradox data.

Use the sample file named biolife.db.
This is sample data of Paradox.
I brought it from C++Builder 5 sample data.

There is a "Graphic" field in biolife.db. "Graphic" is Blob type.

 

Save the Blob data in the JPEG format using the BDE.

In VCL, JPEG can be processed using TJPEGImage.

#include <Vcl.Imaging.jpeg.hpp>

Use TTable to get all of biolife.db.

//---------------------------------------------------------------------------
void __fastcall TfmMain::bde_biofish_save()
{
    // created a new TTable and set the biolife table.
    std::auto_ptr<TTable> l_table( new TTable(this));
    l_table->DatabaseName    = "DBDEMOS";
    l_table->TableName      = "biolife.db";
    l_table->Active         = true;
    l_table->FindFirst();
    //Loop for acquiring all data.
    while (! l_table->Eof)
    {
        std::tr1::shared_ptr<TJPEGImage> l_jpeg(new TJPEGImage());
        std::tr1::shared_ptr<TMemoryStream> l_ms(new TMemoryStream());

        //Using the CreateBlobStream() function will create a new TStream.
        //Instances created with TStream need to be deleted.
        std::tr1::shared_ptr<TStream> ss(l_table->CreateBlobStream(
            l_table->FieldByName("Graphic"), TBlobStreamMode::bmRead));
        ss->Position = 8;
        l_ms->CopyFrom(ss.get(), ss->Size-8);
        l_ms->Position = 0;
        std::tr1::shared_ptr<TBitmap> b(new TBitmap());
        b->LoadFromStream(l_ms.get());
        //Convert calling Bitmap data to jpeg.
        l_jpeg->Assign(b.get());

        //When saving JPEG, the file name is "Species No" and "Species Name".
        l_jpeg->SaveToFile(l_table->FieldByName("Species No")->AsString + "_" +
            StringReplace(l_table->FieldByName("Species Name")->AsString, " ", "_", TReplaceFlags() <<rfReplaceAll) +
            ".jpeg");
        //Move to the next record.
        l_table->Next();
    }
}

Make the file name "Species No" + "Species Name" + ". Jpeg".
"Species No" + "Species Name" exists in DB field.

 

 

 

Confirm the output JPEG data

Back to the Future: Rückblick Forentage in Hamburg und EKON in Köln

$
0
0

In den letzten Tagen war es hier etwas ruhig..... Konferenzen und Urlaub muss auch mal sein.

Hier einige Eindrücke von den Forentagen in Hamburg:

Sebastian Gingter

Haupt-Session-Raum / Panorama

Die Vortragenden:

David Millington, Stefan Glienke, Bernd Ott, Sebastian Gingter, Volker Hillmann, Christina Kruse, Bernd Ua, Ulf Klarmann, Frank Lauter, Bruno Fierens, Uwe Raabe, ....

Und natürlich von der EKON aus Köln:

Marco Cantus Keynote

Bernd Ua Keynote

Einer meiner Vorträge

Mit insgesamt weit über 250 Teilnehmern wirklich tolle und erfolgreiche Veranstaltungen.

 

iPhone X, Face ID und Delphi

$
0
0

Apple bietet für das iPhone X eine neue Autorisierungsmöglichkeit an: Face ID. Generell ist Face ID, als Nachfolger von Touch ID (dem Fingerabdrucksensor seit dem iPhone 5S) auf API Ebene kompatibel zu Touch ID. Also sollte die kleine Unit von https://bitbucket.org/allesbeste/ios-touchid-wrapper-for-delphi auch hier mit Face ID funktionieren.

Und die Unit funktioniert auch mit Delphi und Face ID auf dem iPhone X:

Generell kapselt die Unit iOSapi.LocalAuthentication (vom oben angegeben Link) die absoluten, aber ausreichenden Grundfunktionalitäten aus dem LocalAuthetication-Framework: Die Fallback-Methode habe ich etwas umgeschrieben. Hier wird die Statusbar (ein anderes Thema für iPhone X) einfach rot oder grün gefärbt:

uses
[...] iOSapi.LocalAuthentication [...]


procedure TFormIrgendwas.TouchIDReply(success, error: Pointer); var bSuccess: Boolean; begin bSuccess := false; if not Assigned(error) AND Assigned(success) then begin bSuccess := ((Integer(success)) = 1); end; if bSuccess then begin // hat geklappt! Autorisiert self.SystemStatusBar.BackgroundColor := TAlphaColorRec.Darkgreen; end else begin // keine Autorisierung! self.SystemStatusBar.BackgroundColor := TAlphaColorRec.Darkred; end; // Form neu zeichnen self.Invalidate; end;

RAD Studio 10.2.2 Released Today

$
0
0

I am excited to announce that RAD Studio 10.2.2 was released today. 10.2 Tokyo, Release 2 (also known as 10.2.2) is an update of Delphi 10.2 Tokyo, C++Builder 10.2 Tokyo and RAD Studio 10.2 Tokyo available for any active Update Subscription customer.

 

10.2.2 Registered User Download Links:

Docwiki: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/10.2_Tokyo_-_Release_2  

 

Several key new features were added, including FireMonkey Quick Edit support, a number of new VCL controls, a new dark themed IDE option, a RAD Server single site deployment license in Enterprise and Architect editions, installer and welcome page enhancements and more.

 

Also included is newly added support for macOS High Sierra, and enhanced platform support for iOS 11 (including iPhone X), Android 8, Windows 10, and Linux, additional enhancements throughout various product areas, and over quality improvements to over 150 publicly reported issues.

 

 

Key RAD Studio 10.2.2 Features:

The new dark theme is designed for night-time work or lengthy use, with updated component icons that complement both the light and dark theme. Easily toggle between the newly added dark theme and the existing light theme through a newly provided option on the desktop toolbar in the IDE.

 

 

Improve developer productivity with the new Quick Edit feature for FireMonkey, allowing you to quickly perform common actions in the FireMonkey Form Designer.

 

 

 

Also new in 10.2.2 are four new VCL Windows GUI controls, designed with Windows 10 in mind.

  • TCardPanel: The new Card Panel is a specialized component that manages a collection of cards.
  • TStackPanel: The Stack Panel is a new container control that allows you to automatically align all parented controls vertically or horizontally while retaining each control's custom height and width settings.
  • TDatePicker and TTimePicker are modern date and time picker controls with support for multiple formatting options, a custom drop-down count and ok and cancel date and time selection buttons.

 

 

Also new is an updated IDE Welcome Page with new sample projects, videos from our YouTube channel, and a calendar of local and global events to help new users get started quickly.

 

Delphi, C++Builder and RAD Studio Enterprise and Architect editions now include a RAD Server Single Site/Single Server deployment license. Also covered by the included single site RAD Server license is BeaconFence deployment for a single location with unlimited users, and no square footage limitation

 

We've also enhanced our JavaScript client support for Sencha Ext JS with RAD Server through TDataSet JSON mapping.

 

Click on our new 10.2.2 product video below to see the key new features in action:


[YoutubeButton url='https://www.youtube.com/watch?v=iGnJANX18uw']

 

New to RAD Studio? Download the RAD Studio 10.2.2 Trial today!

Tech Tipp #12: Android 8.x und Debugging

$
0
0

Frage: Ich kann mit dem RAD Studio/Delphi/C++Builder  10.2 auf meinem Android 8.0 Gerät nicht debuggen. Wodran liegt das?

Antwort: Google ist mit dem Android 8.0 Release "etwas" über das Ziel hinausgeschossen..... Google hat mit dem Release von Android 8.0 in diesem Sommer (war das ein Sommer?) einige Sicherheitsfeatures nachgeschärft. Leider ist dadurch das Debugging flöten gegangen. "Can't open socket: Permission denied.".

Dazu gibt es auch einige Diskussionen hier und hier.

Die gute Nachricht: Google hat das mit Android 8.1 geradegebogen. Viel Glück an die Android-User ein Oreo 8.1 Update zu erhalten.

Quelle: http://blog.marcocantu.com/blog/2017-december-delphi-android81-debugging.html?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+marcocantublog+%28marcocantu.blog%29

 

It is a new function of 10.2.2, and it can be outputted by Ext JS store definition.

$
0
0

New in 10.2.2 TFDBatchMoveJSONWriter was added.

TFDBatchMoveJSONWriter is a Writer that combines with TFDBatchMove to out to a simple JSON. But,  TFDBatchMoveJSONWriter has the function of generating Model definition of Ext JS.
I tried with a field dynamically created with TFDMemTable.

code

The code below is a simple 64-bit console application.
I wrote this code using C++Builder.

umain.cpp
#include <vcl.h>
#include <windows.h>

#pragma hdrstop
#pragma argsused
#pragma link "dbrtl.a"
#pragma link "FireDAC.a"
#pragma link "FireDACCommonDriver.a"
#pragma link "FireDACCommon.a"

#include <tchar.h>
#include <iostream>
#include <System.JSON.hpp>
#include <FireDAC.Stan.Intf.hpp>
#include <FireDAC.Stan.Option.hpp>
#include <FireDAC.Stan.Param.hpp>
#include <FireDAC.Stan.Error.hpp>
#include <FireDAC.DatS.hpp>
#include <FireDAC.Phys.Intf.hpp>
#include <FireDAC.DApt.Intf.hpp>
#include <FireDAC.Comp.BatchMove.JSON.hpp>
#include <FireDAC.Comp.BatchMove.hpp>
#include <FireDAC.Comp.BatchMove.DataSet.hpp>
#include <Data.DB.hpp>
#include <FireDAC.Comp.DataSet.hpp>
#include <FireDAC.Comp.Client.hpp>
#include <FireDAC.Stan.StorageJSON.hpp>
#include <functional>
#include <string>
#include <sstream>

struct dbs
{
    TFDMemTable* f_MemTable1;
    TFDBatchMove* f_BatchMove1;
    TFDBatchMoveDataSetReader* f_DataSetReader1;
    TFDBatchMoveJSONWriter* f_JSONWriter1;
    TFDStanStorageJSONLink* f_JSONLink1;
    dbs(std::function<void(TFDMemTable*)> func)
    {
        f_MemTable1         = new TFDMemTable(nullptr);
        f_BatchMove1        = new TFDBatchMove(nullptr);
        f_DataSetReader1    = new TFDBatchMoveDataSetReader(nullptr);
        f_JSONWriter1       = new TFDBatchMoveJSONWriter(nullptr);
        f_JSONLink1         = new TFDStanStorageJSONLink(nullptr);
        f_DataSetReader1->DataSet   = f_MemTable1;
        f_BatchMove1->Reader        = *f_DataSetReader1;
        f_BatchMove1->Writer        = *f_JSONWriter1;
        func(f_MemTable1);
    };
    static inline String IToString(int iin)
    {
        std::wostringstream ss;
        ss << iin;
        return ss.str().c_str();
    }

    ~dbs()
    {
        delete f_MemTable1;
        delete f_BatchMove1;
        delete f_DataSetReader1;
        delete f_JSONWriter1;
        delete f_JSONLink1;
    };
};

int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        TStringList* alist = new TStringList();
        try
        {
            dbs adbs([](TFDMemTable* memt)
                {
                    //Field definition of TFDMemTable* instance.
                    //Create five fields.
                    for (int i = 0; i < 5; i++)
                    {
                        TStringField* aField    = new TStringField(nullptr);
                        aField->FieldName       = "Column" + dbs::IToString(i);
                        aField->Size            = 50;
                        memt->Fields->Add(aField);
                    }
                });
            //Then execute the GenerateExtJSModel() method.
            //This GenerateExtJSModel() is a TFDBatchMoveJSONWriter class that has been added than 10.2.2.
            adbs.f_JSONWriter1->GenerateExtJSModel("Table1", true, alist);
            //Console out.
            std::wcout << alist->Text.c_str() << std::endl;
        }
        __finally
        {
            delete alist;
        }

    }
    catch(...)
    {

    }
    return 0;
}

result GenerateExtJSModel()

The output store definition is as follows.

Ext.define('Table1', {
  extend: 'Ext.data.Model',
  requires: [
    'Ext.data.field.Field'
  ],
  fields: [
    { name: 'Column0', type: 'string' },
    { name: 'Column1', type: 'string' },
    { name: 'Column2', type: 'string' },
    { name: 'Column3', type: 'string' },
    { name: 'Column4', type: 'string' }
  ]
});

It can be output in Ext JS store definition.
2018-01-011450.png

C++Builder 10.2.2 新コンポーネントTCardPanel[JAPAN]

$
0
0

あけましておめでとうございます。2018年が皆様にとって、飛躍の年であるよう祈っております。新しい年の始まりにあたり、Eショップ各社にて、新春初売りキャンペーンを実施します。幅広い製品ラインナップが18% OFF!1月31日までの期間限定です。この機会をぜひご活用ください。

 

C++Builder 10.2 Release 2 TCardPanelについて

TCardPanel概要

TCardPanelは、複数のTCardとセットで利用します。
IDEのデザイナ上でTCardを作成し管理する事ができ、TCardPanelを配置した上にTButtonなどのコンポーネントをドラッグ&ドロップすると自動でTCardが作られその配下にTButtonが配置されます。
TCardはフォーム上に作られるが、TCardPanel内部ではTList<TCard>を作って管理している。


TCardPanel機能

TCardを管理する為のいくつかの機能があります。

CreateNewCard();

新しくTCardを作成し、アクティブにする。

 TCard* acard = CardPanel1->CreateNewCard();
    TButton* b1 = new TButton(this);
    b1->Parent =  acard;

 

DeleteCard(int Index);

TCardを削除する。コンテナから消すだけではなくインスタンスもdeleteする。

 //アクティブなカード番号を取得しカードを削除
    CardPanel1->DeleteCard(CardPanel1->ActiveCardIndex);

 

FindNextCard(int Index, bool GoForward, bool CheckCardVisible);

順方向または逆方向に順番に次のカードのインデックスを取得する。

引数名 内容
Index 開始位置
GoForward false =前, true=後
CheckCardVisible false = visibleカードだけを検索
 int i = CardPanel1->FindNextCard(0,true,false);

 

NextCard();

次のカードに移動

 CardPanel1->NextCard();

 

PreviousCard();

前のカードに移動

 CardPanel1->PreviousCard();

 

プロパティ ActiveCardIndex

アクティブなカード番号を取得

 int i = CardPanel1->ActiveCardIndex;

 

プロパティ ActiveCard

アクティブなカード取得

 TCard* acard = CardPanel1->ActiveCard;

 

プロパティ CardCount

TCardPanel上のカード数

 int acount = CardPanel1->CardCount;

 

プロパティ Cards[int Index]

TCardPanel上カード個別取得

 TCard* acard = CardPanel1->Cards[0];

 

プロパティ Loop

ナビゲートするときにNextCardおよびPreviousCardのメソッドがカードリストの反対側にループするかどうかを制御します。

 CardPanel1->Loop = true;

 

イベント OnCardChange

アクティブなカードが別のカードに変更された場合に発生します。

typedef void __fastcall (__closure *TCardChangeEvent)(System::TObject* Sender, TCard* PrevCard, TCard* NextCard);

 

Neuer YouTube Video Kanal von Leon Kassebaum / Akademisches Programm / Nachwuchsförderung

$
0
0

Im Bereich der Nachwuchsförderung von Embarcadero tut sich einiges in der letzten Zeit:

 

Viewing all 167 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>