Und ggf. gibt es hier noch einen weiteren Textabschnitt, der im mobilen Bereich aber nicht zu sehen ist.
Wie im letzten Post schon angedeutet, geht es heute um weitere GUI- Elemente, die ich als Ausgabemedium für Standard- Streams verwenden möchte. Dabei sind der Phantasie keine Grenzen gesetzt,sie können Edit- Felder, Label, die Statuszeile und die Überschrift des Formulars verwenden, aber auch so komplexe Oberflächenelemente wie ein VCL- ListView- Element für Windows. Dabei können die Standard- Streams cout, clog und cerr verwendet werden, oder sie definieren einen eigenen Stream den sie dann mit den normalen Stream- Operatoren verwenden können.
Um das vorzubereiten, nutze ich jetzt einmal die Objektorientierung und hier eine neue abstrakte Klasse für meine Umsetzung. Gerade hier liegt der entscheidene konzeptionelle Vorteil von C++. Im Gegensatz zu Java und damit letztlich auch C# war und ist C++ nie als reine Sprache definiert worden. Während der 90iger wurde sich aus dem dortigen Lager oft über den hypriden Charakter von C++ ausgelassen. Heute werden mehr recht als schlecht Eigenschaften der Metaprogrammierung und der funktionalen Entwicklung in die einst reinen Sprachen ergänzt. C++ war und ist als Multiparadigmen- Sprache entworfen wurden, unterstützt damit nicht nur eine Reihe von verschiedenen Programmierparadigmen, sondern ermöglicht ein nahtloses Zusammenspiel. So haben wir in den bisherigen Post nicht nur globale Variablen verwendet, wir haben die Vorteile von templates und deren Spezialisierung verwendet. Nun eine abstrakte Klasse, und die Implementierung der Methode, in der die Ausgabe erfolgt zentral mit Hilfe dieser abstrakten Methode.
Beginnen wir mit der Vorbereitung und passen die bisherige Lösung aus dem Posting Verwendung von Standardstreams zur Ausgabe in Memofeldern an. Als erstes definiere ich mir eine neue Basisklasse für meine bestehende Klasse "MyMemoStreamBuf". Diese neue Klasse bekommt die bisherige Basisklasse std::streambuf. Ich verschiebe den als Puffer verwendeten ostringstream "os" in diese Klasse, die Sichtbarkeit definiere ich einfachheitshalber nur als geschützt (protected).. Der Konstruktor und Destruktor können leer bleiben.
Nun definiere ich eine pure virtuelle Methode Write(). Mit dieser kann ich die Implementierung der Methode Write() aus der Klasse "MyMemoStreamBuf" in diese Klasse verschieben, der Zugriff auf das eigentliche Datenelement "value" ersetze ich dafür durch den Aufruf der Methode Write(). Gerade der Zugriff auf dieses Datenelement wird sich von Steuerelement zu Steuerelement unterscheiden.
class MyStreamBufBase : public std::streambuf {
protected:
std::ostringstream os;
public:
MyStreamBufBase(void) { }
virtual ~MyStreamBufBase(void) { }
virtual void Write(void) = 0;
int overflow(int c) {
if(c == '\n') {
Write();
os.str("");
}
else {
os.put(c);
}
return c;
}
};
Damit habe ich eine Basisklasse für die anderen Umlegungen und der Puffer steht allen zur Verfügung. Die Methode Write() übernimmt damit den eigentlichen Zugriff auf das Datenelement. Hier müssen wir natürlich unsere bisherige Klasse "MyMemoStreamBuff" auch anpassen. Um diese später instanzieren zu können, müssen wir die Methode Write() implementieren.
class MyMemoStreamBuf : public MyStreamBufBase {
private:
TMemo* value;
public:
MyMemoStreamBuf(TMemo* para, bool boClean = true) : MyStreamBufBase() {
value = para;
if(boClean) value->Lines->Clear();
}
virtual ~MyMemoStreamBuf(void) { value = 0; }
virtual void Write(void) {
if(os.str().length() > 0) {
value->Lines->Add(__ToVCL(os.str()));
}
else {
value->Lines->Add(L"");
}
}
};
Nun können wir weitere Klassen definieren. Dabei gibt es, wie beim Memofeld sehr einfache Varianten, wie zum Beispiel normale Eingabefelder, da sich ihr die beiden Implementierung wieder gleich verhalten. So sieht diese wie folgt aus.
class MyEditStreamBuf : public MyStreamBufBase {
private:
TEdit* value;
public:
MyEditStreamBuf(TEdit* para, bool boClean = true) : MyStreamBufBase() {
value = para;
if(boClean) value->Text = L"";
}
virtual ~MyEditStreamBuf(void) { value = 0; }
virtual void Write(void) {
if(os.str().length() > 0) {
value->Text = __ToVCL(os.str());
}
else {
value->Text = L"";
}
}
};
In der Implementierung nutze ich hier die Hilfsmethode __ToVCL() aus dem Post Konvertierung der Delphi Stringtypen. Entsprechend der Steuerung der Headerdateien ist eine weitere Unterscheidung hier nicht notwendig.
Anders ist es mit den Labeln. Hier gibt es einen bedauerlichen Unterschied. Während das Datenfeld mit dem anzuzeigenden Text in der VCL "Caption" heisst, ist es in FMX die Eigenschaft "Text". Aber auch hier hilft uns die bedingte Übersetzung, die wir ja in den bisherigen Beispielen auch schon genutzt haben.
class MyLabelStreamBuf : public MyStreamBufBase {
private:
TLabel* value;
public:
MyLabelStreamBuf(TLabel* para, bool boClean = true) : MyStreamBufBase() {
value = para;
if(boClean) {
#ifdef BUILD_WITH_VCL
value->Caption = L"";
#else
value->Text = L"";
#endif
}
}
virtual ~MyLabelStreamBuf(void) { value = 0; }
void Write(void) {
#ifdef BUILD_WITH_VCL
value->Caption = os.str().c_str();
#else
value->Text = os.str().c_str();
#endif
return;
}
};
Nun gibt es auch Steuerelemente, für die eine Implementierung für ein bestimmtes Framework keinen Sinn macht. Während eine Statuszeile in der VCL komplex ist, und mit der Eigenschaft "SimplePanel" und "SimpleText" über direkte Beschriftung erfolgt, ist dieses Element in FMX nur ein Container, der wieder andere Elemente aufnimmt. So könnte man in diese ein Label ziehen und mit einem Align von "alClient" zu einem Simplepanel machen. Deshalb möchte ich nur für die VCL eine Implementierung der Statuszeile vornehmen. Auch hier wieder, wie gewohnt, die bedingte Übersetzung.
#ifdef BUILD_WITH_VCL
class MyStatusStreamBuf : public MyStreamBufBase {
private:
TStatusBar* value;
public:
MyStatusStreamBuf(TStatusBar* para, bool boClean = true) : MyStreamBufBase() {
value = para;
value->SimplePanel = true;
if(boClean)
value->SimpleText = "";
}
virtual ~MyStatusStreamBuf(void) { value = 0; }
virtual void Write(void) {
value->SimpleText = os.str().c_str();
return;
}
};
#endif
Als letztes müssen wir für die neuen Klassen Activate() Methoden im Wrapper "TMyStreamWrapper" aus dem Post RAII beim Verwenden der stream- Neuzuordnungen die Implementierungen vornehmen. Hier der Auszug mit diesen.
#if defined BUILD_WITH_VCL || defined BUILD_WITH_FMX
template<>
inline void TMyStreamWrapper::Activate<TEdit>(TEdit* element) {
Check();
old = str.rdbuf(new MyEditStreamBuf(element));
}
template<>
inline void TMyStreamWrapper::Activate<TLabel>(TLabel* element) {
Check();
old = str.rdbuf(new MyLabelStreamBuf(element));
}
#endif
#if defined BUILD_WITH_VCL
template<>
inline void TMyStreamWrapper::Activate<TStatusBar>(TStatusBar* element) {
Check();
old = str.rdbuf(new MyStatusStreamBuf(element));
}
#endif
Damit haben wir für weitere Steuerelemente Klassen bereitgestellt, und mit Ausnahme der Statuszeile für beide Frameworks bereitgestellt. So können wir jetzt clog für die Statuszeile oder die Überschrift verwenden, und neben cout auch cerr mit einem Memofeld verbinden.
Keine Kommentare
Dieses Seminar richtet sich primär an Einsteiger, die über Programmierkenntnisse, vorzugsweise in C++ verfügen und auf den C++Builder wechseln wollen. Es ist aber auch für Umsteiger von einer wesentlich älteren Version geeignet.
3 Tage
8 Teilnehmer
Dieses Seminar richtet sich an alle Entwickler, die ihre bestehenden Anwendungen vom klassischen C++- Compiler zum neuen, auf Clang basierenden Compiler im C++- Builder umstellen wollen.
3 Tage
8 Teilnehmer
In diesem Seminar erhalten Sie eine kompakte Einführung in die jeweils aktuelle Version des C++Builder (aktuell 10.3.3). Der C++Builder ist ein plattformübergreifendes Entwicklungstool, mit der Sie performante, native Anwendungen für die Zielplattformen Windows (32bit, 64bit), Mac OS (32bit), iOS und Android entwickeln kann.
5 Tage
8 Teilnehmer
Wie der Titel der Schulung sagt, geht es hier um die Entwicklung von nativen Anwendungen für mobile Endgeräte (App) mit dem C++Builder (aktuell 10.3.3).
2 Tage
8 Teilnehmer
Dieser Kurs richtet sich an C++ Entwickler, die den C++Builder nutzen und ihre Kenntnisse vertiefen wollen. Dabei geht es neben der Verwendung der Komponenten und den Eigenschaften der Sprache C++, besonders auch darum, beides vernünftig zu verbinden.
3 Tage
8 Teilnehmer
Dieses Seminar richtet sich an C++ Programmierer, die den Zugriff auf Datenbanken in ihren Anwendungen erweitern wollen. In diesem Seminar werden die wichtigsten Komponenten des C++ Builders für Datenbankzugriff erläutert, aber es wird auch gezeigt, wie sie diese in eine saubere Anwendungsarchitektur integrieren können.
3 Tage
8 Teilnehmer
Dieses Seminar richtet sich an C++ Programmierer, die Erfahrungen mit dem den Datenbankkomponenten des C++ Builders gesammelt haben, und nun skalierbare Datenbankanwendungen entwickeln wollen. In diesem Seminar wird die Bedeutung von ANSI C++ - Schnittstellen zwischen der Businesslogik einer Anwendung und der Datenbank gezeigt.
3 Tage
6 Teilnehmer
Dieser Kurs richtet sich an Softwareentwickler, die die Elemente der Programmiersprache C als Basis für einen späteren Einstieg in die objektorientierte Programmierung mit C++ lernen wollen.
3 Tage
8 Teilnehmer
Dieses Seminar richtigt sich an die Programmierer, die von C nach C++ umsteigen wollen. Es werden die wichtigsten Erweiterungen der Sprache C++, und die Unterschiede zu C ausführlich besprochen.
3 Tage
5 Teilnehmer
Dieses Seminar richtigt sich an die Programmierer, die von C nach C++ umsteigen wollen. Es werden die wichtigsten Erweiterungen der Sprache C++, und die Unterschiede zu C ausführlich besprochen.
5 Tage
8 Teilnehmer
Wir wurden oft gefragt, ob wir eine Schulung "mit allem" machen könnten. Ein größeres Beispiel, beginnend mit einer Idee, daraus eine Architektur entwickeln, und dann unabhängig in C++ implementieren. Die Erweiterungen nur verwenden, ohne das diese unsere Struktur und Architektur bestimmen.Und wenn es geht, auch noch mit Entwicklung eines Zugriffs für mobile Anwendungen verbinden.
5 Tage
8 Teilnehmer
In diesem Seminar lernen Sie, welche Open Source- Tools Sie für Ihre tägliche Arbeit mit dem aktuellen C++ Builder 10.3.2 nutzen können. Dabei geht es um Lösungen zu den Themen Dokumentieren, Metriken, Codeanalyse und Codeverwaltung.
2 Tage
6 Teilnehmer