Board index » cppbuilder » A new method of displaying hints?

A new method of displaying hints?


2004-02-03 11:39:18 AM
cppbuilder64
I've been wrestling with an easier method of displaying hints in BCB
forms, and all of the examples I've ever seen discuss how one uses a
dedicated hint-handler for each form, how you assign/save the hint
handler in OnActivate and OnDeactivate events, etc. Ultimately, I found
problems with the housekeeping associated with this, so I've generated
the routine below. It is stored in the MainForm, but will write the
hint to the status bar of the active form (assuming a status bar
exists). If there is no status bar, then it writes no hint. This can
be disabled on a given form simply be disabling hints for that form in
the Object Inspector. This would eliminate the calls, but isn't
strictly necessary.
This routine is simply stored in the Application->OnHint event during
main form creation, and never needs to be changed. This eliminates
having separate DisplayHint routines, and using the
OnActivate/OnDeactivate events to call them.
Note (as I mentioned in my comments) that it would be a simple matter to
modify this routine, such that the constructor of the 'active form'
could store the pointer to the StatusBar in the Tag property (or have
Tag be a pointer to a MyUserProperties structure), and this would
eliminate the unneeded repetition of finding the status bar, but this is
realistically pointless, as the hint is only called if the user is
scrolling around the form, which isn't going to be happening horribly
often during computations (and it it's that big of a problem hints could
be disabled during time-sensitive operations). This is one of those
examples where in days of yore I would have coded it to perform the
iteration once, and stored the result, but with today's computers, it
seems rather pointless.
Any comments welcomed. Code follows signature.
David Erbas-White
// Routine for implementing a 'generic' hint handler, across forms.
// The routine simply uses the ActiveForm property of the screen to find the
// current form, then looks for the status bar component on the active form.
// Once that component is found, the long hint is displayed on the
status bar.
//
// If the status bar has SimplePanel set to true, then SimpleText is used.
// If it is false, it uses the first panel of the Panels property to display
// the hint. If no StatusPanel is found, no hint is displayed.
//
// Note that this doesn't work if the hint is being displayed in another
area,
// such as a larger panel. A distinct function must be called for this, if
// desired, or the routine must be modified.
//
// A possible alternative is to store the 'hint panel' as a TPanel
address, in
// a structure for each form. Then the iterative technique will not be
needed,
// at least after the constructor is called (the constructor would set the
// value of the tag structure).
void __fastcall TMainForm::ShowGenericHint(TObject *Sender)
{ TStatusBar *HintBar=NULLP;
TForm *HintForm = Screen->ActiveForm;
for (int i=0;i<HintForm->ComponentCount;i++) {
HintBar=dynamic_cast<TStatusBar*>(HintForm->Components[i]);
if (HintBar)
break;
} // for all ComponentCount
// At this point, HintBar contains the pertinent status bar, if it exists
if (HintBar) {
if (HintBar->SimplePanel)
HintBar->SimpleText=GetLongHint(Application->Hint);
else
HintBar->Panels->Items[0]->Text=GetLongHint(Application->Hint);
} // if (HintBar)
}
 
 

Re:A new method of displaying hints?

David Erbas-White wrote:
I had a weird bug crop up this week, and finally tracked it down. The
ultimate solution would be to fix what I perceive to be a bug in the
VCL, but that's pointless now. Instead, I've modified my 'generic hint'
routine to 'solve' the problem.
Here's what happened - out of the blue, my program (that had been
working fine) suddenly started giving me 'Index out of bounds' errors.
After debugging, it turned out that the SimplePanel property of one of
the status bars had been set to 'false', but there were no entries in
the 'Panels' property. Thus, when attempting to write to the first
entry in the Panels property, there would be an access violation.
Now, I did not (at least intentionally) change the SimplePanel property.
However, I have run into similar things on occasion with BCB, where
something that I've not selected is 'changed', so I'm not horribly
surprised by this. For example, if you have several items in your
project, say 20 or so, and you make the project window smaller, to fit
about 10 of the entries, then scroll down to show the bottom entries,
and double click on one of them, it will open a different item from the
project box.
The bug (as it relates to the TStatusPanel) is that it should not be
POSSIBLE to set SimplePanel to false if no Panels are present -- this is
a condition that is illegal. If the argument is going to be made that
one could programmatically add panels, I would counter with the argument
that one could also programmatically change the SimplePanel property
after populating the Panels.
David Erbas-White
The new code is posted below:
void __fastcall TMainForm::ShowGenericHint(TObject *Sender)
{ TStatusBar *HintBar=NULLP;
TForm *HintForm = Screen->ActiveForm;
for (int i=0;i<HintForm->ComponentCount;i++) {
HintBar=dynamic_cast<TStatusBar*>(HintForm->Components[i]);
if (HintBar)
break;
} // for all ComponentCount
// At this point, HintBar = the pertinent status bar, if it exists
if (HintBar) {
if (HintBar->SimplePanel)
HintBar->SimpleText=GetLongHint(Application->Hint);
else {
if (HintBar->Panels->Count)
HintBar->Panels->Items[0]->Text=GetLongHint(Application->Hint);
else {
HintBar->SimplePanel = true;
HintBar->SimpleText=GetLongHint(Application->Hint);
}
}
} // if (HintBar)
}
 

