user1596704
user1596704

Reputation: 21

Delphi: Create form which stays on top and doesnt activate

I am using WS_EX_NOACTIVATE, but form still can be activated by clicking on it. Testing under Windows 10, Delphi XE8. What am I doing wrong?

Main form (calling Form3.Show on button click):

unit Unit2;

...

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);

...

procedure TForm2.Button1Click(Sender: TObject);
begin
form3.Show;
end;

end.

toolbar form (form3):

unit Unit3;

...

type
  TForm3 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  protected
  procedure CreateParams(var Params: TCreateParams); override;
  public

...   

procedure TForm3.CreateParams(var Params: TCreateParams);
const WS_EX_NOACTIVATE = $8000000;
begin
  inherited;
  Params.ExStyle := Params.ExStyle + WS_EX_NOACTIVATE;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
FormStyle := fsStayOnTop;
end;

end.

Upvotes: 0

Views: 1119

Answers (1)

Alfred Doppler
Alfred Doppler

Reputation: 68

I am not able to post comments yet so I have to post as an answer.

You can quite easily achieve it by setting the focus on any window you want. Just use EnumWindows to get all windows and then use SetForegroundWindow to loose focus. I did this in my implementation of an onscreen keyboard.

This means while you are clicking your window will have focus. In the OnClick method you call SetForegroundWindow with the Handle you want to have focussed an you will loose focus again. If you use the OnMouseDown method you will loose focus even faster.

Here is production code I made around 6 years ago. You will have to modify it but I hope it will give you the idea what I am talking about.

  TWindowData = class(TObject)
  private
    FWDWindowHandle: HWND;
    FWDWindowCaption: string;
    FWDExeFileName: string;
    procedure SetWDExeFileName(const Value: string);
    procedure SetWDWindowCaption(const Value: string);
    procedure SetWDWindowHandle(const Value: HWND);
  public
    property WDWindowCaption:string read FWDWindowCaption write SetWDWindowCaption;
    property WDExeFileName:string read FWDExeFileName write SetWDExeFileName;
    property WDWindowHandle: HWND read FWDWindowHandle write SetWDWindowHandle;
  end;

function GetTitle (Hwnd: THandle; Param: Pointer): Boolean; stdcall;
{ get caption from every visible window }

var Text,TempString: string;
    Buf : Array [0..100] of Char;
begin
  result := True;
  If (GetWindowLong(Hwnd,GWL_HWNDPARENT)=0) and (IsWindowVisible(Hwnd) or IsIconic(Hwnd))then
  begin
  TempString := GetWindowExeName(Hwnd);
  SetLength (Text, 100);

  GetModuleFileName( Hwnd,buf, 100 );

  GetWindowText (Hwnd, PChar (Text), 100);
  if NoSystemWindowOrSelf(TempString,Text) then
  begin
    MainForm.OneWindowData := TWindowData.create;
    with MainForm.OneWindowData do
    begin
      WDWindowHandle := Hwnd;
      WDWindowCaption := Text;
      WDExeFileName := TempString;
    end;
    MainForm.WindowDataList.Add (MainForm.OneWindowData);
    MainForm.lbWindowListMemo.Items.Add(text); { Show all Windows in this Memo }

  end;
  Result := True;
  end;
end;

procedure TMainForm.bFillMemoClick(Sender: TObject);
var EWProc: EnumWindowsProc;
begin
  WindowListMemo.Items.Clear;
  WindowDataList.clear;

  { EnumWindows geht der Reihe nach alle offenen Fenster durch }
  EWProc := GetTitle;
  EnumWindows (@EWProc, 0);
end;

procedure TMainForm.FocusWindow;
{ Click on a Memo line to focus a window }
var TempWindowData : TWindowData;
begin
  TempWindowData := TWindowData(WindowDataList[WindowListMemo.itemindex]);
  SetForegroundWindow(TempWindowData.WDWindowHandle);
end;

Upvotes: 1

Related Questions