Jump to content
troller

Form (Event Handling)

Recommended Posts

Hello,

I was wondering how it is possible to make a form that users can interact with.

I mean, i made a form with some basic things, but how can i make the script check, if a button was pressed or if a box was ticked and stuff?

Didnt find any tutorial about this :(

 

Thanks

Link to comment
Share on other sites

I've been struggling with that as well. I did find 2 tutorials with a small amount of information that you might find helpful. Unfortunately things seem to have pretty much died down here and there isn't much information that isn't woefully outdated or lacking of in depth explanations. Here are those links. Hope they help.

 

https://villavu.com/forum/showthread.php?t=5165

 

http://www.freddy1990.com/forums/index.php?topic=69.0;wap2

  • Confused 1
Link to comment
Share on other sites

I had already read the first one but i didn't understand anything.

The second one you sent was really useful as i learned handling some stuff.

I Still dont know though, how to make changes in the script through a form(e.g. change a boolean by ticking-unticking a box)

Link to comment
Share on other sites

Afraid I can't help any further as I'm also a beginner with forms. There is so much undocumented stuff that I think a lot of trial and error and searching will be required for those of us that inherently dont know what to do. I'd intended to use the form as a 'pause' feature in my script and displaying various game states, and then once I got that handled dig into the same issues you are having where I could alter booleans for various script issues. To be honest, other than stumbling upon the second tut I think that you are further along than me in figuring it out.

Link to comment
Share on other sites

It is like learning something new on your own which is actually not possible. Even by trial and error, if you dont have a clue, you cant move further....

Found this http://www.scar-divi.com/oldmanual/

Scroll down till the end and there is an example.

Freddy also states somewhere above the following "For more help on properties and methods of individual classes consult Delphi help or internet search"

So this may be the reason that there is no documentation for these. I will search the whole thing and answer back if i find something.

(2 noobs = 1 pro :D)

  • Confused 1
Link to comment
Share on other sites

I hate to see anyone stuck. Here is a basic example generated using SCAR's built-in form editor. I added some events to demonstrate and read the properties after the form closes. (You could read the properties while the form is still open in the various events).

 

Note out of laziness I pointed all the controls to the same event but you could write a separate proc for each control.

 

program New;

// Generated using SCAR's built-in form designer and adding events after the
// fact.

type
 TForm1 = record
   Form1: TForm;
   Label1: TLabel;
   Button1: TButton;
   Edit1: TEdit;
   CheckBox1: TCheckBox;
   RadioButton1: TRadioButton;
   ComboBox1: TComboBox;
   Memo1: TMemo;
 end; 

var
 Form1: TForm1;

procedure OnClickEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnClick> Event.');
end;

procedure OnEnterEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnEnter> Event.');
end;

procedure OnExitEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnExit> Event.');
end;

procedure OnChangeEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnChange> Event.');
end;

procedure OnDropDownEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnDropDown> Event.');
end;

procedure OnCloseUpEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnCloseUp> Event.');
end;

procedure OnSelectEvent(Sender: TObject);
begin
 Form1.Memo1.Lines.Add(Sender.ClassName + ': <OnSelect> Event.');
end;

procedure Form1_Init;
begin
 with Form1 do
 begin
   Form1 := CreateForm;
   Label1 := TLabel.Create(Form1);
   Button1 := TButton.Create(Form1);
   Edit1 := TEdit.Create(Form1);
   CheckBox1 := TCheckBox.Create(Form1);
   RadioButton1 := TRadioButton.Create(Form1);
   ComboBox1 := TComboBox.Create(Form1);
   Memo1 := TMemo.Create(Form1);
   with Form1 do
   begin
     Left := 435;
     Top := 179;
     Caption := 'Form1';
     ClientHeight := 202;
     ClientWidth := 304;
     Color := clWindow;
     Font.Charset := DEFAULT_CHARSET;
     Font.Color := clWindowText;
     Font.Height := -11;
     Font.Name := 'Tahoma';
     Font.Style := [];
     OldCreateOrder := False;
     PixelsPerInch := 96; 
     // Any properties set on the form will "flow down" to child components.
     ShowHint := True;
   end;
   with Label1 do
   begin
     Parent := Form1;
     Left := 12;
     Top := 44;
     Width := 25;
     Height := 13;
     Caption := '&Label';
     FocusControl := Edit1; 
     Hint := 'This is a TLabel. Try pressing <Alt-L> to see shortcut key and FocusControl in action.'; 
     OnClick := @OnClickEvent;
   end;
   with Button1 do
   begin
     Parent := Form1;
     Left := 6;
     Top := 9;
     Width := 75;
     Height := 25;
     Caption := 'Button';
     TabOrder := 0;  
     Hint := 'This is a TButton';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
   end;
   with Edit1 do
   begin
     Parent := Form1;
     Left := 48;
     Top := 40;
     Width := 72;
     Height := 21;
     TabOrder := 1;
     Text := 'Editbox';
     Hint := 'This is a TEdit. Try pressing <Alt-L> to see the TLabel''s shortcut key in action.';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
     OnChange := @OnChangeEvent; 
   end;
   with CheckBox1 do
   begin
     Parent := Form1;
     Left := 169;
     Top := 13;
     Width := 97;
     Height := 17;
     Caption := '&CheckBox';
     TabOrder := 2;
     Hint := 'This is a TCheckBox. Try pressing <Alt-C> to see shortcut key in action.';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
   end;
   with RadioButton1 do
   begin
     Parent := Form1;
     Left := 169;
     Top := 35;
     Width := 113;
     Height := 17;
     Caption := 'RadioButton';
     TabOrder := 3;
     Hint := 'This is a TRadioButton.';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
   end;
   with ComboBox1 do
   begin
     Parent := Form1;
     Left := 169;
     Top := 56;
     Width := 116;
     Height := 21;
     Style := csDropDownList;
     TabOrder := 4;
     Text := 'ComboBox';
     Items.Add('ComboBox');
     Items.Add('Line 2');
     Items.Add('Line 3');
     // This must come *AFTER* defining items or it doesn't work.
     ItemIndex := 0;
     Hint := 'This is a TComboBox.';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
     OnChange := @OnChangeEvent;
     OnDropDown := @OnDropDownEvent; 
     OnCloseUp := @OnCloseUpEvent;
     OnSelect := @OnSelectEvent;
   end;
   with Memo1 do
   begin
     Parent := Form1;
     Left := 6;
     Top := 88;
     Width := 276;
     Height := 89;
     Lines.Add('Memo');
     ReadOnly := True;
     ScrollBars := ssVertical;
     TabOrder := 5;
     Hint := 'This is a TMemo. Notice how it is read only.';
     OnClick := @OnClickEvent;
     OnEnter := @OnEnterEvent;
     OnExit := @OnExitEvent;
//      OnChange := @OnChangeEvent;
   end;
 end;
end;

procedure Form1_SafeInit;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 ThreadSafeCall('Form1_Init', v);
end;

function Form1_ShowModal: Boolean;
begin
 Result := Form1.Form1.ShowModal = mrOk;
end;

function Form1_SafeShowModal: Boolean;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 Result := ThreadSafeCall('Form1_ShowModal', v);
end;

begin
 Form1_SafeInit;
 if Form1_SafeShowModal then
   WriteLn('Form returned modalresult ok');
 Writeln('Checkbox: ' + BoolToStr(Form1.CheckBox1.Checked));
 Writeln('RadioButton: ' + BoolToStr(Form1.RadioButton1.Checked));
 Writeln('Combobox: "' + Form1.ComboBox1.Text + '"');
 FreeForm(Form1.Form1);
end.

 

I'm baaaaaaack. No not really. Just popping in.

Link to comment
Share on other sites

haha oh yeah, that was what i was searching for!

Some questions....

1)On enter, on exit events, what's their purpose? I mean OnExit couldn't have been used as OnClose like