Re:A new method of displaying hints?

"David Erbas-White" < XXXX@XXXXX.COM >wrote in message
Quote
The bug (as it relates to the TStatusPanel)
The bug is in your own code. You should have checked the StatusBar Panels
before assuming that a panel would be available. Even the native VCL checks
the Panels first:
function TStatusBar.ExecuteAction(Action: TBasicAction): Boolean;
begin
if AutoHint and (Action is THintAction) and not DoHint then
begin
// *** here ***
if SimplePanel or (Panels.Count = 0) then
SimpleText := THintAction(Action).Hint else
Panels[0].Text := THintAction(Action).Hint;
// ******
Result := True;
end
else Result := inherited ExecuteAction(Action);
end;
Quote
is that it should not be POSSIBLE to set SimplePanel to
false if no Panels are present -- this is a condition that is illegal.
Actually, it is not strictly illegal at all, or they would have already
implemented such restrictions already. It is your own code's responsibility
to make sure that it is performing valid operations to begin with. Even if
the VCL did prevent what you suggest, it could not prevent you from
continuing to access Panels[0] if no panels are actually present. It is
still your own responsibility to check the Panels Count first.
Gambit
 

{smallsort}

Re:A new method of displaying hints?

Remy Lebeau (TeamB) wrote:
Quote
end;


>is that it should not be POSSIBLE to set SimplePanel to
>false if no Panels are present -- this is a condition that is illegal.


Actually, it is not strictly illegal at all, or they would have already
implemented such restrictions already.
Really? Borland is infallible? And that's why things such as the
PrintSetupDialog box cause an immediate access violation if no printer
is installed on a target system?
It is your own code's responsibility
Quote
to make sure that it is performing valid operations to begin with.
Huh? It's my own code's responsibility to check this, but it's not the
responsibility of the VCL to check if SimplePanels can be set to a state
that is illegal?
Even if
Quote
the VCL did prevent what you suggest, it could not prevent you from
continuing to access Panels[0] if no panels are actually present. It is
still your own responsibility to check the Panels Count first.


Do you do that for everything, in every bit of code? Or do you assume
that the compiler will do certain things for you?
Do you do this:
MyForm->Caption = "My Caption";
MyForm->Show();
Or do you do this:
if (MyForm)
MyForm->Caption = "My Caption";
if (MyForm)
MyForm->Show();
I'm fairly certain I know which one you use...
To take it to an extreme, do you check to make sure that the Show()
function exists WITHIN the form before you attempt to execute it? I
don't think so.
The example you gave MAKES SENSE from the standpoint of the VCL,
particularly if similar code were used in relation to the SimplePanel
property. Bottom line -- the state of SimplePanel being 'false' while
no panels exist is an 'illegal state'; and the VCL should not allow this
to occur.
The point is that the development tool is supposed to make it EASIER for
the developer, not make it harder. This is compounded by the fact that
I did not (intentionally) change the SimplaPanel property in the form,
and I'm fairly convinced that it was changed due to a bug in the Object
Inspector (i.e., double clicking on one item, and it accidentally
changes another). Given that, and the difficulty that can come about in
debugging such an issue, it should be incumbent upon the VCL to not
allow such a state.
David Erbas-White
 

