Hi!
How can I show LabelCaption Text for a few seconds and then clear it automatically?
And how can I let the program wait for finishing an event before going to the next event or executing piece of code?
Hi!
How can I show LabelCaption Text for a few seconds and then clear it automatically?
And how can I let the program wait for finishing an event before going to the next event or executing piece of code?
Hello! To do that you should either use TUiState.Update
or TCastleWindowsBase.OnUpdate
or even TCastleLabel.Update
. E.g.
TDisappearingLabel = class(TCastleLabel)
public
Timeout: Single;
procedure Update(const SecondsPassed: Single;
var HandleInput: boolean); override;
end;
procedure TDisappearingLabel .Update(const SecondsPassed: Single;
var HandleInput: boolean);
begin
inherited;
Timeout -= SecondsPassed;
if Timeout < 0 then
Exists := false;
end;
This will make the label disappear after Timeout
seconds.
That depends on what are you trying to do. Overall you can just use the same method as above - through Update
. Or you can have a similar approach with âeventsâ e.g.
TDisappearingLabel = class(TCastleLabel)
public
OnDone: TNotifyEvent;
function Press(const Event: TInputPressRelease): Boolean; override;
end;
function TDisappearingLabel.Press(const Event: TInputPressRelease): Boolean;
begin
Result := inherited;
if Event.Key = keyEnter then
begin
Result := true;
Exists := false;
if Assigned(OnDone) then
OnDone(Self);
end;
end;
Thanks!
It tried the first one but it is confusing to me how to implement this in updating my current Label.
I have created a label TalkTextLabel.
So how can I make it display a text for a few seconds or make it dependent of the length of the text so larger lines are displayed longer?
TalkTextLabel.Text.Add(âtestâ);
TalkTextLabel.Update(); ??
That depends on how you are handling your current Label. The pseudocode above was given for the case when you create the label manually:
procedure TMyState.Start;
begin
inherited;
... (load and create other UI elements here) ...
MyLabel := TDisappearingLabel.Create;
MyLabel.Caption := Text;
MyLabel.Timeout := 5;
InsertFront(MyLabel);
end;
It will insert the MyLabel
in front of other UIs and will automatically call Update
on it - it will disappear in 5 seconds after Start
.
Youâll need a few additional improvements to have this âspecialâ TDisappearingLabel
available in the Castle Editor, so itâs easier to create it by code for now.
Thanks.
I am obviously doing something wrong here as I get Identifier not found âTimeoutâ error?
I have:
TDisappearingLabel = class(TCastleLabel)
public
Timeout: Single;
procedure Update(const SecondsPassed: Single;
var HandleInput: boolean); override;
end;
procedure TDisappearingLabel.Update(const SecondsPassed: Single;
var HandleInput: boolean);
begin
inherited;
Timeout -= SecondsPassed;
if Timeout < 0 then
Exists := false;
end;
procedure TalkLabel;
begin
TalkTextLabel := TDisappearingLabel.Create(Application);
with TalkTextLabel do
begin
Color := White;
Frame:= true;
FrameColor := White;
Outline := 2;
OutlineHighQuality := true;
BorderColor := Red;
Font.OutlineColor := Black;
FontSize := 18;
MaxWidth:= 500;
CustomFont := MyTextureFont;
Timeout := 5;
InsertFront(TalkTextLabel);
end;
end;
Make sure that TalkTextLabel
is declared as TalkTextLabel: TDisappearingLabel
.
However, note that procedure TalkLabel;
is not a procedure of some TUiContainer
(i.e. it doesnât know about the UI) - and therefore the next error you will get is InsertFront
not found.
To insert UI elements you need to insert them somewhere. This may be either TSomeUiState.InsertFront
(this is the recommended approach) or TCastleWindowBase.Controls.InsertFront
. I.e. your procedure must be aware of âwhere to insert the new labelâ.
As you are adding a lot of stuff by-hand youâll get a lot of help here from Castle Editor where you can properly insert the label and fine-tune its parameters in WYSIWYG way. Yes, defining a TDisappearingLabel
is a bit more complicated in this case, see: Editor | Manual | Castle Game Engine . You can look at a custom label properly defined for use with Castle Editor here : code/typinglabel.pas ¡ master ¡ EugeneLoza / Without Form and Void ¡ GitLab just instead of TypingSpeed
you will have your Timeout
.
Thanks. I had forgotten to declare TalkTextLabel as TDisappearingLabel.
Okay, it works!
But⌠only once. I cannot get the Text shown again once it disappears after 5 seconds.
Probably because TimeOut stays 0?
How can I reset this so that I can call the procedure again?
To show the text again you should reset the timeout and show the label again (Exists
property):
TalkTextLabel.Caption := 'Some new text';
TalkTextLabel.Timeout := 5;
TalkTextLabel.Exists := true; // because we just "disabled" it before
Thanks.
Almost there, but now every time I call this procedure the display time of the text / timeout is shorter?
procedure PlayerTalk;
begin
TalkTextLabel.Frame:= False;
TalkTextLabel.Text.Clear;
Window.Controls.InsertFront(TalkTextLabel);
TalkTextLabel.Timeout:= 5;
TalkTextLabel.Text.Add(âsome textâ);
TalkTextLabel.Exists := true;
end;
Hmmm⌠Iâm not 100% sure if this is the case, but as youâre using Exist
you shouldnât insert the label again by Window.Controls.InsertFront(TalkTextLabel);
. In other words - you insert it multiple times into Window.Controls
. Iâd expect it to crash But if it doesnât for some reason - it will indeed call Update
many times on the label, each time forcing it to disappear faster (1x, 2x, 3x, 4x - as many times as it was inserted into the controls, and as many times as Update was called on it).
Who said it did not crash?
But how can I avoid multiple InsertFront(TalkTextLabel)?
I removed it from the procedure and moved it to initial design part of the code (right after TalkTextLabel := TDisappearingLabel.Create(Application);
but then it did not show up at all.
Hmmm⌠thatâs probably the place where it should go. But why doesnât it show up?
Maybe some other UI element covers it? Like background image? What exactly do you mean by âinitial design part of the codeâ - you create some other UI there, right?
Or as the last resort - itâs not a good and clean code but it should do the job:
procedure PlayerTalk;
begin
if TalkTextLabel = nil then
begin
TalkTextLabel := TDisappearingLabel.Create(Application);
Window.Controls.InsertFront(TalkTextLabel);
end;
TalkTextLabel.Frame:= False;
TalkTextLabel.Text.Clear;
TalkTextLabel.Timeout:= 5;
TalkTextLabel.Text.Add(âsome textâ);
TalkTextLabel.Exists := true;
end;
and obviously remove TalkTextLabel := TDisappearingLabel.Create(Application);
from âinitial design part of the codeâ - this way the label will be created when PlayerTalk
is called for the first time.
Just a quick addition to what @eugeneloza writes: Indeed you cannot insert the same instance of TCastleUserInterface
(like TCastleLabel
) multiple times to an UI hierarchy. It may not crash, but you will definitely see a warning like
U: Inserting to the UI list (InsertFront, InsertBack) an item that is already a part of other UI list: ..... The result is undefined, you cannot insert the same TCastleUserInterface instance multiple times.
(the warning will be in log, Logging | Manual | Castle Game Engine )
Indeed, the most probable result is that time will âseemâ to fly faster, as the control will have Update
virtual method called many times.
So you should either toggle the Exists
property (and do not add the same instance many times), or you should create a new instance of TDisappearingLabel
each time.
Thanks!
So here is the final procedure.
And I changed TimeOut time depending on the length of the text, so longer testlines are displayed longer as they take more time to read, obvious.
procedure PlayerTalk;
begin
if TalkTextLabel = nil then
begin
TalkTextLabel := TDisappearingLabel.Create(Application);
Window.Controls.InsertFront(TalkTextLabel);
end;
with TalkTextLabel do
begin
Color := White;
Font.OutlineColor := Black;
FontSize := 18;
MaxWidth:= 500;
CustomFont := MyTextureFont;
Frame:= false;
Text.Clear;
TimeOut := Length(NPC[Location.NPC.NR].Appearance.Description);
Timeout := TimeOut/15;
Text.Add(NPC[Location.NPC.NR].Appearance.Description);
Exists := true;
end;
end;