TScreen->Forms Shows Unexpected Extra Forms - delphi

I am using C++Builder 10.3 Rio and a VCL windows application. I am using the TScreen->Forms to get information about my programs open forms. This shows a higher FormCount than I expected. My application has two open forms (1)the main program form and (2)a data entry dialog box. When I check the Screen->FormCount it shows 6 forms. When I check the forms name and caption in the for loops below only my 2 forms have a name and caption. The other form names and captions are NULL. I can identify my forms using the dynamic_cast or the form name. What are the other extra forms? How can I identify the other forms?
UnicodeString MyName, MyCaption;
for(int j=0; j<Screen->FormCount; j++){
MyName = Screen->Forms[j]->Name;
MyCaption = Screen->Forms[j]->Caption;
TMyForm *MyLocal = dynamic_cast<TMyForm *>( Screen->Forms[j] );
}
for(int j=0; j<Screen->CustomFormCount; j++){
MyName = Screen->CustomForms[j]->Name;
MyCaption = Screen->CustomForms[j]->Caption;
}

You can use the ClassName property to find out a little more information.
But that might not reveal anything of use if, for instance, some of the forms are plain TForm, or you don't recognise the name. To truly work out what these forms are, set a breakpoint in TCustomForm.Create and inspect the call stack each time that breakpoint is triggered.

Related

Using CompareText() and AdvPopupMenu

I'm using C++Builder 10.3 with a VCL application for Windows. I'm trying to identify a specific item in an AdvPopupMenu by looping through the Items Caption and comparing the Caption to my search text using CompareText(). The Captions have an '&' in the Caption text which I believe is part of the ShortCut feature. This seems to prevent a match when comparing the text.
I have tried setting up the menu items two ways to try and remove the '&'.
//--#1 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
TShortCut sc2;
sc2 = TextToShortCut("(None)");
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = sc2;
//--#2 Menu Setup--
TMenuItem *NewMenuItem;
NewMenuItem = new TMenuItem(MainForm->AdvPopupMenu1);
NewMenuItem->Caption = "Google";
NewMenuItem->ShortCut = NULL;
Below is my loop to search for the AdvPopupMenu item.
UnicodeString SearchFor = "Google";
UnicodeString TestCaption;
for(int i=0; i<MainForm->AdvPopupMenu1->Items->Count; i++){
TestCaption= MainForm->AdvPopupMenu1->Items->Items[i]->Caption;
if(CompareText(SearchFor , TestCaption)==0 ){
//This CompareText always fails
//TestCaption looks like this "&Google" or this "G&oogle"
}
}
How can I setup the AdvPopupMenu Caption to contain no '&' and make the CompareText work?
The &s are important. Without these, keyboard users like myself will find your application more difficult to use.
I think your best solution is to use the StripHotkey function in the Vcl.Menus unit to remove the ampersand character before you pass the caption to CompareText. (In addition, instead of testing if CompareText returns 0, it's better to use the SameText function.)
That is, don't attempt to create the menu items without the ampersand character, and don't try to remove it from the menu items. Only remove the character from the string you pass to the comparison function.
Also notice that the ampersand character is not related to the ShortCut property. The ampersand character makes the next character underlined in the menu item caption, telling the user than he or she can press that key to activate the menu item, but only when the menu is open. On the other hand, the ShortCut property adds a right-aligned text like Ctrl+A or Shift+Ctrl+N or F2 to the menu item, and these shortcuts are available even when the menu isn't open. Hence, these are different features.

Multiple instances of the same Active Form

I have an Active Form, I made some years ago, compiled as an ocx. It is installed on the tool palette.
I've only used one instance of it on each main application, and it has worked fine.
Now I need to use many instances of this active form from the same main application. So I drop a couple of them from the tool palette to my main application. But no matter which of the active forms I use (it has an built in form I open) from the application, the same instance of it shows up. And this is not what I want.
I can't figure out if the active form should been created in a different way, or if I should use it different from the main application.
The active form is built with c++builder XE, and the main application is built with XE6.
This is the way I create the instances:
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ActXList = new TList;
TMyActX *TempActX;
for(int i=0; i<10; i++)
{
TempActX = new TMyActX(Owner);
TempActX->Parent = this; //Tried also with NULL and a new TForm(this), same result
ActXList->Add(TempActX);
TempActX->Init(i); //This adds i to a string in the created instance
}
MyActX1->Init(20); //Adds 20 to a string in the design time created instance
MyActX2->Init(21); //Adds 21 to a string in the instance
}
And here I open the different instances:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
TMyActX *TempActX;
//A Combobox chooses the instance to show
if(ComboBox1->ItemIndex < 10)
{
TempActX = (TMyActX *)ActXList->Items[ComboBox1->ItemIndex];
TempActX->ShowForm();
}
else if(ComboBoxTerminaler->ItemIndex == 10)
MyActX1->ShowForm();
else if(ComboBoxTerminaler->ItemIndex == 11)
MyActX2->ShowForm();
//No matter which instance is chosen to be shown,
//the label with the init-string shows "0 1 2 3...9 20 21" for all of them
}
For testing, the integer i is added to an Label in ->Init(). TMyActX has an internal form where the Label is shown. If I open this from (with any of the created instances), the Label shows "0 1 2 3 4...". Therefore I make the conclusion that ->Init() calls the same instance, and the same form is opened no matter which created instance I use to open it.
The same thing happens if I drop two instances to my main form at design time. The same Label is shown if I open the ocx-form.
The reason I use an ocx, is that the ocx is a part of a payment solution, that is certified by a external organization. So I don't want to not mess around with it, if possible. But I have access of the code for it, and for testing I can change it.
if you got access to the TForm class of your form then just create new instances on runtime like:
TForm *win[10];
for (int i=0;i<10;i++) win[i]=new TForm(this);
where this is pointer to parent VCL form created by IDE. This works for me but I do not use ocx instead I include the 3 files per window (*.h,*.cpp,*.dfm) however I am bound to BDS2006 so on newer versions of builder things may be a bit different ...
Do not forget that to make this work you can not have global variables in your form, and have proper close/destroy method of the win[] on apps close.
You can access your windows by their pointer (to show or hide them or whatever) also you should handle the manual close of window (so you do not access dead pointer latter on)

