TObject::TObject(int, String)

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

TObject::TObject(int, String)

Postby ingalime » Fri Nov 10, 2017 2:18 am

Hello.
Code: Select all
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  int * Pint = new int;
  * Pint = 1;
  ListBox1->Items->AddObject(L"Test", (TObject)(* Pint));

 //String pos = "***";
 //ListBox1->Items->AddObject(name, reinterpret_cast<TObject*> (pos));//error
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
 for(int i = 0; i < ListBox1->Count; i++)
   {
    if(ListBox1->Items->Objects[i] != NULL)
      delete ListBox1->Items->Objects[i];
   }
}

Could not find a match for 'TObject::TObject(int)'

How correct add int or String in ListBox1->Items->Objects?
How correct read Object?
Last edited by ingalime on Fri Nov 10, 2017 6:32 am, edited 1 time in total.
ingalime
Active Poster
Active Poster
 
Posts: 18
Joined: Wed Apr 12, 2017 3:22 am

Re: TObject::TObject(int, String)

Postby HsiaLin » Fri Nov 10, 2017 3:05 pm

Heres one way i used it in a mp3 player, you should be able to adapt it:

Code: Select all
//---------------------------------------------------------------------------

struct TPlayListItem
{
   String FileName;
   String Path;
   int Index;
};

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

int __fastcall TForm1::AddListItem(String Path, int Index)
{

   try
   {
      PlayListItem = new TPlayListItem;
      PlayListItem->FileName = ExtractFileName(Path);
      PlayListItem->Path = Path;
      PlayListItem->Index = Index;

      ListBox1->Items->AddObject(PlayListItem->FileName, (TObject*)PlayListItem);
   }
   catch(...)
   {
      return 0;
   }

   return 1;
}

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

TPlayListItem *__fastcall TForm1::GetListItem(int index)
{

   TPlayListItem *Temp;
   Temp = (TPlayListItem*)ListBox1->Items->Objects[index];
   return Temp;

}

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



to delete items you`d use something like this

     for(int x = 0; x < ListBox1->Items->Count; ++x)
     {
       delete (TPlayListItem*)GetListItem(x);
       ListBox1->Items->Delete(x);
     }
     ListBox1->Items->Clear();

HsiaLin
BCBJ Master
BCBJ Master
 
Posts: 281
Joined: Sun Jul 08, 2007 6:29 pm

Re: TObject::TObject(int, String)

Postby rlebeau » Fri Nov 10, 2017 8:55 pm

ingalime wrote:ListBox1->Items->AddObject(L"Test", (TObject)(* Pint));


AddObject() expects a TObject* pointer, but you are trying to pass it a TObject object instance that is constructed with an 'int' as input. TObject has no such constructor, that is why you are getting an error.

You need to change your type-cast to this:

Code: Select all
ListBox1->Items->AddObject(L"Test", (TObject*)Pint);
// or:
// ListBox1->Items->AddObject(L"Test", reinterpret_cast<TObject*>(Pint));


ingalime wrote:delete ListBox1->Items->Objects[i];


This is also wrong. You are trying to delete a TObject instance, but you actually allocated an 'int' instead. You need to cast the pointer back to the correct type so 'delete' acts correctly:

Code: Select all
delete (int*)(ListBox1->Items->Objects[i]);
// or:
// delete reinterpret_cast<int*>(ListBox1->Items->Objects[i]);


That being said, I would not suggest dynamically allocating the 'int' at all. You can store its value as-is, just type-casted to a pointer:

Code: Select all
int i = 1;
ListBox1->Items->AddObject(L"Test", (TObject*)i);
// or:
// ListBox1->Items->AddObject(L"Test", reinterpret_cast<TObject*>(i));


Then you don't need to call 'delete' at all, since nothing is being allocated with 'new'.

Use a similar cast to read the 'int' value:

Code: Select all
int value = (int)(ListBox1->Items->Objects[index]);
// or:
// int value = reinterpret_cast<int>(ListBox1->Items->Objects[index]);


In fact, integer-to-pointer and pointer-to-integer casts are one of the main reasons reinterpret_cast even exists in the first place.

Now, that being said, note that this approach only works in VCL, and FMX non-ARC systems. Under ARC, TObject* pointers MUST point at valid TObject instances, so you would have to wrap the 'int' in a TObject-derived class:

Code: Select all
class TIntWrapper : public TObject
{
public:
    int Value;
    __fastcall TIntWrapper(int InitialValue = 0) : TObject(), Value(InitialValue) {}
};

...

TIntWrapper * Pint = new TIntWrapper(1);
ListBox1->Items->AddObject(L"Test", Pint);

...

int value = ((TIntWrapper*)(ListBox1->Items->Objects[index]))->Value;
// or:
// int value = static_cast<TIntWrapper*>(ListBox1->Items->Objects[index])->Value;


No need to 'delete', since ARC objects are reference counted.

Otherwise, use a completely different design that does not rely on storing the 'int' in the ListBox itself. Store it in an array/list off to the side, and then use ListBox indexes to access that array/list when needed. This design better separates your data from your UI:

Code: Select all
private:
    std::vector<int> MyValues; // or whatever container you want to use...

...

MyValues.push_back(1);
try {
    ListBox1->Items->Add(L"Test");
}
catch (const Exception &) {
    MyValues.pop_back();
    throw;
}

...

int value = MyValues[index];


This works especially well with TListBox::Style set to lbVirtual or lbVirtualOwnerDraw (VCL only):

Code: Select all
private:
    std::vector<std::pair<String, int> > MyItems;

...

MyItems.push_back(std::make_pair(L"Test", 1));
ListBox1->Count = MyItems.size();

...

int value = MyItems[Index].second;


Then you just need a TListBox::OnData event handler to populate the ListBox with string values (and optionally a TListBox::OnDataFind event handler to handle searches and auto-completion):

Code: Select all
void __fastcall TForm1::ListBox1Data(TWinControl *Control, int Index, String &Data)
{
    Data = MyItems[Index].first;
}

int __fastcall TForm1::ListBox1DataFind(TWinControl *Control, String FindString)
{
    auto iter = std::find_if(MyItems.begin(), MyItems.end(),
        [=](const std::pair<String, int> &item){ return (item.first == FindString); });
    return (iter != MyItems.end())
        ? (int) std::distance(MyItems.begin(), iter)
        : -1;
}
Remy Lebeau (TeamB)
Lebeau Software
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1457
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: TObject::TObject(int, String)

Postby ingalime » Sat Nov 11, 2017 9:57 am

Many thanks for the detailed answer! I copied all of your code into my recipe book with С++. Great!
ingalime
Active Poster
Active Poster
 
Posts: 18
Joined: Wed Apr 12, 2017 3:22 am

Re: TObject::TObject(int, String)

Postby Lena » Tue Nov 14, 2017 4:26 am

This is a very interesting topic. Thanks for the code!
Lena
BCBJ Master
BCBJ Master
 
Posts: 524
Joined: Sun Feb 06, 2011 1:28 pm


Return to Technical

Who is online

Users browsing this forum: No registered users and 14 guests