procedure FormClose(Sender: TObject; var Action: TCloseAction);
begin
 PreMain.Caption:= PreMain.Caption + '.';
 PreMain.ModalResult:= mrOk;
 //Action:=caFree;  //disabled this, caused only errors
end;

or do i miss something?

2)I tried to create tabs with TTabControl and added the tab names but still all the tabs show the same stuff... Do i miss something here too?

3)How can i ask the user enter a value (e.g a number or a string) and then make the script understand that String:='fff' or Integer:=50 ???

 

Thanks man

Link to comment
Share on other sites

Some people use OnExit to validate the field. (As users exits control check value. If invalid change it back to something valid). Or OnChange can be used. I just threw those all in there so you could see the timing of when things happen.

 

TTabControl is a bit odd. They aren't actually separate tabs like you would expect. Look into using TPageControl for that.

 

And see this example for parsing data:

type
 TForm1 = record
   Form1: TForm;
   PageControl1: TPageControl;
   TabSheet1: TTabSheet;
   Label1: TLabel;
   Label3: TLabel;
   Edit1: TEdit;
   TabSheet2: TTabSheet;
   Label2: TLabel;
 end;

var
 Form1: TForm1;

procedure EditChanged(Sender: TObject);
var
 Num: Integer;
begin
 with Form1.Edit1 do
 begin
   if (Length(Text) = 0) then
     Form1.Label3.Caption := 'Edit is empty.'
   else
   begin
     Num := StrToIntDef(Text, -999999);
     if (Num = -999999) then
       Form1.Label3.Caption := 'Edit contains string. Value: "' + Text + '"'
     else
       Form1.Label3.Caption := 'Edit contains number. Value: ' + IntToStr(Num);  
   end; 
 end;

