Running a Delphi program without user-triggered events.

I am very new to Delphi and visual programming in general.

I work for a medical claims clearinghouse. We supply our clients with a Windows-style claims editor. The claim files they edit often need filtering for invalid characters or data scrubbing before loading the files into the editor. Right now I'm doing this with Pascal programs that I have created. The claims editor allows me to preload the name of the Pascal scrub program into a 'preprocess' field and then when the user selects a claim file to edit at his site, the scrubbing appears to be done from within the Windows editor program; that is, except for an unimpressive looking Dos window that opens up until the scrubbing is done.

I want to do these scrubs in Delphi and have a professional looking Delphi form appear that shows the name of the file with a message that it is being processed. Then, just have the form disappear when its done, all without any user intervention.

The problem I am having is that I don't know how to call a Delphi program, show the form and information, and then have it run straight through until its done without stopping at some point and requiring user intervention to finish.
I tried using the form event 'OnActivate' to trigger the scrub procedure, and the scrub worked fine, but the problem is the form doesn't show until the program is finished running. Is there another way to start the scrub procedure after the form appears without a user-triggered event?

Sorry for the length of this question.
At some point, I'd like the entire claims editor to be written in Delphi.
davelawAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

X_KaliburCommented:
Dave,

If you placed your "scrubbing" code in the OnActivate procedure, then it will work fine, the only thing that is happenening, is that the program is executing so fast, it does not have time to display the form, before it is finished.
There is one way to fix this, although it is to forcebly slow down your program, by wasting CPU cycles (for example, using the "Sleep" procedure). I would actually discourage doing this, because if your program is being run on a slow computer, which will have time to process the window and everything, then it will unnecesarily slow down the execution.

The other way i was thinking of doing this, is to just forget about teh form altogether. If it seems that your program is running fairly quickly (and isnt very complex), then remove the form unit altogether, and place your "scrubbing" code in the main program unit's code window.

See if thats what you want first, though...Its no good chaning something that works for something that is pain to assemble.

HTH,

-x
0
kretzschmarCommented:
hi davelaw,

maybe it helps, if you place sometimes the line

Application.Processmessages;

in your code,
so that the app get time to paint the form and update a progressbar(for example)

meikl
0
AttarSoftwareCommented:
Or, try this:

below the uses clause in your main unit, add:

const
  WM_SHOWN = WM_USER + 1 ;

then in the private section, add:

  procedure WMSHOWN( var msg : tMessage ) ; message WM_SHOWN ;

then in the implementation, add:

Procedure tForm1.WMSHOWN( var msg : tMessage ) ;
begin
  { Do the processing here... }
  Close ;
end ;

and as the last line in your OnShow event , add:

  SendMessage( handle, WM_SHOWN, 0, 0 ) ;

This will mean that your processing will start after the form has shown, and is better than a sleep function, as it will not lock the system...

Good luck,

Tim.
0
Cloud Class® Course: Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

nricoCommented:
A "dirty" but effective way would be:

Add a TTimer to your form, set the interval to 5 or something (something short), and set "enabled" to True, then create an OnTimer event.

Assuming the TTimer is called "Timer", this is what the event should look like:

Procedure TForm1.TimerTimer(Sender:TObject);
Begin
  If Not Form.Visible Then Exit;
  Timer.Enabled:=False;
  ...
  { do scrubbing here }
  ...
  PostMessage(Handle,WM_QUIT,0,0);
End;

This will:
a) wait for the form to become visible before the scrubbing starts
b) disable the timer so the scrubbing does not get interrupted
c) scrubs ;-)
d) posts a message WM_QUIT to the form, so the form terminates itself and the application once it receives one.

0
nricoCommented:
I have to say Tims solution is more elegant... :-)
0
AttarSoftwareCommented:
*curtsey* ;OD

Tim.
0
florisbCommented:
An I missing something in the question with all these complex answers? Sorry if I miss something, but I try...

Use the OnShow event of the form to perform special processing when the form is shown (that is, when the form’s Visible property is set to True), so that's the event you need.

One but, people can minimize the form and show it again, so:

With this you define a global var: FirstTime: Boolean.

In the Form create you make this boolean true.

In the OnShow Event you only start your crubbing procedure when the boolean is true and you make the global boolean false.

Scrubbing will happen only once now, and after your form is visible!


Hmmm, I didn;t take time to read all the comments totally. But I might have something to add. You could keep your scrubbing .exe as-is (without dos window?) and start it from Delphi.

You can run an other executable from a Delphi application, and return to this application when the other one is finished, you do this with:
CreateOK := CreateProcess(nil, PChar(UMSService2), nil, nil,False,
GROUP+HIGH_PRIORITY_CLASS,nil, nil, StartInfo, ProcInfo);
if CreateOK then //check to see if successful
  WaitForSingleObject(ProcInfo.hProcess, INFINITE);

Easier, but the old windows way:
WinExec(UMSService2, SW_HIDE); //start it hidden...

You should check the help a bit for this... ...this is not my expertice...

Good luck,
Floris.
0
AttarSoftwareCommented:
> An I missing something in the question with all these complex answers?

Heh, whereas yours looks simple! ;O)

What is so complex about sending a message to the form?

And why not put your answer as a comment, and allow davelaw to decide which he wishes to go with?

Tim.

PS:  Sorry if I sound stroppy...Friday evening, and my server app just developed a huge bug...
0
bogieman_Commented:
You don't even need to set the timer's interval property to 5, just 1.  It will only start after the form has been shown.
0
X_KaliburCommented:
Hmm..

Complex answers look like the most common option here...

