FrÕzÑ_§ÕµL
2008-01-05 03:51:42

Hey everyone,
this is my first tut, but I hope you enjoy it and learn anyway :D After hours of searching the forums, I didn't find any in depth guides on how to do this, had to find out myself by mixing up some tuts and experimenting.
To use this tut, you should already know how to create a functional form! I will show you how to turn a bitmap into a string and then use it to make your Forms look cool. I will also show you how to add some effects to the form ;).
OK go to Form Editor, and create a new form. Put 2 labels on it. With both labels change the following settings:
Autosize -> False.
Captions -> Blank.
Cursor -> crHandPoint.
Name -> One to StartLabel and one to ExitLabel.
Transparent -> True. //SINGLE MOST IMPORTANT VALUE!
Your form should like like this:

OK save that as SweetForm.
Now in SCAR go to Tools -> Load DFM Form. Find SweetForm and click OK.
Put the variables at top of script and in a procedure called InitForm put the rest.
Add the 3 procedures that every form needs (SafeInitForm, ShowFormModal, SafeShowFormModal)
Don't forget to change frmDesign.Visible to False!
By this stage your script should look like:
program SweetForm;
var
frmDesign : TForm;
StartLabel, ExitLabel : TLabel;
Procedure InitForm;
Begin
frmDesign := CreateForm;
frmDesign.Left := 246;
frmDesign.Top := 88;
frmDesign.Width := 361;
frmDesign.Height := 214;
frmDesign.Caption := 'frmDesign';
frmDesign.Color := clBtnFace;
frmDesign.Font.Color := clWindowText;
frmDesign.Font.Height := -11;
frmDesign.Font.Name := 'MS Sans Serif';
frmDesign.Font.Style := [];
frmDesign.Visible := False;
frmDesign.PixelsPerInch := 96;
StartLabel := TLabel.Create(frmDesign);
StartLabel.Parent := frmDesign;
StartLabel.Left := 16;
StartLabel.Top := 72;
StartLabel.Width := 113;
StartLabel.Height := 49;
StartLabel.AutoSize := False;
StartLabel.Caption := 'StartLabel';
StartLabel.Cursor := crHandPoint;
StartLabel.Color := clBlack;
StartLabel.ParentColor := False;
StartLabel.Transparent := True;
ExitLabel := TLabel.Create(frmDesign);
ExitLabel.Parent := frmDesign;
ExitLabel.Left := 192;
ExitLabel.Top := 72;
ExitLabel.Width := 113;
ExitLabel.Height := 49;
ExitLabel.AutoSize := False;
ExitLabel.Caption := 'Exit';
ExitLabel.Cursor := crHandPoint;
ExitLabel.Color := clBlack;
ExitLabel.ParentColor := False;
ExitLabel.Transparent := True;
end;
procedure SafeInitForm;
var
v: TVariantArray;
begin
setarraylength(V, 0);
ThreadSafeCall('InitForm', v);
end;
procedure ShowFormModal;
begin
frmDesign.ShowModal;
end;
procedure SafeShowFormModal;
var
v: TVariantArray;
begin
setarraylength(V, 0);
ThreadSafeCall('ShowFormModal', v);
end;
begin
Try
SafeInitForm;
SafeShowFormModal;
Finally
FreeForm(frmDesign);
end.
If you run it, you will get a form with 2 invisble boxes with text!Now we need some pictures!
OK, so get a bitmap (I've attached 2 below if you don't know what to use, you can not release a script using these). It should be quite small, and it will be the size of your buttons.
First clear the Debug box.
In SCAR go Tools -> Picture To String.
Click Open and find your bitmap.
Change the Name of the Bitmap to Picture and then click OK.
You will get a massive string of text in the debug box.
Since we cleared the debug box first, we only need to click it, press ctrl + a and then copy.
Now we need to create a new procedure that will be used when the Form starts up, so that the images are painted on it. Call it DrawImages(Sender : TObject);
Then we need a couple of variables:
Picture : Integer;
Canvas : TCanvas
Picture is the Bitmap and Canvas is what we will paint the bitmaps onto.
So the new procedure is:
Procedure DrawImages(Sender: TObject);
var
Picture : Integer;
Canvas : TCanvas;
Begin
end;This must go ABOVE InitForm.OK now inside the DrawImages procedure paste the BitmapString that you just got from the debugbox.
Right, so now we have the bitmap in the procedure, we need something to draw it on to the form.
For this we use the procedure CopyCanvas.
First we put the bitmap onto the canvas using GetCanvasBitmap:
Canvas := GetBitmapCanvas(Picture);
And then we draw it onto the main form as follows:CopyCanvas(Canvas, frmDesign.Canvas, 0, 0, 113, 49, 16, 203, 129, 252);OK I'll explain the parameters for this, so that you don't make any mistakes and know how to use it properly.Canvas is where to copy the image from.
frmDesign.Canvas is the destination of that image, in our case that is the Forms Canvas.
The first 4 numbers are the coordinates of the picture to copy from.
0, 0 means from the top left corner of Picture.
113, 49 is the bottom right corner.
This is used in case you don't want the whole image, but if that is so then you should re make the Bitmap String with the unwanted part cut out to save space in your script.
The last 4 numbers are where on the form to draw the image.
These will be the points of:
StartLabel.Left
StartLabel.Top
StartLabel.Left + Width of your image (in my case 113)
StartLabel.Top + Height of your image (in my case 49)
So I get
CopyCanvas(Canvas, frmDesign.Canvas, 0, 0, 113, 49, 16, 203, 129, 252);
Also make sure you add a FreeBitmap(Picture); after your last image has been drawn to save memory.
So the new procedure is:
Procedure DrawImages(Sender: TObject);
var
Picture : Integer;
Canvas : TCanvas;
Begin
Picture := BitmapFromString(113, 49, 'string data here');
Canvas := GetBitmapCanvas(Picture);
CopyCanvas(Canvas, frmDesign.Canvas, 0, 0, 113, 49, 16, 203, 129, 252);
FreeBitmap(Picture);
end;Repeat the above process for all the Bitmaps on your form!
Now everything is in place, all we need is to make the form paint the image!
So add this to your InitForm procedure.
frmDesign.OnPaint := @DrawImages;or you can useFr0znFormDesign.OnActivate := @DrawImages;Thats up to you, try them both out, but OnPaint is probably better.We also need to get rid of the text on the labels, so delete the lines
*Label.Caption := '*';
So far, our form is as follows:
program SweetForm;
var
frmDesign : TForm;
StartLabel, ExitLabel : TLabel;
Procedure DrawImages(Sender: TObject);
var
Picture : Integer;
Canvas : TCanvas;
Begin
Picture := BitmapFromString(113, 49, 'string data here');
Canvas := GetBitmapCanvas(Picture);
CopyCanvas(Canvas, frmDesign.Canvas, 0, 0, 113, 49, 16, 203, 129, 252);
FreeBitmap(Picture);
end;
Procedure InitForm;
Begin
frmDesign := CreateForm;
frmDesign.Left := 246;
frmDesign.Top := 88;
frmDesign.Width := 361;
frmDesign.Height := 214;
frmDesign.Caption := 'frmDesign';
frmDesign.Color := clBtnFace;
frmDesign.Font.Color := clWindowText;
frmDesign.Font.Height := -11;
frmDesign.Font.Name := 'MS Sans Serif';
frmDesign.Font.Style := [];
frmDesign.OnPaint := @DrawImages;
frmDesign.Visible := False;
frmDesign.PixelsPerInch := 96;
StartLabel := TLabel.Create(frmDesign);
StartLabel.Parent := frmDesign;
StartLabel.Left := 16;
StartLabel.Top := 72;
StartLabel.Width := 113;
StartLabel.Height := 49;
StartLabel.AutoSize := False;
StartLabel.Cursor := crHandPoint;
StartLabel.Color := clBlack;
StartLabel.ParentColor := False;
StartLabel.Transparent := True;
ExitLabel := TLabel.Create(frmDesign);
ExitLabel.Parent := frmDesign;
ExitLabel.Left := 192;
ExitLabel.Top := 72;
ExitLabel.Width := 113;
ExitLabel.Height := 49;
ExitLabel.AutoSize := False;
ExitLabel.Cursor := crHandPoint;
ExitLabel.Color := clBlack;
ExitLabel.ParentColor := False;
ExitLabel.Transparent := True;
end;
procedure SafeInitForm;
var
v: TVariantArray;
begin
setarraylength(V, 0);
ThreadSafeCall('InitForm', v);
end;
procedure ShowFormModal;
begin
frmDesign.ShowModal;
end;
procedure SafeShowFormModal;
var
v: TVariantArray;
begin
setarraylength(V, 0);
ThreadSafeCall('ShowFormModal', v);
end;
begin
GetApplication.BringToFront; //Makes sure Form is in front of other windows.
Try
SafeInitForm;
SafeShowFormModal;
Finally
FreeForm(frmDesign);
end.
Wow our form just painted its first image! If you set it all up right then when you move the mouse over the 'picture' then your cursor will change to a hand with a finger pointed :D Now we need a few more things, like labelclicks.
Making your form do stuff!
We create another procedure, ButtonClick(Sender : Object);
In that we create a Case statement of Sender, so that when an object is clicked they are all directed to one procedure, with a part specific to the object!
So our new procedure will be:
Procedure ButtonClick(Sender: TObject);
Begin
case Sender of
StartLabel : Begin
end;
ExitLabel : Begin
end;
end;
end;
If we want the form to continue without an error we must have the line:
frmDesign.ModalResult := mrOk;
So StartLabel will be
StartLabel : Begin
frmDesign.ModalResult := mrOk;
end;and ExitLabel will be
ExitLabel : Begin
frmDesign.ModalResult := mrOk;
Exit;
end;Now to get to that procedure we put the following in InitForm:
StartLabel.OnClick := @ButtonClick;
ExitLabel.OnClick := @ButtonClick;
And you have working buttons! I will show this in the script further down after a few more things.
Now when you run the script, you may have noticed that sometimes the images all disappear :eek:
So we add something that will make the form RePaint, makes sense right? It can be anything, but I use OnClick as follows:
frmDesign.OnClick := @DrawImages;And thats all you need to do for that ^^ :pSo now we have a fully functional form, and you have added as many bitmaps to the DrawImages procedure as you need. What else can we do to make this form look/do-stuff-thats cool?!
Well in mine, I create two procedures : EffectsOn and EffectsOff.
In these when something occurs in the form, such as changing textbox in my example, it goes to the EffectsOff on one thing and the EffectsOn on the other. I will show here, but you can not use these directly as I have made those labels for my form and it won't compile:
Procedure EffectsOn(Sender: TObject);
Begin
Case Sender of
LogoutEdit : Begin
LogoutLabel.Font.Height := -25;
LogoutLabel.Font.Style := [fsUnderline];
end;
TalkEdit : Begin
TalkLabel.Font.Height := -25;
TalkLabel.Font.Style := [fsUnderline];
end;
ColorEdit : Begin
ColorLabel.Font.Height := -24;
ColorLabel.Font.Style := [fsUnderline];
ColorLabel.Caption := 'Game Color Tol';
end;
SpeedEdit : Begin
SpeedLabel.Font.Height := -25;
SpeedLabel.Font.Style := [fsUnderline];
end;
LampEdit : Begin
LampLabel.Font.Height := -25;
LampLabel.Font.Style := [fsUnderline];
end;
end;
end;
EffectsOff is the same, but uses LogoutLabel.Font.Height := -15;
LogoutLabel.Font.Style := [];
therefore reversing the effects of EffectsOn.
The sender for these is the textboxes:
LampEdit.OnEnter := @EffectsOn;
LampEdit.OnExit := @EffectsOff;
I will explain in more depth what this does. When the user clicks in a text box to change a value, it underlines and enlarges the text in the corresponding label. So clicking the LampEdit makes LampLabel get bigger and underlined! And then when the user clicks on another box, LampLabel returns to normal state and the other label gains the effects :D
That is just one simple example of what you can do to make them look cool. I used to have my form paint stars on the background when it started up 1/5 of the time. However, since I kept that inside the DrawImages procedure, when the form re-drew, it would sometimes draw a star over an existing object and cause an access violation, so I removed it because I did not need it. However, I may as well show you how I did it ;)
Drawing things onto the background of the form
OK the main thing you use here is FastSetPixel. Parameters are:
Picture = Where to put the pixels.
x, y = the coordinate of where to put the pixel.
StarColor : A variable I made for starcolor (it needs to be a TColor not an integer or string)
OK the parts of the procedure I made:
The Case Random(5) means that if the random number is 0 it will draw stars, otherwise it will skip it.
You need to do Picture := BitmapFromString(SizeOfForm.Y, SizeOfForm.Y, '');
Make sure the last bit is ''!
Inc(Tries) means that it increases the number of stars made by 1 (I used tries to save on variables)
the x and y := Random(SizeOfForm.*) means it will put the star in a random place.
Case Random(6) of
0 : Starcolor;
This simply chooses a randomcolor to make a star.
And at last the FastSetPixels.
FastSetPixel(Picture, x, y, Starcolor)
That one creates the center point of the star.
The next 6 extend the line by 3 pixels up and down of the center.
The following 6 extend the line by 3 pixels left and right.
And the last 4 make a point on a diagonal each way of the center.
Until(tries > RandomRange(40, 60))
This means that the script will place a random amount between 40 - 60. however it will get a new number every time it does the loop I believe (tell me if I'm wrong) so the higher the number the less likely it is. So about 45 stars is highly more likely than 60, but also more likely then 40.
And last of all actually putting it on your form!
Use
SafeDrawBitmap(Picture, frmDesign.Canvas, 0, 0);This draws from Picture to the Canvas, starting from 0, 0 of the picture. You will want to leave at 0, 0.
case Random(5) of
0 : Begin
Picture := BitmapFromString(283, 283, '');
Repeat
Inc(Tries);
x := Random(283);
y := Random(283);
Case Random(6) of
0 : StarColor := clSilver;
1 : StarColor := clGold;
2 : StarColor := clFuchsia;
3 : StarColor := clAqua;
4 : StarColor := clSkyBlue;
5 : StarColor := clTeal;
end;
FastSetPixel(Picture, x, y, StarColor);
FastSetPixel(Picture, x, y - 3, StarColor);
FastSetPixel(Picture, x, y - 2, StarColor);
FastSetPixel(Picture, x, y - 1, StarColor);
FastSetPixel(Picture, x, y + 1, StarColor);
FastSetPixel(Picture, x, y + 2, StarColor);
FastSetPixel(Picture, x, y + 3, StarColor);
FastSetPixel(Picture, x - 3, y, StarColor);
FastSetPixel(Picture, x - 2, y, StarColor);
FastSetPixel(Picture, x - 1, y, StarColor);
FastSetPixel(Picture, x + 1, y, StarColor);
FastSetPixel(Picture, x + 2, y, StarColor);
FastSetPixel(Picture, x + 3, y, StarColor);
FastSetPixel(Picture, x - 1, y - 1, StarColor);
FastSetPixel(Picture, x - 1, y + 1, StarColor);
FastSetPixel(Picture, x + 1, y - 1, StarColor);
FastSetPixel(Picture, x + 1, y + 1, StarColor);
Until(Tries > RandomRange(40, 60));
SafeDrawBitmap(Picture, Fr0znFormDesign.Canvas, 0, 0);
Tries := 0;
end;
end;
Using the SRL PlayerForm with your Form!
OK, the awesome thing about the SRL PlayerForm is that its only one line to call it! And that saves those hundreds of lines of a DeclarePlayers procedure :p Also it is easier for the user, noobs won't forget to set it up cause it's in their way of running the script, and it is much safer than DeclarePlayers. How many of us have left our names and passes is scripts we have posted? Too many!
OK, to call the PlayerForm, the procedure is:
SRLPlayerForm(True, [Boolean labels], [Integer labels], [String labels], [Extendeds labels]);
The True means whether or not you want it to be visible… I don't see the point in that being False but hey, there must be one.
The Boolean, integers, strings and extendeds labels are Arrays of things you want the form to make labels and text boxes (or drop downs for booleans). So my example is:
SRLPlayerForm(True, ['Member?'], ['Loads To Do'], ['Tree To Cut', 'Bank or Drop', 'Bank PIN', 'Run Direction', 'SRL ID', 'SRL Password'], []);All these things that the user enters will be saved for them and filled in for the next time the user runs it.
Right… So I got my playerform… but which one is Integer[x]?! Well, you can probably just go back to the SRLPlayerForm, and your first one in each sequence is [0] and the next is [1] etc… but that uses my brain! So why not make SCAR write it all out for us in the debug box :p
//Add this in to your setup procedure after the SRLPlayerForm to find out which string/integer etc is [0] and [1] etc.
For x := 0 to HowManyPlayers - 1 do
Begin
For y := 0 to GetArrayLength(Players[x].Integers) - 1 do
Begin
if Players[x].Integers[y] = 0 then
Break;
WriteLn('Players[' + IntToStr(x) + '].Integers[' + IntToStr(y) + '] = ' + IntToStr(Players[x].Integers[y]));
end;
For y := 0 to GetArrayLength(Players[x].Strings) - 1 do
Begin
if Players[x].Strings[y] = '' then
Break;
WriteLn('Players[' + IntToStr(x) + '].Strings[' + IntToStr(y) + '] = ' + Players[x].Strings[y]);
end;
For y := 0 to GetArrayLength(Players[x].Booleans) - 1 do
Begin
WriteLn('Players[' + IntToStr(x) + '].Booleans[' + IntToStr(y) + '] = ' + BoolToStr(Players[x].Booleans[y]));
if Not(Players[x].Booleans[y]) and Not(Players[x].Booleans[y + 1]) and Not(Players[x].Booleans[y + 2]) then
Break;
end;
For y := 0 to GetArrayLength(Players[x].Extendeds) - 1 do
Begin
if Players[x].Extendeds[y] = 0 then
Break;
WriteLn('Players[' + IntToStr(x) + '].Extendeds[' + IntToStr(y) + '] = ' + FloatToStr(Players[x].Extendeds[y]));
end;
end;And don't forget to remove it again afterwards lol.So to call the PlayerForm, we add our line to our ButtonClick like so:
StartLabel : Begin
frmDesign.ModalResult := mrOk;
SRLPlayerForm(True, ['Member?'], ['Loads To Do'], ['Tree To Cut', 'Bank or Drop', 'Bank PIN', 'Run Direction', 'SRL ID', 'SRL Password'], []);
end;Now we have a fully functional PlayerForm! That concludes my tutorial (for now, I'll think of some more cool stuff you guys might be able to use).
May I suggest someone comes up with an idea for using
OnMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
If you want a list of all the things you can add effects with and stuff, go to SCAR, Tools -> Events Handler List. It also tells you all the params you need for the @Whatever procedure.
If you have any questions, comments or suggestions, feel free to reply! I have this thread on instant email alert :D Remember, you can only make cool new things by experimenting!
Attached files :
Home and Start.bmp for your test form if you don't have anything else.
Fr0zn Form. This is my form that I use in my wc script. Take a look, its pretty awesome :D