end;
procedure Form1_Init;
begin
 with Form1 do
 begin
   Form1 := CreateForm;
   PageControl1 := TPageControl.Create(Form1);
   TabSheet1 := TTabSheet.Create(PageControl1);
   Label1 := TLabel.Create(TabSheet1);
   Label3 := TLabel.Create(TabSheet1);
   Edit1 := TEdit.Create(TabSheet1);
   TabSheet2 := TTabSheet.Create(PageControl1);
   Label2 := TLabel.Create(TabSheet2);
   with Form1 do
   begin
     Left := 651;
     Top := 241;
     Caption := 'Form1';
     ClientHeight := 202;
     ClientWidth := 304;
     Color := clWindow;
     Font.Charset := DEFAULT_CHARSET;
     Font.Color := clWindowText;
     Font.Height := -11;
     Font.Name := 'Tahoma';
     Font.Style := [];
     OldCreateOrder := False;
     PixelsPerInch := 96;
   end;
   with PageControl1 do
   begin
     Parent := Form1;
     Left := 0;
     Top := 0;
     Width := 304;
     Height := 202;
     ActivePage := TabSheet1;
     Align := alClient;
     TabOrder := 0;
   end;
   with TabSheet1 do
   begin
     Parent := PageControl1;
     PageControl := PageControl1;
     Caption := 'TabSheet1';
   end;
   with Label1 do
   begin
     Parent := TabSheet1;
     Left := 12;
     Top := 8;
     Width := 57;
     Height := 13;
     Caption := 'This is tab 1';
   end;
   with Label3 do
   begin
     Parent := TabSheet1;
     Left := 12;
     Top := 56;
     Width := 163;
     Height := 13;
     Caption := 'Edit contains text. Value = "Edit1"'; 
   end;
   with Edit1 do
   begin
     Parent := TabSheet1;
     Left := 12;
     Top := 28;
     Width := 121;
     Height := 21;
     TabOrder := 0;
     Text := 'Edit1';
     OnChange := @EditChanged;
   end;
   with TabSheet2 do
   begin
     Parent := PageControl1;
     PageControl := PageControl1;
     Caption := 'TabSheet2';
   end;
   with Label2 do
   begin
     Parent := TabSheet2;
     Left := 19;
     Top := 24;
     Width := 57;
     Height := 13;
     Caption := 'This is tab 2';
   end;
 end;
end;

procedure Form1_SafeInit;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 ThreadSafeCall('Form1_Init', v);
end;

function Form1_ShowModal: Boolean;
begin
 Result := Form1.Form1.ShowModal = mrOk;
end;

function Form1_SafeShowModal: Boolean;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 Result := ThreadSafeCall('Form1_ShowModal', v);
end;

begin
 Form1_SafeInit;
 if Form1_SafeShowModal then
   WriteLn('Form returned modalresult ok');
 FreeForm(Form1.Form1);
end.

Link to comment
Share on other sites

Thx Bixby

That helped a looooooot!

Please some more questions.

What is the difference between using records or not?(In form editor, "code" tab)

Also when im trying to make a multi line label(through form creator)(word wrapper true, autosize false) code viewer crashes....??

 

Found it...it crashes when the text exceed a specified amount of characters, dont know why happens though

Edited by troller
Link to comment
Share on other sites

never mind.

Page control with its tab sheets fits my needs.

Still need answer for questions 1 and 3 :)

 

I thought I answered #3 in my example. You'll see it reads the value of an edit and determines if it is a string or a number. Perhaps I am misunderstanding the question.

 

