• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 364
  • Last Modified:

Minimize app if idle for a period of time - Delphi 5

Hi,

I've got a delphi app that i need to minimize if there is no user activity of ay kind for a period of time, probably 5 minutes.  What's he simplest way to do this?

TIA,
WS
0
Waterstone
Asked:
Waterstone
  • 4
  • 3
  • 3
2 Solutions
 
mokuleCommented:
No activity in this app or in all apps/windows?
0
 
Russell LibbySoftware Engineer, Advisory Commented:

It also helps to define "no activity". As far as window is concerned, having to repaint, having a mouse move over it, etc etc will cause the message queue to be serviced and code to be exeuted. Perhaps something along the lines of

- no mouse clicks, no key presses -

Something like this could be handled (updated) in the applications OnMessage handler. A timer could be set to poll every N number of seconds and evaluate the last activity value set by the OnMessage handler. If 300 seconds have passed since the last activity, then the app could minimize itself.

Regards,
Russell
0
 
WaterstoneAuthor Commented:

Just the App.  No key or mouse activity.
0
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
Russell LibbySoftware Engineer, Advisory Commented:
An example based on code placed in the main form (binding the application message handler)

Regards,
Russell

----

unit Unit1;

interface

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

type
  TForm1            =  class(TForm)
     procedure      FormCreate(Sender: TObject);
  private
     // Private declarations
     FTimer:        TTimer;
     FLastActivity: LongWord;
     FDelayMS:      LongWord;
  protected
     // Protected declarations
     procedure      OnAppTimer(Sender: TObject);
     procedure      OnAppMessage(var Msg: TMsg; var Handled: Boolean);
  public
     // Public declarations
     property       LastActivity: LongWord read FLastActivity;
     property       DelayMS: LongWord read FDelayMS write FDelayMS;
  end;

var
  Form1: TForm1;

implementation
{$R *.DFM}
procedure TForm1.OnAppTimer(Sender: TObject);
begin

  // Check current time against last activity
  if ((FLastActivity+FDelayMS) < GetTickCount) then
  begin
     // Inactive for DelayMS time period
     Application.Minimize;
  end;

end;

procedure TForm1.OnAppMessage(var Msg: TMsg; var Handled: Boolean);
begin

  // Check for keyboard messages
  if ((Msg.message >= WM_KEYFIRST) and (Msg.message <= WM_KEYLAST)) then
     // Update last activity
     FLastActivity:=GetTickCount
  // Check for non-client mouse messages
  else if ((Msg.message >= WM_NCLBUTTONDOWN) and (Msg.message <= WM_NCMBUTTONDBLCLK)) then
     // Update last activity
     FLastActivity:=GetTickCount
  // Check for mouse messages
  else if ((Msg.message >= WM_LBUTTONDOWN) and (Msg.message <= WM_MOUSELAST)) then
     // Update last activity
     FLastActivity:=GetTickCount
  // Check for activation messages
  else if (Msg.message in [WM_ACTIVATE, WM_SETFOCUS, WM_ACTIVATEAPP]) then
     // Update last activity
     FLastActivity:=GetTickCount;

  // We do not directly handle the message
  Handled:=False;

end;

procedure TForm1.FormCreate(Sender: TObject);
begin

  // Set defaults
  FDelayMS:=300 * 1000;                  // Delay time in ms
  FLastActivity:=GetTickCount;           // Last activity time, set to startup time
  Application.OnMessage:=OnAppMessage;   // Bind the message handler for the app
  FTimer:=TTimer.Create(Self);           // Create timer
  FTimer.Interval:=5000;                 // Set timer interval to 5 seconds
  FTimer.OnTimer:=OnAppTimer;            // Bind timer event
  FTimer.Enabled:=True;                  // Enable the timer

end;

end.
0
 
mokuleCommented:
And this is my version

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    LastMsgTime: TDateTime;
    procedure CheckMsg(var Msg: TMsg; var Handled: Boolean);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}



procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.OnMessage := CheckMsg;
  LastMsgTime := Now;
  Timer1.Interval := 100;
  Timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if SECSPERDAY*(Now - LastMsgTime) > 5 then
    begin
    Application.Minimize;
    Timer1.Enabled := False;
    end;
  Edit4.Text := IntToStr(Round(SECSPERDAY*(Now - LastMsgTime)));
end;