TListView DynamicAppearance with TImageObjectAppearance will not view image when using LiveBindingsDesigner with TFDMemTable

I am welcoming Embarcaderos efforts to make TListView more dynamically, and was exited to see Sarina Duponts post here where you could just link the imageindex to the TListView properties in LiveBindings Designer, and even the image property to a datafield (integer) when using DynamicAppearance and TImageObjectAppearance.
But... I tried, and did almost succeed.
In my challenge I have an application where I use TFDMemTable with TREST* function to populate the TFDMemTable. All works well if I don't use the DynamicAppearance and use i.e. ImageListItem and links the datafield I want to use to the imageindex property in TListView using LiveBindings Designer.
With DynamicApperance though, there are no imageindex property to link to, but Sarina Dupont says in here post that you could link the integer field directly to the image property (and IDE/compiler will figure it out).
Well... I figured following out: My data fields (semicreated from TREST* and TFDMemTable) are not neccesserely what they seems to be. Since I am using REST/JSON, the fieldtypes are "anonymized" to WideString, actually the FieldDefs->'dataitem'->DataType is set to "ftWideString". I tried to change this value to ftInteger in hope that this would help, but I did just get this errormessage: "FDMemtTable1: Type mismatch in field for 'datafield', exepecting: WideString actual: Integer".
So... I was nearly there, and I really want to use DynamicAppearance and view several images and textfields for each TListViewItem...
...or is it easier to make a ListViewItem 'Template' dynamically and populate it with data instead, and what is the best way to do that ?
I usually try to avoid LiveBindings. The fastest, most stable and easiest way is to add items using code.
ListView1->BeginUpdate();
try {
for (int i = 0; i < arrayOfThings->item.Length; i++) {
TListViewItem* item = ListView1->Items->Add();
item->Text = arrayOfThings->item[i]->item_name;
item->Data["itemName"] = TValue::From<UnicodeString>( arrayOfThings->item[i]->item_name);
item->Data["itemId"] = TValue::From<UnicodeString>( IntToStr( arrayOfThings->item[i]->id ));
item->Data["itemDate"] = TValue::From<UnicodeString>(arrayOfThings->item[i]->item_date);
// adding the image - imgClock is name of the image field [TImageObjectAppearance ] added to items in ItemAppearance in the TListView object that uses DynamicAppereance
const UnicodeString imgClock = L"imgClock";
dynamic_cast<TListItemImage*>(item->Objects->FindDrawable(imgClock))->Bitmap = //bitmap source;
}
} catch (...) {
}
ListView1->EndUpdate();