As for #1. I guess I confused the issue by showing the OnEnter and OnExit events. 99.99% of the time you don't need these. There are some special cases where it is useful to do something when a control changes and there is no OnChange event for that particular control. In that case you could hook into the OnExit event as a cheap workaround. But for now pretend they don't exist. If you have a need for them you'll know it.

 

As for the OnClose, not sure what you are asking. If you want to do something after the form is closed just put your code out in the main script after the call to the form. You can in the OnClose event prevent the form from closing. A Special case, but sometimes you want to prevent the user from closing the form until they have enter valid values in everything. Again not something you will use often.

 

Tip: If the form is modal (and I think the example is?) you can force the form to close by setting the result yourself in code (or at least you can in Delphi, I believe SCAR works the same way?).

Form1.ModalResult := mrOK

 

Someone else asked about using records. Personal preference. 6 of one, half dozen of another. Try looking at the generated code in the form designer while toggling the records option. Accomplishes the same thing. Some people prefer it. Some people think it looks "odd". One nice thing about using the record is each control is automatically "owned" by the form. Everything has an "owner" that is responsible for freeing its memory after use. If you don't use records remember to manually set each control's owner to the form to keep things tidy memory wise.

 

I am now officially rambling so I will shut up now.

Link to comment
Share on other sites

Thanks dude, now im able to understand many things.

Still have some questions though.

For example, i have a form with only an Ok button and the "X" symbol for exit. How can i make the script terminate and close form if "X" pressed while If ok pressed, to close the form and continue with the script? Tried messing around with modal results but failed.

Link to comment
Share on other sites

Thanks dude, now im able to understand many things.

Still have some questions though.

For example, i have a form with only an Ok button and the "X" symbol for exit. How can i make the script terminate and close form if "X" pressed while If ok pressed, to close the form and continue with the script? Tried messing around with modal results but failed.

 

Interesting! (My goto phrase when I am stumped) I was just about to respond "check the modal result" and then I read the rest of your post. Have to get back to you on this one.

 

Edit: There are ton of ways to do this. Here is a "quick and dirty": note how I set the properties of the buttons to mrOk and mrCancel respectively.

var
 Form1: TForm;
 Button1: TButton;
 Button2: TButton;

procedure Form1_Init;
begin
 Form1 := CreateForm;
 Button1 := TButton.Create(Form1);
 Button2 := TButton.Create(Form1);
 with Form1 do
 begin
   Left := 376;
   Top := 179;
   Caption := 'Test Modal';
   ClientHeight := 50;
   ClientWidth := 190;
   Color := clWindow;
   Font.Charset := DEFAULT_CHARSET;
   Font.Color := clWindowText;
   Font.Height := -11;
   Font.Name := 'Tahoma';
   Font.Style := [];
   OldCreateOrder := False;
   PixelsPerInch := 96;
 end;
 with Button1 do
 begin
   Parent := Form1;
   Left := 10;
   Top := 11;
   Width := 75;
   Height := 25;
   Caption := 'Button1';
   ModalResult := mrOk;
   TabOrder := 0;
 end;
 with Button2 do
 begin
   Parent := Form1;
   Left := 96;
   Top := 11;
   Width := 75;
   Height := 25;
   Caption := 'Button2';
   ModalResult := mrCancel;
   TabOrder := 1;
 end;
end;

procedure Form1_SafeInit;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 ThreadSafeCall('Form1_Init', v);
end;

function Form1_ShowModal: Boolean;
begin
 Result := Form1.ShowModal = mrOk;
end;

function Form1_SafeShowModal: Boolean;
var
 v: TVariantArray;
begin
 SetLength(v, 0);
 Result := ThreadSafeCall('Form1_ShowModal', v);
end;

var
 FormOk: Boolean;

begin
 Form1_SafeInit;
 FormOk := Form1_SafeShowModal;
 FreeForm(Form1);  
 if not FormOk then
 begin
   Writeln('Form returned mrCancel');
   TerminateScript();
 end;

 Writeln('Form returned mrOk');
 Writeln('>> Continue on with script');
end.

Edited by Bixby Sayz
Link to comment
Share on other sites

Yes, that did work! Thanks again!

Just a random question. Is it possible to run a browser in a scar form? and if yes,(thats a bit crazy), to make this run in background with its own mouse and keyboard(so the user can still use his pc if scar is using mouse/keyboard)

Link to comment
Share on other sites