procedure TForm1.CheckMsg(var Msg: TMsg; var Handled: Boolean);
begin
  if Application.Active then
    begin
    if (Msg.message >= WM_KEYFIRST) and (Msg.message <= WM_KEYLAST) then
      begin
      LastMsgTime := Now;
      end;
    if (Msg.message >= WM_MOUSEFIRST) and (Msg.message <= WM_MOUSELAST) then
      begin
      LastMsgTime := Now;
      end;
    if (Msg.message = WM_ACTIVATE) then
      begin
      LastMsgTime := Now;
      end;
    end
  else
    if (Msg.message = WM_PAINT) then
      begin
      LastMsgTime := Now;
      Timer1.Enabled := True;
      end;
  Handled := False;
end;

0
 
mokuleCommented:
I've left 5 secs off time
0
 
WaterstoneAuthor Commented:

Took the advice listed here and did some more research and the code below is what I came up with.  It works great
except that it doesnt recognize the BUTTONDOWN methods when I click on the scroll bar in the memo box.  

Any idea why?


===============================================================================

unit TimeMinUnit;

interface

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

type
  TTimeMinForm = class(TForm)
    Timer2: TTimer;
    Memo1: TMemo;
    RadioButton1: TRadioButton;
    SecondsEdit: TEdit;
    Label1: TLabel;
    Button1: TButton;

    procedure AppMinimize(Sender: TObject);
    procedure AppRestore(Sender: TObject);

    procedure ApplicationEvents1Message(var Msg: tagMSG;
      var Handled: Boolean);
    procedure Timer2Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure SecondsEditChange(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  TimeMinForm: TTimeMinForm;

implementation

{$R *.DFM}

procedure TTimeMinForm.FormCreate(Sender: TObject);
begin
   Application.OnMinimize  := AppMinimize;
   Application.OnRestore   := AppRestore;
   Application.OnMessage   := ApplicationEvents1Message;
   Timer2.Interval := (1000 * 60);
   Timer2.Enabled  := True;

end;  { FormCreate }

procedure TTimeMinForm.AppMinimize(Sender: TObject);
begin
  Timer2.Enabled := False;
end; { AppMinimize }

procedure TTimeMinForm.AppRestore(Sender: TObject);
begin
   Timer2.Enabled  := True;
end; { AppRestore }

procedure TTimeMinForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin

if (Msg.message = WM_KEYDOWN) or
   (Msg.message = WM_LBUTTONDOWN) or
   (Msg.message = WM_RBUTTONDOWN)

 then
   begin
   Timer2.Enabled := False;
   Timer2.Enabled := True;
   end; { endIf }

Handled := false;

end;  { ApplicationEvents1Message }

procedure TTimeMinForm.Timer2Timer(Sender: TObject);
begin

Application.Minimize;

end; { Timer2Timer }

procedure TTimeMinForm.SecondsEditChange(Sender: TObject);
begin
   Timer2.Interval := (1000 * StrToInt(SecondsEdit.text));
   Timer2.Enabled  := False;
   Timer2.Enabled  := True;
end; { SecondsEditChange }

end.

0
 
Russell LibbySoftware Engineer, Advisory Commented:
There was a specific reason for the messages being handled in my example, and now you know why...


  else if ((Msg.message >= WM_NCLBUTTONDOWN) and (Msg.message <= WM_NCMBUTTONDBLCLK)) then
   ... do what ever your doing ...


Please add checks for WM_NCLBUTTONDOWN to WM_NCMBUTTONDBLCLK

Regards,
Russell

0
 
WaterstoneAuthor Commented:

Thanks Rusell.  The reason I went to specific events as opposed to ranges was because I didn't want to trap for mousemovement, only mouse clicks and key presses.  It seems that WM_NCLBUTTONDOWN would cover WM_NCMBUTTONDBLCLK, so I added the NCLBUTTONDOWN to the code and it works fine.  The Scrollbar click  passes a message value of 161.  Just out of curriosity, do you know if there is documentation giving the numeric values for the windows message constants?
0
 
Russell LibbySoftware Engineer, Advisory Commented:

My code did not trap movement, which is why I avoided the WM_MOUSEFIRST.. WM_MOUSELAST constants. The messages are documented in the Windows SDK, which for D5 anyways is listed in the IDE's help menu.

Russell

0

Featured Post

How to Use the Help Bell

Need to boost the visibility of your question for solutions? Use the Experts Exchange Help Bell to confirm priority levels and contact subject-matter experts for question attention.  Check out this how-to article for more information.

  • 4
  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now