This is how my drawing routine for TDBGrid component looks like. I am replacing values from database based on some rules:
void __fastcall TForm_Loadpoint_Details::DBGrid1DrawColumnCell(
TObject *Sender, const TRect &Rect, int DataCol, TColumn *Column,
TGridDrawState State)
{
int row_index = ???;
AnsiString text = GetCustomizedText(row_index, DataCol);
DrawText(text);
}
However I don't know how to tell which row is currently being rendered? Without this knowledge i can't get data for displaying.
You can use the Index or FieldNo property of the Column->Field object, or you can use an accessor class to access the protected TDBGrid::DataLink property and then use its ActiveRecord property.
Related
Is there a reference to a class property in C++Builder, analogous to a regular reference in C++? To understand what I mean, I will give the code (so far this is my solution to the problem):
void change(TControl* object) {
struct TAccessor : TControl { __property Text; };
static_cast<TAccessor*>(object)->Text = L"some text";
}
This function allows you to change the Text property of any object inherited from TControl.
But maybe there is a more elegant solution to this problem?
Your approach will update the Text of any TControl, even if it doesn't actually expose access to Text (which is declared protected in TControl itself, derived classes decide whether to promote it to public/__published as needed).
To account for that fact, you would have to use RTTI to discover if Text is accessible or not. You can also use RTTI to set the property value, without resorting to the Accessor trick.
For example, old-style RTTI (via the <TypInfo.hpp> header) works only with __published properties, nothing else, eg:
#include <TypInfo.hpp>
void change(TControl* object) {
if (IsPublishedProp(object, _D("Text"))
SetStrProp(object, _D("Text"), _D("some text"));
}
Alternatively:
#include <TypInfo.hpp>
void change(TControl* object) {
PPropInfo prop = GetPropInfo(object, _D("Text"), TTypeKinds() << tkUString);
if (prop)
SetStrProp(object, prop, _D("some text"));
}
Whereas newer-style Extended RTTI (via the <Rtti.hpp> header) supports fields, methods, and properties, and all the supported member visibilities, eg:
#include <Rtti.hpp>
typedef Set<TMemberVisibility, mvPrivate, mvPublished> TMemberVisibilitySet;
void change(TControl* object) {
static const TMemberVisibilitySet WantedVisibilities = TMemberVisibilitySet() << mvPublic << mvPublished;
TRttiContext ctx;
TRttiType *type = ctx.GetType(object->ClassType());
TRttiProperty* prop = type->GetProperty(_D("Text"));
if ((prop) && (WantedVisibilities.Contains(prop->Visibility)) && (prop->IsWritable))
prop->SetValue(object, _D("some text"));
}
To send data to multiple clients I create a TIdThreadSafeStringList in OnConnect and assign it to AContext->Data like so
AContext->Data = new TIdThreadSafeStringList
When the client disconnects, its stringlist is deleted in OnDisconnect like so
delete AContext->Data
However this results in an AV. If I zero the parameter, like so
delete AContext->Data
AContext->Data = NULL
the AV goes away. Is there some auto cleanup I'm not aware of?
Using C++ Builder 10.2.3.
Is there some auto cleanup I'm not aware of?
Yes. TIdContext derives from TIdTask, which owns the Data property. The TIdTask destructor is called after the OnDisconnect event and will free the Data object if it is not NULL.
Another (preferred) way to handle this situation is to instead derive a new class from TIdServerContext and add your TIdThreadSafeStringList to that class (and any other per-client custom functionality you want), eg:
class TMyContext : public TIdServerContext
{
public:
TIdThreadSafeStringList *MyList;
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL)
: TIdServerContext(AConnection, AYarn, AList)
{
MyList = new TIdThreadSafeStringList;
}
__fastcall ~TMyContext()
{
delete MyList;
}
//...
};
Then assign your class type to the server's ContextClass property at runtime before activating the server, eg:
__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
IdTCPServer1->ContextClass = __classid(TMyContext);
//...
}
Then, you can simply type-cast any TIdContext* pointer belonging to the server to your class type in order to access the TIdThreadSafeStringList (or other functionality):
static_cast<TMyContext*>(SomeIdContext)->MyList->...
This way, you can ignore the TIdContext::Data property altogether, or use it for other purposes, if desired.
In Dart, I see that it is possible to create const constructors within a class. Is it possible to mix a normal and const constructor within a class using the same fields? Or is it intended to always separate classes used for purposes of creating mutable and immutable instances?
I have tried creating a normal and const constructor in the same class. The issue is const constructors require final fields, and so if a normal constructor were to use these fields, then its instance fields would be immutable.
void main() {
Jank fj = Jank.normal(5, 'LOL');
const cj = const Jank.fixed(6, 'HA');
fj.a = 123; //cannot do this, but want to
cj.a = 456; //cannot do this, is expected
}
class Jank {
final int a;
final String b;
Jank.normal(this.a, this.b);
const Jank.fixed(this.a, this.b);
}
I want to be able to use immutable fields when using the const constructor, and use mutable fields when using the normal one. It seems to be one or the other.
You can have non-const constructors on a class with const constructors, but all fields still need to be final.
You can also use new (implicit) with a const constructor (but not the other way around).
So the difference with a non-const constructors is that the constructor can have a body but it can not do much because it can't update the classes state. It can only invoke changes to states outside of the const instance.
A way around that would be using an Expando
The constructor initializer list allows more expressions because they are not limited to the few only allowed in const context.
So in overall mixing const and non-const is rather limited and only used for edge cases.
What you could do is create a different class that implements the class with the const constructor and instantiate it transparently using a factory constructor.
class Foo {
final int value;
const Foo(this.value);
factory Foo.nonConst(int val) => _Bar(val);
}
class _Bar implements Foo {
int _value
int get value() => _value;
Bar(int val) {
_value = val * 5;
}
}
Hi any idea how to add event to the constructed button in the run time?
I understand how to build component in the run time, but adding event is another thing. Got any example to explain how it works?
Thanks
A VCL event is just a pointer to a class method for a particular object. You can assign that pointer directly, eg:
__fastcall TForm1::TForm1(TComponent *Owner)
: TForm(Owner)
{
TButton *btn = new TButton(this);
btn->Parent = this;
// set other properties as needed...
btn->OnClick = &ButtonClicked;
/*
behind the scenes, this is actually doing the equivalent of this:
TMethod m;
m.Data = this; // the value of the method's hidden 'this' parameter
m.Code = &TForm1::ButtonClicked; // the address of the method itself
btn->OnClick = reinterpret_cast<TNotifyEvent&>(m);
*/
}
void __fastcall TForm1::ButtonClicked(TObject *Sender)
{
// do something ...
}
I'm moving some C++Builder code to BCB2010 and need to replace calls to LeftStr() and RightStr() with appropriate functions, as there's no UnicodeString overload of these.
AnsiLeftStr() appears to work, but the name is scaring me...
You are right to be wary. Use the SubString method from UnicodeString instead.
All of the Ansi...() functions were migrated to Unicode in CB2009. The naming scheme was preserved to maintain backwards compatibility with pre-2009 code, that's all.
If you don't want to change your code to call AnsiLeftStr() instead of LeftStr(), then you could simply implement your own LeftStr() function that calls AnsiLeftStr() or UnicodeString::SubString() internally, eg:
UnicodeString __fastcall LeftStr(const UnicodeString &AText, const int ACount)
{
return AnsiLeftStr(AText, ACount);
}
.
UnicodeString __fastcall LeftStr(const UnicodeString &AText, const int ACount)
{
return AText.SubString(1, ACount);
}