Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have a form class TfrmWelcome and I want to be able to dynamically add
a memo to it when a button is clicked in the main part of the form (frmWelcome.MainPanelSourceEditor).
My unsuccessful attempt at some code is below. I get the error
"undeclared identifier WelcomeMemo". How could I get this to compile and work?
type
WelcomeMemo : TMemo;
end;
implementation
procedure SetHelpWelcome;
begin
WelcomeMemo : TMemo.Create(frmWelcome);
with TMemo(FindComponent('WelcomeMemo')) do
begin
Parent := frmWelcome.MainPanelSourceEditor;
If what you are trying to do is to add a memo to your frmWelcome at runtime, a better (but still not very good) way to do it would be like this:
procedure SetHelpWelcome;
var
WelcomeMemo : TMemo;
begin
WelcomeMemo := TMemo.Create(frmWelcome);
WelcomeMemo.Parent := frmWelcome.MainPanelSourceEditor;
// set any other properties of WelcomeMemo here.
end;
This avoids the with (which you should never use especially if you are a beginner) and the completely avoidable FindComponent to find something you don't need to find in the first place if you capture it by the assignment to the WelcomeMemo local variable.
But that's still a fairly naff way of doing what you want. It would be better to have the WelcomeMemo as a member of your form, and define a method of the form to create and initialise it; you could then call the method from the OnClick handler of the button you want to use to create it. Something like (untested)
TfrmWelcome = Class(TForm)
private
fWelcomeMemo : TMemo;
procedure SetUpWelcomeMemo;
[...]
end;
procedure TfrmWelcome.SetUpWelcomeMemo;
begin
if fWelcomeMemo <> Nil then exit; // to avoid creating it more than once
fWelcomeMemo := TMemo.Create(Self);
fWelcomeMemo.Parent := Self.MainPanelSourceEditor;
// set any other properties of WelcomeMemo here.
end;
Apart from anything else, this avoids the memo's owner being set to the specific TfrmWelcome instance frmWelcome, which is an accident waiting to happen because it may not be the instance you are actually wanting to work with.
But like #J.. said, you really need to look at a beginner's tutorial if you are blundering around using trial and error the way it sounds like you are.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have created a custom form, to resamble a dialog. Then I overloaded the MessageDlg function in a special unit to call this form. Great, its working A-OK.
When I call the form, it's shown as a Modal, and inside this modal I need the caller form name.
Example: FormA calls unit U_Functions that overloads MessageDlg. Then U_Functions calls FormDLG and it's shown. Inside FormDLG I execute function "GetParentFormName" and it returns "FormA".
I already tried GetForegroundWindow, but it returns the same thing as Self. Self.Parent is null. How can I get the modal caller's reference(TForm)?
Example of flow
FormA:
procedure TFormA.Button1Click(Sender: TObject);
begin
MessageDlg('Call Dialog', mtWarning, [mbOK], 0);
end;
U_Functions
function MessageDlg(Msg: String; Icone: TMsgDlgType; Botoes: TMsgDlgButtons): Integer; overload;
begin
Result := FormDialog.fn_ShowMessage(msg, Icone, Botoes);
end;
FormDialog
function FormDialog.fn_ShowMessage(Msg: String; Icone: TMsgDlgType; Botoes: TMsgDlgButtons): Integer;
begin
// Get FormA's name
end;
Remy Lebeau's approach (Screen.ActiveForm) accomplished exactly what I was looking for. Thank you so much for your time.
Since there's a middle unit, it gathered the callers name, and sent via parameter to the third form (Dialog).
I am currently working on one a little bit complex application and I have found one problem. I am going to try to reduce complexity of my application into one simple application, just for example. The point is, that I have 16 regions and there is variables and procedures for each one of them. Each procedure have to be universal for each region. Currently I resolve that by writing one "if" on the beginning of the procedure and them copy that 15 times bellow and changing it little bit, because for each region it makes difference just in a few words. So I have to change that word in each one of them. This makes the code sooo unclear and it is wasting of time. Is there any way, how to write those 16 "ifs" into one? Using something like template or something like that?
Example application:
key code:
procedure TForm1.WriteItem;
var item:integer;
begin
if currentFile='FirstFile' then begin
Seek(FirstFile,filesize(firstfile)-1);
read(FirstFile,item);
inc(item);
write(FirstFile,item);
end;
if currentFile='SecondFile' then begin
Seek(SecondFile,filesize(SecondFile)-1);
read(SecondFile,item);
inc(item);
write(SecondFile,item);
end;
end;
full version:
https://drive.google.com/drive/folders/0BzhR4bZa5iBuazJuX0FWQzBXcHM?usp=sharing
I am guessing that FirstFile, SecondFile and so on are all of type TFile or some descendant of it, so the first change I would make would be to make 'currentFile' of the same type (or ancestor of it). Then, instead of setting your currentFile as a string, you put something like
currentFile := FifthFile;
for instance.
Then your procedure just becomes
procedure TForm1.WriteItem;
var item:integer;
begin
Seek(CurrentFile,filesize(CurrentFilefile)-1);
read(CurrentFile,item);
inc(item);
write(CurrentFile,item);
end;
Better, though, you could pass your file as a parameter, like this
procedure TForm1.WriteItem( const CurremtFile : TYourFileType);
var item:integer;
begin
Seek(CurrentFile,filesize(CurrentFilefile)-1);
read(CurrentFile,item);
inc(item);
write(CurrentFile,item);
end;
Edit
As pointed out in the comments, this procedure does not required any object variables (although your real procedure may). You can make this independent of any object one of two ways: Either move the function out of the object altogether
procedure WriteItem( const CurremtFile : TYourFileType);
or make it a class procedure
class procedure TForm1.WriteItem( const CurremtFile : TYourFileType);
As a general principle I prefer the latter method, but I would probably move it to a different class specifically designed to handle this type of functionality (not my form).
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I can do this in other languages that I use. For instance I can do this in PHP when needed for web app creation, but here is what I want to do and can't find a solution:
I want to define an interface say:
unit myBigUnit;
interface
uses someUnits;
type
TsampleType = class
someVar: Integer;
someOtherVar: Integer;
someObj: TneatObj;
procedure foo;
function bar : String;
procedure foobar(a: boolean);
All this in one file. Now I want two files that implement this interface or at least know about it. In php I can just say
class blah implements thisInterface
but I can't find an equivalent in Delphi. What I am trying to do is implement this in one unit while in another one I just want it to know about these functions/procedures/et al so I can then call them from there. I couldn't care less about how it is implemented. I thought this was the whole point of having interfaces and separating them from implementors?
How do I do this in Delphi?
You need to use an actual interface, eg:
type
IsampleType = interface
procedure foo;
function bar : String;
procedure foobar(a: boolean);
end;
An interface can only have methods and properties, not variables.
You can then implement the interface in your classes as needed, eg:
type
TMyClass = class(TInterfacedObject, IsampleType)
public
someVar: Integer;
someOtherVar: Integer;
someObj: TneatObj;
procedure foo;
function bar : String;
procedure foobar(a: boolean);
end;
var
Sample: IsampleType;
begin
Sample := TMyClass.Create;
// use Sample as needed...
end;
Delphi interfaces are reference counted. TInterfacedObject handles the reference counting for you. It automatically frees the object when its reference count falls to 0.
You can find more details in Delphi's documentation:
Object Interfaces Index
Then you should use an Interface:
...
type
IsampleType = Interface
.....
an implement this in your classes:
type
TIntfType = class(TInterfacedObject, ISampleType)
....
and the details you will find with F1 in Delphi...
This question already has answers here:
Reference object instance created using "with" in Delphi
(9 answers)
Closed 8 years ago.
Is there a way to refer to a dinamicaly created object in "with" segment to let's say pass this object somewhere else?
I have a simple code like this
var
someObject: TSomeObject;
begin
someObject := TSomeObject.Create;
try
someObject.someProperty := 1;
SomeOtherProcedure(someObject);
finally
someObject.Free;
end;
end;
there is a variable that is being passed to SomeOtherProcedure. Now I am trying to drop someObject variable and use "with" segment to have something like this
begin
with TSomeObject.Create do
try
someProperty := 1
SomeOtherProcedure( < what goes here ?? > );
finally
Free;
end;
end;
I do not want to have something like
var
someObject: TSomeObject;
begin
someObject := TSomeObject.Create;
with someObject do
(...)
Is this even possible to refer to an object that is being created in "With"?
Thanks!
No you can't and use of the With statement (especially in cases like the one you illustrated) should be avoided as it can cause more problems than it solves.
Consider the following code :-
Procedure TMyForm1.btnProcessClick(Sender : TObject);
Begin
With TMyForm2.Create(Nil) Do
Begin
Try
Caption := 'Processing....';
DoSomeProcessing;
DoSomeMoreProcessing;
Finally
Free;
End;
End;
End;
Supposing TMyForm1 also has a method called DoSomeProcessing? Which one will get called? Which form caption will change to say 'Processing...'? It's not immediately clear the method that will be called. The situation becomes even more complicated when you start referencing properties. Don't expect the Debugger to be able to help you either. Now all of this might not cause you too much of an issue now when the code is still fresh, but what about 6 months or a year later? You have caused yourself a whole load of grief all to save yourself a bit of typing.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I would like to build a program which lets lyrics of a song run over the screen. Something like this:
http://www.youtube.com/watch?v=kIAiBvD9njM
Can you help me?
Algorithm:
pushes the marker to the right of a line fitting the music
lets a line above the current line disappear
inserts a new line above the current line
What is needed?
lyrics of the song (line per line)
time to text data? (when does a line start/end)
Some approaches would help me a lot. Pseudo-code or even Delphi code of any part would be fantastic.
If you're interested in karaoke code in pascal, make sure to take a look at UltraStar Deluxe.
It's a super slick and very popular karaoke application. The project is active and it's open source. It can be compiled to various platforms with FPC. You can compile it from both Delphi and Lazarus.. nice.
http://ultrastardx.sourceforge.net/
My neighbours thought that my dog was their worst nightmare until I found this program.
See it in action: po-po-po-pokerface po-po-pokerface.. mum mum mum mah! :)
let's assume you have a text file with the text to be shown and the annotated time of when to hightlight it (kind of a subtitles file, for example the standard proposal w3c timed text (http://www.w3.org/AudioVideo/TT/) or the SUB - Movie subtitle file format in use by several media players.
Your program must first read and parse the text file, and decode the annotated time. Insert it in a stringlist called Subtitles which items would also keep objects similar to this one
type tSubtitle = class
num : integer;
prevTime, fromTime : tdatetime;
toTime, nextTime: tdatetime;
text: string;
end;
You might want to extend the object to hold some highlighting attributes as well.
Then you just need to display those objects synchronized with a timer.
procedure TForm1.Timer1Timer(Sender: TObject);
var rt : TDateTime;
done:boolean;
si,st,sb:integer;
s:string;
begin
rt:=now-startTime;
st:=0;
sb:=subtitles.Count; // binary search the subtitle for the current time
repeat
si:=(st+sb) div 2;
s:=TSubtitle(subtitles.Objects[si-1]);
done:= ((t>=s.prevTime) and (t<=s.nextTime));
if not done then
begin
if t>s.prevTime then st:=si
else if t<s.nextTime then sb:=si;
if st=sb then done:=true;
end;
until done;
// do what you want with s
end;
Another option would be to create your own markup that you parse for that contains both the text and the delay timing. While a timer would work, the problem is that its not going to be accurate enough over time to give you reliable results since its fired based on messaging. Instead, I would perform triggers based on how far from the beginning of the music file you want the event to occur. This also allows the system to catch-up if some other app blocking process gets in the way and should help keep things in sync.
Something as simple as:
00:00:15;LYRIC;This is lyric line 1
00:00:18;FADEOUT
you then can parse this into list of appropriate objects which take the appropriate actions.
You should create a new class based on TGraphicControl/TCustomControl(anything with a canvas) and add a string property, now you have to create a timer as a private variable with it's interval value published through your class, something like so
...
type TLyricViewer = class(TGraphicControl)
private
FTimer : TTimer;
FLyric : string;
FBitmap : TBitmap;// offset bitmap on which you draw
// some more variables to store paint information
private
procedure OnNextWord(Sender: TObject);// assign this to FTimer.OnTimer event
public
constructor Create(AOwner: TComponent);
destructor Destroy; override;
public
procedure StartLyric;
procedure StopLyric;
procedure Paint; override;
published
property WordInterval : Integer|Cardinal
read GetWordInterval write SetWordInterval;
end;
...
procedure TLyricViewer.Paint;
begin
// here is where the magic happends
end;
constructor TLyricViewer.Create(AOwner: TComponent);
begin
// create timer, bitmap and set default properties
end;
destructor TLyricViewer.Destroy;
begin
// free and nil the timer and bitmap
inherited Destroy;
end;
The rest is up to you, after all your the one getting paid, work for it :)