The more I trhink about it, though, it seems more logical to omit the form altogether (if that's ok with you), because it seems that the scrubbing process is working relativly quickly anyway...
In this manner, the user wouldnt even know that an external program has been called, making the whole process seem very fluid!

-x
0
X_KaliburCommented:
One other thing that we have to consider is that DaveLaw is:
"very new to Delphi and visual programming in general."

All these complex solutions will bedazzle the poor fellow...Lets try to keep things at an easier level of understanding and implementation.

-x
0
florisbCommented:
Hi DaveL,

I meant OnCreate, next should be copy paste-able in unit of new Delphi  project. Add a statusbar and a progressbar to the form and there you are. Why not copy-paste the pascal too... ...some editting maybe.

You can by the way offcourse also use Delphi to create a formless application, in the 'old-fashioned' way; one long source with a main. Can inlude sample. Adding a form (progress&status) to this application does the same trick.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  FirstTime: Boolean;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
//this pocedure is only called once.
begin
FirstTime := true;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
if FirstTime then
  begin
  FirstTime := false;
  //call a formless version of you scrubbing application here, or insert code / calls.
  //..
  showMessage('only once after form visible');
  end;
end;

end.


>What is so complex about sending a message to the form?
Eeeh Atar, it's just a bit overdone. Why?



Saterday!
:-)


0
davelawAuthor Commented:
Wow! This is the first question I've ever submitted and I'm overwhelmed by the response. This is great! I'm a bit baffled by the point system though.

I should offer some additional information, as I see some commenters are suggesting that I use no form at all. And they are correct that some of the files that are run may only be 1 or 2 megs and are finished very quickly and it would only slow things down to show a form.

However, some other files may get as big as 15 or 20 megs, and may be scrubbed twice, once for invalid characters and once for reformatting of the data. In this case, you might have an awkward 10 second period where the program appears to be doing nothing, plus no message to let you know what's going on.

I must confess that in my testing, I've only used the smaller files, so far. My employer is not a Delphi owner, so I've been working on this project at home and didn't have any example files that large. My intent is to develop this project and convince her that Delphi should be in our arsenal.
0
kretzschmarCommented:
hi davelaw,

taking x_caliburs suggestion in his/her frist comment,
i created following sample, which should show you how could done

//a sample
//used the OnActivate-event
//instead of sleep do your processing;

var First : Boolean = True;

procedure TForm1.FormActivate(Sender: TObject);
begin
  if First then
  Begin
    First := False;
    Application.ProcessMessages;
    ProgressBar1.Position := 10;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 20;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 30;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 40;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 50;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 60;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 70;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 80;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 90;
    sleep(500);
    Application.ProcessMessages;
    ProgressBar1.Position := 100;
    Application.ProcessMessages;
    Application.Terminate;
  end;
end;

meikl
0
X_KaliburCommented:
Dave,

Ja...After reading your last comment, then it makes sense to have a form, so just omit my suggestion about that...

I think the code which meikl has demonstrated is perfect for your cause, at this stage...You just have to make sure that you have the "Application.ProcessMessages" line after one part of your scrubbing code, so that it can get that process done.

EG: (Based on Meilk's suggestion)

var First : Boolean = True;

procedure TForm1.FormActivate(Sender : TObject);
begin
  if First Then
    Begin
      First := False;  

      {Put a small chunk of the code here}
      ProgressBar1.StepBy(20)
      Application.ProcessMessages;

      {Put a small chunk of the code here}
      ProgressBar1.StepBy(20)
      Application.ProcessMessages;

      {Put a small chunk of the code here}
      ProgressBar1.StepBy(20)
      Application.ProcessMessages;

      {Put a small chunk of the code here}
      ProgressBar1.StepBy(20)
      Application.ProcessMessages;
    end;
end;


Actually, after thinking about it, I doubt you would even need the "Sleep(500);" line, because "Application.ProcessMessages" will automatically allow the form to be updated, by setting the priority of the application's main thred (is that right?).

HTH,

-x
0
davelawAuthor Commented:
Tried this method and ran about a 5 meg file which took about 4 seconds overall but the form did not appear until the run was complete.
0
florisbCommented:
I'm still thinking that this is a bit overwhelming/complex response for a simple problem, whatever, we all seem to have the time...:-)

I still don't know how you call your scrubbing code from Delphi, but if you insert it the code from my last comment, the form should be visible first... ....eeeeh?

I you call the proces for your scrubbing code, it will be a process that runs to to end, so using a progessbar will be more complicated.
If you use your scrubbing code in Delphi, the code from the other comments add a nice GUI solution for the form problem, eeh?

Floris.
0
davelawAuthor Commented:
To FlorisB:
In answer to your question about how I am running the program, I inserted the entire (short) code right into FormActivate procedure.

When I ran the program, just the title bar of the form appeared, and then, apparently, the scrub code took over for the duration of its run. When the scrub code finished, I saw the form flash on screen for a milisecond and the run was over.

To All:
At that point, I considered Meikl's advice that the app needed time to paint the form. So, I inserted the line "Application.ProcessMessages;" as the first line in the FormActivate procedure. After that, it worked perfectly. That's exactly what I was looking for. Meikl's advice was the key.

I will continue to look at some of the other comments, but this appears to be the simplest solution. Thanks to all of you for a great experience! I'll certainly be back when I have a another problem to solve.   DaveLaw

0
kretzschmarCommented:
hi davelaw,

glad that this helps :-)
let me know,
if i should post an answer,
after you've looked over the other comments.

if there a better one solution than my,
then force this expert to answer the q
for closing this thread

meikl ;-)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
davelawAuthor Commented:
Although it was a relatively simple solution, it was brief and exactly what was needed. Its nice to know there's a place one can go to tap such expertise. Thanks.  DaveLaw
0
florisbCommented:
My option with form.visible := true should also work... ...I thought.

ProcessMessages works for waiting processes...
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.