additional part, not visible
As already mentioned in the last post, today I want to add more GUI elements that I want to use as output medium for standard streams. There are no limits to your imagination, you can use edit fields, labels, the status bar and the form header, but also such complex interface elements as a VCL ListView element for Windows. You can use the standard streams cout, clog and cerr, or you can define your own stream which you can then use with the normal stream operators.
To prepare this, I use the object orientation and here a new abstract class for my implementation. This is the main conceptual advantage of C++. In contrast to Java and thus ultimately also C#, C++ has never been defined as a pure language. During the 90s the local camp often talked about the hybrid character of C++. Today, more rather than bad features of metaprogramming and functional development are being added to the once pure languages. C++ was and is designed as a multiparadigm language, thus not only supporting a number of different programming paradigms, but also enabling seamless interaction. Thus, in previous post, we have not only used global variables, we have taken advantage of templates and their specialization. Now an abstract class, and the implementation of the method in which the output is done centrally using this abstract method.
Let's start with the preparation and adapt the previous solution from the post using standard streams for output in memo fields. First I define a new base class for my existing class "MyMemoStreamBuf". This new class gets the previous base class std::streambuf. I move the ostringstream "os" used as buffer into this class, the visibility I define only as protected for simplicity. The constructor and destructor can remain empty.
Now I define a pure virtual method Write(). With this method I can move the implementation of the method Write() from the class "MyMemoStreamBuf" into this class, the access to the actual data element "value" I replace by calling the method Write(). Especially the access to this data element will differ from control to control.
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;
}
};
So I have a base class for the other reallocations and the buffer is available to everyone. The method Write() thus takes over the actual access to the data element. Here we must of course adapt our previous class "MyMemoStreamBuff" as well. To be able to instantiate it later, we have to implement the method Write().
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"");
}
}
};
Now we can define further classes. There are, like the memo field, very simple variants, like normal input fields, because the two implementations are the same again. So it looks like this.
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 the implementation I use here the help method __ToVCL() from the post conversion of the Delphi string types. According to the control of the header files a further differentiation is not necessary here.
It is different with the labels. Here there is a regrettable difference. While the data field with the text to be displayed is called "Caption" in the VCL, in FMX it is the property "Text". But also here the conditional translation helps us, which we have already used in the previous examples.
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;
}
};
Now there are also controls for which an implementation for a certain framework makes no sense. While a status line in the VCL is complex, and with the property "SimplePanel" and "SimpleText" is done via direct labeling, in FMX this element is just a container that takes other elements. So you could drag a label into this container and make it a Simplepanel by aligning "alClient". Therefore I want to implement the status line only for the VCL. Again, as usual, the conditional translation.
#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
Finally, we have to implement the new Activate() class methods in the wrapper "TMyStreamWrapper" from the post RAII when using the stream reassignments. Here the excerpt with these.
#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
With this we have provided classes for more controls, and with the exception of the status bar we have provided classes for both frameworks. So we can now use clog for the status bar or the header, and besides cout we can also connect cerr with a memo field.
Keine Kommentare
3 days
8 Participants
3 Days
8 Participants
In this seminar you will get a compact introduction to the latest version of C++Builder (currently 10.3.3). C++Builder is a cross-platform development tool that allows you to develop high-performance, native applications for the target platforms Windows (32bit, 64bit), Mac OS (32bit), iOS and Android.
5 Days
8 Participants
As the title of the course says, this course is about developing native applications for mobile devices (app) with C++Builder (currently 10.3.3).
2 Days
8 Participants
This course is designed for C++ developers who want to use the C++Builder and deepen their knowledge. In addition to using the components and the properties of the C++ language, it is especially important to combine both in a sensible way.
3 Days
8 Participants
This seminar is aimed at C++ programmers who want to extend access to databases in their applications. This seminar explains the main components of the C++ Builder for database access, but also shows how to integrate them into a clean application architecture.
3 Days
8 Participants
This seminar is aimed at C++ programmers who have gained experience with the database components of the C++ Builder and now want to develop scalable database applications. In this seminar the importance of ANSI C++ - interfaces between the business logic of an application and the database is shown.
3 Days
6 Participants
This course is aimed at software developers who want to learn the elements of the C programming language as a basis for a later entry into object-oriented programming with C++.
3 Days
8 Participants
This seminar is aimed at programmers who want to switch from C to C++. The most important extensions of the C++ language and the differences to C are discussed in detail.
3 Days
5 Participants
This seminar is aimed at programmers who want to switch from C to C++. The most important extensions of the C++ language and the differences to C are discussed in detail.
5 Days
8 Participants
We were often asked if we could do a training "with everything". A larger example, starting with an idea, developing an architecture from it, and then implementing it independently in C++. Just use the extensions without letting them determine our structure and architecture, and if possible, combine this with developing access for mobile applications.
5 Days
8 Participants
In this seminar you will learn which Open Source tools you can use for your daily work with the current C++ Builder 10.3.3. This includes solutions for documenting, metrics, code analysis and code management.
2 Days
6 Participants