Friday, October 22, 2010

Sooo you got your first milion, now what?!

Let's just say that you just won € 1.7 mil. in lottery(tax free). What would you do with that much money in the current economy state?!
There are lots of things you can do with it, but the million euro question is: What's the best thing you can do with it, for you and MAYBE for others as well.
Let's just list a few possibilities:
- quit the job and waste the money;
- give the money to homeless people and help them start a fresh new life;
- give it to charity;
- start your own company(what kind of company, most of you that read this blog are developers, would you start a software company or do you think you can squeeze more money in other fields?!);
- buy the company in which you currently work(I'm sure it applies to many of you out there);
- buy a bigger house, bigger car, lots of bling-blings and biaches(I'm sure some of you want that -smile-);
- hold on to the money since there's no certain future coming;
- keep the money until pension, waste it then;
The above list is just off the top of my head — I disagree with at least half of the list — BUT I'm curious what other people would do with that much money.

No matter what you would do, consider this: money come and go, you're current job(if applies) is most likely pretty steady, you should take a deep breath before starting to think about how would you spend it and on what.
P.S. Don't forget, you also lose money(inflation which is a pretty big percent, let's say about 2%/year in Germany's or USA's case) by keeping it „safe¯ with each year.

Thursday, October 14, 2010

Message dialogs: you're doing it wrong...

No matter what you say or think, end-users are beasts, they will always find a way to make their life more complicated instead of reading messages or instructions...
I'm pretty sure AT least once in your life you pressed the wrong button on a message dialog, because you „thought¯ you know what it will ask you OR because you was in a hurry...
The main problem with the end-user is that (s)he will do this most of the times, let's suppose that you're asking the user if (s)he is sure to wipe a file or discard changes that are very important to him/her, even if the user should be blamed because (s)he didn't read the message, you're still the one that will be sweared.
So what can we do to overcome such a situation?! well not much without stressing the user BUT we can use a timed message dialog with which the user cannot interact for a amount of time — this will probably force the user to read the freaking message!
So here's my implementation of a timed message dialog:
unit uTimedMessageDlg;

interface

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

const
  CDEFAULT_WAIT_SEC = 10;
  CSECOND = 1000;
  CTIMED_MESSAGE = '%s (%d seconds)';

type
  TTimedMessageDlg = class(TObject)
  private
    FTimer: TTimer;
    FSeconds: Cardinal;
    FMessageForm: TForm;
    FCountDown: Integer;
    FCaption: string;
    procedure OnTimer(Sender: TObject);
    procedure OnDialogShow(Sender: TObject);
  public
    constructor Create;
    destructor Destroy; override;
  public
    function DisplayDialog(const Msg: string; const Args: array of const;
      DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
      const SecondsToWait: Cardinal = 10): Integer;
  public
    property Seconds: Cardinal
      read FSeconds write FSeconds;
  end;
  
function TimedMessageDlg(const Msg: string; const Args: array of const ;
  DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
  const SecondsToWait: Cardinal): Integer;

implementation

{ TTimedMessageDlg }

constructor TTimedMessageDlg.Create;
begin
  FTimer := TTimer.Create(NIL);
  FTimer.Enabled := False;
  FTimer.Interval := 1000;
  FTimer.OnTimer := OnTimer;
  FSeconds := 10;
end;

function TTimedMessageDlg.DisplayDialog(const Msg: string;
  const Args: array of const;
  DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
  const SecondsToWait: Cardinal = 10): Integer;
begin
  FMessageForm := CreateMessageDialog(Format(Msg, Args), DlgType, Buttons);
  FMessageForm.OnShow := OnDialogShow;
  FCountDown := SecondsToWait -1;
  FCaption := FMessageForm.Caption;
  FMessageForm.Caption := Format(CTIMED_MESSAGE, [FCaption, FCountDown]);
  FTimer.Interval := 1000;
  FTimer.Enabled := True;
  Result := FMessageForm.ShowModal;
  FreeAndNil(FMessageForm);
end;

destructor TTimedMessageDlg.Destroy;
begin
  FreeAndNil(FTimer);
  inherited;
end;

procedure TTimedMessageDlg.OnTimer(Sender: TObject);
begin
  Dec(FCountDown);
  FMessageForm.Caption := Format(CTIMED_MESSAGE, [FCaption, FCountDown]);
  if FCountDown <= 0 then begin
    FMessageForm.Caption := FCaption;
    FTimer.Enabled := False;
    FMessageForm.Enabled := True;
  end; // if FCountDown <= 0 then begin
end;

procedure TTimedMessageDlg.OnDialogShow(Sender: TObject);
begin
  FMessageForm.Enabled := False;
end;

function TimedMessageDlg(const Msg: string; const Args: array of const ;
  DlgType: TMsgDlgType; Buttons: TMsgDlgButtons;
  const SecondsToWait: Cardinal): Integer;
var
  TimedMessage: TTimedMessageDlg;
begin
  TimedMessage := TTimedMessageDlg.Create;
  Result := TimedMessage.DisplayDialog(Msg, Args, DlgType, Buttons,
    SecondsToWait);
  FreeAndNil(TimedMessage);
end;

end.
Sooo... what's the difference between normal and this custom message dialog?! nothing much, just that it can also format your message if you wish to AND the user cannot close or press any button on the message for the specified amount of time — I suggest to keep the time-out value somewhere between 3 to 7 seconds max.

Tuesday, October 12, 2010

Fun with callbacks and progress form

Some time ago I needed to display a progress form in order to give feedback to the user on current state of the task, therefore the „challenge¯ is pretty simple: a secondary form that will have a label — to display some info on current task — and two progress bars — for visual feedback — 1 progress bar for the „overall progress¯ and the other one for „current progress¯, this means that we have a task which is composed of few steps and each step has it's own progress.
Sooo... the MAIN idea is that the progress form needs to be displayed as modal while also calling a method(procedure) from another unit — this is where callbacks come into play.
What are callbacks?!

A callback is a reference to executable code, or a piece of executable code, that is passed as an argument to other code. This allows a lower-level software layer to call a subroutine (or function) defined in a higher-level layer.
For a better understanding of this article click this text to download the source code.
Let's achieve the same thing in a new project:
- add a button to this form
- add a new form to this application, remove it from auto-create forms(Project->Options->Forms)
- add two labels and two progress bars to the second form
- set the caption of one label to „Overall progress¯ and to the other label „Current progress¯
- name one progress bar „pbOverall¯ and the other „pbCurrent¯
Now let's write some code, first define the callback method as
type
  TProgressCallback = procedure (InProgressOverall, InProgressCurrent: TProgressBar) of Object;
we will pass „pbOverall¯ and „pbCurrent¯ as parameters in the callback method.
It's time to define a generic method that will create a new instance of our progress form in order to display a modal progress
procedure ShowProgress(InCallback: TProgressCallback);
var
  LWindowList: TTaskWindowList;
  LSaveFocusState: TFocusState;
  LProgressForm: TfrmProgressForm;
begin
  // create the instance
  LProgressForm := TfrmProgressForm.Create(NIL);
  try
    // save the focus state
    LSaveFocusState := SaveFocusState;
    // save the focused form
    Screen.SaveFocusedList.Insert(0, Screen.FocusedForm);
    // notify that a form will be displayed as modal
    Application.ModalStarted;
    // disable all other forms
    LWindowList := DisableTaskWindows(0);
    // set the progress form instance as the screen focused form 
    Screen.FocusedForm := LProgressForm;
    // send a active message
    SendMessage(LProgressForm.Handle, CM_ACTIVATE, 0, 0);
    // show the form
    LProgressForm.Show;
    // InCallback is our callback method to which we pass pbOverall and pbCurrent
    // as parameters so we can play with them later
    InCallback(LProgressForm.pbOverall, LProgressForm.pbCurrent);
    // after the callback is executed enable windows
    EnableTaskWindows(LWindowList);
    // restore focus state
    RestoreFocusState(LSaveFocusState);
  finally
    // notify that we're leaving a modal state
    Application.ModalFinished;
    // free and nil the progress form instance
    FreeAndNil(LProgressForm);
  end;
end;
all we have left to do now is to define a (private or public)method in main form with same parameters as the callback method like so:
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    // this is our callback method
    procedure ProgressCallback(InProgressOverall, InProgressCurrent: TProgressBar);
  public
    { Public declarations }
  end;
in the implementation section copy-paste this code
procedure TForm1.ProgressCallback(InProgressOverall,
  InProgressCurrent: TProgressBar);
var
  Index: Integer;
  kIndex: Integer;
begin
  MessageDlg('Press OK to start a long task...', mtInformation, [mbOK], 0);
  // 10 steps
  InProgressOverall.Max := 10;
  // 3000 updates per step
  InProgressCurrent.Max := 3000;
  for Index := 1 to InProgressOverall.Max do begin
    for kIndex := 1 to InProgressCurrent.Max do begin
      InProgressCurrent.Position := kIndex;
      // force application to process messages
      Application.ProcessMessages;
    end; // for kIndex := 1 to InProgressCurrent.Max do begin
    InProgressOverall.Position := Index;
    // force application to process messages
    Application.ProcessMessages;
  end; // for Index := 1 to InProgressOverall.Max do begin
  MessageDlg('Task completed!', mtInformation, [mbOK], 0);
end;
on the main form you have a button, in it's OnClick event add the following code:
ShowProgress(Self.ProgressCallback);
Any ideas on how to achieve the same effect in less code or more elegant?! please leave comment.

Blogroll(General programming and Delphi feeds)