RichEdit.PlainText seems to not affect anything

I'm trying to write something like rtf editor in BCB6 and I've encountered such problem while trying to add table to my RichEdit1:
RichEdit1->PlainText=true;
AnsiString ret=RichEdit1->Text;
ret.Insert(table, RichEdit1->SelStart);
RichEdit1->Text=ret;
RichEdit1->PlainText=false;
RichEdit1->Repaint();
This code adds formatted text (code of table) to the RichEdit1 instead of adding formatting code as plain text and displaying it like a table.
Am I doing it wrong, or it can be a problem with something else.
The PlainText property is only used by the Lines->LoadFrom...() and Lines->SaveTo...() methods, nothing else.
The Text property only operates on plain text. Reading the property extracts the RichEdit's textual content without formatting. Setting the property does not process RTF code at all, the RichEdit's textual content is replaced with the new text as-is.
If you want to insert RTF code into the RichEdit, especially if you don't want to overwrite the RichEdit's current content, you will have to use the EM_STREAMIN message directly. For example:
DWORD CALLBACK StreamInCallback(DWORD_PTR dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)
{
int numRead = reinterpret_cast<TStringStream*>(dwCookie)->Read(pbBuff, cb);
if (pcb) *pcb = numRead;
return 0;
}
TStringStream *strm = new TStringStream(table);
EDITSTREAM es = {0};
es.dwCookie = (DWORD_PTR) strm;
es.pfnCallback = &StreamInCallback;
SendMessage(RichEdit1->Handle, EM_STREAMIN, SF_RTF | SFF_SELECTION, reinterpret_cast<LPARAM>(&es));
delete strm;
Problem solved, formatting was not added because of table code was not in {} brackets, after adding them around table code and using SendMessage, program works well.

TAction.SecondaryShortCuts is language specific. How to set it correctly?

I just used the SecondaryShortCuts-Feature of Delphi's TAction. But Shortcuts are defined by Strings, like "F5" or "Shift+F5". Now the problem: On my German Windows the action doesn't fire, because the key "Shift" is called "Umsch" in German!
Does it mean the SecondaryShortCuts-Property is completely useless at design time, because nobody can create applications which work internationally with that?
I could set the key at runtime by translating the VK_SHIFT into the correct name. I tried it via GetKeyNameText but this didn't worked because it gave the long form "Umschalt" not "Umsch". Anybody know the function to get the short version of the key name?
You could try this: Generate the shortcut text from a shortcut:
var
s: TShortCut;
begin
s := ShortCut(Ord('A'), [ssShift]);
Action1.SecondaryShortCuts.Add(ShortCutToText(s));
By the way, these values are determined by the following constants. Have you translated those? And if so, do you need to?:
SmkcShift = 'Shift+';
SmkcCtrl = 'Ctrl+';
SmkcAlt = 'Alt+';

Resources