My form is ready with saving option. Thanks for your help, i really appreciate it.

First i wanna do this

USES ShelAPI;

.................................................. .........

.................................................. .........

var

wHandle : THandle;

begin

//Run Excel or any program.

ShellExecute(Application.Handle,'Open','Excel.exe' ,nil,nil,SW_NORMAL);

 

//Wait for it to be loaded.

Sleep(500);

 

//Get the handle of the other program using the caption of the window.

wHandle := FindWindow(NIL,'Microsoft Excel - Book1');

 

//Now change the parent of the other program to be your program.

Windows.SetParent(wHandle,self.Handle);

 

This is for delphi. How to Take it into scar?

 

Just another question not about forms.

I found this https://villavu.com/forum/showthread.php?t=45534

It is a webclient. I see many times saying that can find content even minimized(which is what i meant with background).

So, uhm, how to load that dll? I mean, i am running scar 3.40 portable and there's no plugins folder neither in scar's directory nor in documents.

P.S.(The game is flash based)

 

Thanks in advance

Edited by troller
Link to comment
Share on other sites

One thing I'm running into is that my form doesn't pop up on the main client. I have a script running for a game and would like the form to appear over top the game. What happens is my game pauses and but I see no form. But if I Alt-Tab to the SCAR window the form will appear over top of scar.

 

How would I go about making the form appear overtop the game?

Link to comment
Share on other sites

Yes, that did work! Thanks again!

Just a random question. Is it possible to run a browser in a scar form? and if yes,(thats a bit crazy), to make this run in background with its own mouse and keyboard(so the user can still use his pc if scar is using mouse/keyboard)

 

One thing I used when running scripts on a RuneScape Classic server, was Virtual Machine. a VM can be run on your computer in the background(it uses a virtual mouse and keyboard). However, they do take a lot of CPU power to run. But for me it was fine and worked wonders. (I hope I'm on the right track here,wasn't too sure about your question)

At one point I was running three different characters macroing on a VM.

 

Heres a link to the website if you are interested: https://my.vmware.com/web/vmware/free

 

Hope I helped :)

Link to comment
Share on other sites

Woops, guess I spoke to soon. While the form does now appear over top of the game, its not active and if I click anywhere on it then Scar is pulled up with the form active over top that. When I close the form (using the x in the corner) then the form partially closes (as in some elements within it vanish) and the script begins running again, however with Scar still showing and the game remaining underneath it. When I try to halt the script then SCAR crashes.

 

It feels like the form is tied to SCAR rather than the game (if that makes sense). Am I missing something to tie it to the game client window? I can post the form code if you like, its just the shell created by the SCAR form creator right now. Haven't had a chance yet to tinker with the guts of it because of this problem.

Link to comment
Share on other sites

I think I found somewhat of a fix. I added in these lines :

 

Form1_1.parent := Form1_1;

Form1_1.align := alNone;

Form1_1.FormStyle:=fsStayOnTop;

 

It still pulls up SCAR over top the Client Game window with my form on top of scar, but now when I close the form Scar drops back behind the Client window and everything seems to run smoothly again. I guess I can live with that as my Form is being used to change various settings running my script and I don't really need to see the game while doing it.

 

I found this link that helped me find that solution. I'm sure I'm still not doing it right but at least I can continue on and start making my form functional.

 

http://www.delphisources.ru/pages/faq/master-delphi-7/content/LiB0064.html

Link to comment
Share on other sites

Glad to hear you go it going.

 

One thing to keep in mind about forms: SCAR is not multi-threaded so when you call a form your script stops at that point and waits until the form exits/closes. May explain some of the behavior you're seeing.There should be a way to prevent SCAR popping up but for the life of me can't remember what it is.

Link to comment
Share on other sites

Glad to hear you go it going.

 

One thing to keep in mind about forms: SCAR is not multi-threaded so when you call a form your script stops at that point and waits until the form exits/closes.

 

Yah, was disappointed when I finally figured that out. I have quite a few timing events in my script so when I call the form up I measure the time that the script has been paused and adjust all the timing variables when the form is closed. I've only really found one thing that allows you to write directly to the client window while a script is running and that is the Alert message box. It's limited in usage, but at least something one can finagle to display some variables while the script is running.

 

Through all my searching to find various solutions I'm pretty sure at some point I read about what you refer to, but of course I can't find it now :P. But like I said, I can live with it ;)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
  • Create New...