A screen saver is really just a Windows program. Screen savers can be divided into two types: full-screen and effects.
The first type has a bsNone border style, the form usaully (not always, though) has a black background and is maximized. They always have the fsStayOnTop form style.
The second type is harder to create because they don't really have a visible form. They perform graphical effects on the screen. These are thougher because there's a lot more code to write.
Because screen savers are Windows applications they can freely access Ini files or the system Registry. They perform all the tasks a program can perform.
The screen saver has a .scr extension. You set this (Delphi 4+) in the project's options or using the {$e 'scr'} directive. No file type conversions are needed.
Windows controls the screen saver using parameters:
- /c - The screen saver is started. Sometimes this parameter will be sent with additional options. The format is: /c:xxxx, where x is a decimal number.
- /p - The screen saver is being installed or the Screen Saver page has been chosen.
- /s - - No commandline options - The screen saver setup should execute.
This example shows how to create a screen saver based on a maximized form with a black (usually) background.
At design time set the WindowState property to wsNormal else there may be problems maximizing it programmatically. Set the form's BorderStyle property to bsNone.
Now in the OnCreate event insert this code: ...
WindowState := wsMaximized; { You can't maximize it properly earlier } ... Don't forget to include a TTimer component (or something more precise if you want) to control the screen saver's animation. You may want to include a "Low CPU Usage" option that won't take too much of the processor's precious :) time. When this option would be set the screen saver would perform less calculations or at least the TTimer component's interval property would be multiplied by 2 or 4. You can also do this by lowering the current thread's and process'es priority level. This option is very useful for users that use screen savers but often have programs running in the background and don't like the screen saver taking 100% of the CPU's time.
Here is the code for a screensaver I've made:
You can download
my screensaver
here:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, compound, mdp, RXCtrls, StdCtrls;
type
TInst = record
NoOfLogos: 1..10;
Interval: 1..10;
end;
TForm1 = class(TForm)
Timer1: TTimer;
MDP1: TMDP;
MDP2: TMDP;
mdp3: TMDP;
MDP4: TMDP;
MDP5: TMDP;
MDP6: TMDP;
MDP7: TMDP;
MDP8: TMDP;
MDP9: TMDP;
MDP10: TMDP;
Memo1: TMemo;
RxLabel1: TRxLabel;
Timer2: TTimer;
procedure Timer1Timer(Sender: TObject);
procedure FormClick(Sender: TObject);
procedure FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure FormCreate(Sender: TObject);
procedure SaveFile;
procedure LoadFile;
procedure Timer2Timer(Sender: TObject);
procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
private
Start: Boolean;
F: file of TInst;
Rad: Integer;
{ Private declarations }
public
Inst: TInst;
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.DFM}
{
Windows controls the screen saver using parameters:
- /c - The screen saver is started. Sometimes this parameter will be sent
with additional options. The format is: /c:xxxx, where x is a decimal number.
- /p - The screen saver is being installed or the Screen Saver page has been
chosen.
- /s - - No commandline options - The screen saver setup should execute.
}
procedure TForm1.Timer1Timer(Sender: TObject);
var n: Integer;
begin
if (ParamStr(1) = '/s') and Start then
begin
WindowState:= wsMaximized;
for n:= 1 to Inst.NoOfLogos do
begin
TMDP(FindComponent('MDP' + IntToStr(n))).Start;
TMDP(FindComponent('MDP' + IntToStr(n))).Show;
end;
for n:= Inst.NoOfLogos + 1 to 10 do
begin
TMDP(FindComponent('MDP' + IntToStr(n))).Stop;
TMDP(FindComponent('MDP' + IntToStr(n))).Hide;
end;
Timer1.Enabled:= true;
end
else
if (ParamStr(1) = '/s') and not Start then
begin
for n:= 1 to Inst.NoOfLogos do
begin
TMDP(FindComponent('MDP' + IntToStr(n))).Left:= Random(700);
TMDP(FindComponent('MDP' + IntToStr(n))).Top:= Random(450);
end;
end
else
begin
Timer1.Enabled:= false;
if MenuForm.ShowModal = mrOK then
begin
SaveFile;
Close;
end;
end;
Start:= false;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
LoadFile;
Timer1.Interval:= Inst.Interval * 1000;
Randomize;
Height:= 0;
Width:= 0;
Rad:= 0;
Timer1.Enabled:= true;
Timer2.Enabled:= true;
Start:= true;
end;
procedure TForm1.SaveFile;
begin
Inst.NoOfLogos:= MenuForm.SpinEdit1.Value;
Inst.Interval:= MenuForm.SpinEdit2.Value;
AssignFile(F, 'c:\mdpscr.dat');
Rewrite(F);
Write(F, Inst);
CloseFile(F);
end;
procedure TForm1.LoadFile;
begin
try
AssignFile(F, 'c:\mdpscr.dat');
Reset(F);
Read(F, Inst);
CloseFile(F);
except
Inst.Interval:= 4;
Inst.NoOfLogos:= 5;
AssignFile(F, 'c:\mdpscr.dat');
Rewrite(F);
Write(F, Inst);
CloseFile(F);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
begin
RxLabel1.Caption:= Memo1.Lines[Rad];
Inc(Rad);
if Rad = 25 then Rad:= 0;
end;
procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
Close;
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, compound, mdp, StdCtrls, Buttons, passoverbtn, RXCtrls, RXSpin,
Spin;
type
TMenuForm = class(TForm)
PassOverBtn1: TPassOverBtn;
MDP1: TMDP;
RxLabel1: TRxLabel;
SpinEdit1: TSpinEdit;
RxLabel2: TRxLabel;
SpinEdit2: TSpinEdit;
procedure PassOverBtn1Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MenuForm: TMenuForm;
implementation
uses Unit1;
{$R *.DFM}
procedure TMenuForm.PassOverBtn1Click(Sender: TObject);
begin
ModalResult:= mrOK;
end;
procedure TMenuForm.FormActivate(Sender: TObject);
begin
SpinEdit1.Value:=Form1.Inst.NoOfLogos;
SpinEdit2.Value:=Form1.Inst.Interval;
end;
end.