Re:A new method of displaying hints?

"David Erbas-White" < XXXX@XXXXX.COM >wrote in message
Quote
It's my own code's responsibility to check this, but it's not
the responsibility of the VCL to check if SimplePanels can
be set to a state that is illegal?
It is your own responsibility to make sure the Count is greater than 0
before you try to access an item in the collection. The same goes for any
list and collection in general.
Quote
I'm fairly certain I know which one you use...
Actually, I would do this:
if( MyForm)
{
MyForm->Caption = "My Caption";
MyForm->Show();
}
It also depends on the context in which MyForm is being used, and whether I
needed to know whether it had been constructed yet or not.
Quote
I did not (intentionally) change the SimplaPanel property in the
form, and I'm fairly convinced that it was changed due to a bug
in the Object Inspector (i.e., double clicking on one item, and it
accidentally changes another).
There are no accidents in that scenerio. The only way it could have been
changed in that manner is if changing something else explitically set the
SimplePanel property to false programmably. Scanning through the entire VCL
source, there is no such action performed, so you must have set it yourself
and just weren't paying attention to what you were doing.
Gambit
 

Re:A new method of displaying hints?

Remy Lebeau (TeamB) wrote:
Quote
"David Erbas-White" < XXXX@XXXXX.COM >wrote in message
news:4025a8d2$ XXXX@XXXXX.COM ...


>It's my own code's responsibility to check this, but it's not
>the responsibility of the VCL to check if SimplePanels can
>be set to a state that is illegal?


It is your own responsibility to make sure the Count is greater than 0
before you try to access an item in the collection. The same goes for any
list and collection in general.

Again, you're completely ignoring the responsibility of the VCL to allow
SimplePanel to be set to an illegal state.
Quote

>I'm fairly certain I know which one you use...


Actually, I would do this:

if( MyForm)
{
MyForm->Caption = "My Caption";
MyForm->Show();
}

It also depends on the context in which MyForm is being used, and whether I
needed to know whether it had been constructed yet or not.

And if you do the above, you are assuming that nothing would intervene
between the two statements to delete MyForm. This, in general, would be
a valid assumption, but it is just as valid for me to assume that the
VCL should not allow SimplePanel to be set to an illegal state.
Quote

>I did not (intentionally) change the SimplaPanel property in the
>form, and I'm fairly convinced that it was changed due to a bug
>in the Object Inspector (i.e., double clicking on one item, and it
>accidentally changes another).


There are no accidents in that scenerio. The only way it could have been
changed in that manner is if changing something else explitically set the
SimplePanel property to false programmably. Scanning through the entire VCL
source, there is no such action performed, so you must have set it yourself
and just weren't paying attention to what you were doing.

In trying to find the problem indicated here, I found many instances
(using google) where properties were changed 'unexpectedly'. I have run
into this myself on a few occasions. I have NOT been able to find a
consistent way to reproduce it, but I can assure you that it DOES
happen. This, in itself, is a problem, but when you combine it with the
fact that properties can be set to an illegal state, the Object
Inspector becomes dangerous.
David Erbas-White
Quote

Gambit


 

Re:A new method of displaying hints?

"David Erbas-White" < XXXX@XXXXX.COM >wrote in message
Quote
Again, you're completely ignoring the responsibility of the
VCL to allow SimplePanel to be set to an illegal state.
And you are ignoring the fact that such a thing is actually irrelevant. If
your own code is not smart enough to make sure it is working with valid
states, then that is your own code's fault regardless of whether the VCL
handles it or not.
Quote
And if you do the above, you are assuming that nothing
would intervene between the two statements to delete
MyForm.
Forms should never be used or accessed outside of the context of the main
VCL thread. As such, it is not possible to delete the form in between the
two statements if they are next to each other. To do what you suggest, the
code would have to be doing something like the following:
MyForm->Caption = "My Caption";
DoSomething();
MyForm->Show();
void DoSomething()
{
delete MyForm;
}
In which case, again it is the responsibility of the code to make sure it is
set up to perform valid operations:
MyForm->Caption = "My Caption";
DoSomething();
if( MyForm )
MyForm->Show();
void DoSomething()
{
delete MyForm;
MyForm = NULL;
}
Gambit