Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Tastatureingabe an Formularen (https://www.delphipraxis.net/76623-tastatureingabe-formularen.html)

Tom65 7. Sep 2006 06:43


Tastatureingabe an Formularen
 
Ich möchte auf dem Hauptformular des Programmes (Form1) ein zweites Formular (Form2) ohne sichtbaren Rahmen (BorderStyle = bsNone) anzeigen. Dabei soll Form2 auch sichtbar bleiben, wenn mit der Maus auf Form1 geklickt wird. Die Titelleiste von Form1 soll blau bleiben wenn Form2 angezeigt wird und Form2 soll im OnKeyDown-Ereignis auf die Tastatureingaben reagieren. Aber an einem dieser Punkte scheitert es immer.
Bei

Form2.FormStyle = fsStayOnTop und
Form2.KeyPreview = true

lässt sich Form2 mit der Tastatur bedienen aber die Titelleiste von Form1 wird grau.
Bei

Form2.Parent:= Form1

wird Form2 angezeigt und die Titelzeile von Form1 bleibt blau aber Form2 lässt sich nicht mit der Tastatur bedienen.
Wie kann man dieses Problem lösen?

Mackhack 7. Sep 2006 07:04

Re: Tastatureingabe an Formularen
 
Brauchst du vlt. Delphi-Referenz durchsuchenWindows.SetParent?

Tom65 7. Sep 2006 07:31

Re: Tastatureingabe an Formularen
 
Soweit ich das sehe ist

Form2.SetParent(Form1);

das gleiche wie

Form2.Parent:= Form1;

Mackhack 7. Sep 2006 07:54

Re: Tastatureingabe an Formularen
 
I hab ja auch Windows.SetParent geschrieben und net FormX.Parent. Dann hast du 2 Argumente die du uebergeben musst.
Kann mich aber auch taeuschen! Ist schon spaet hier!

marabu 7. Sep 2006 08:32

Re: Tastatureingabe an Formularen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

Wenn aus irgendeinem Grund Frames keine akzeptable Lösung sind, dann darf es natürlich auch eine embedded form sein. Ich habe ein Demo-Projekt dazu angehängt. Wenn man die beispielhaften Controls nebst dem event handler ButtonClick() aus der ChildForm entfernt, dann kann man diese ChildForm als Template ins Object Repository stellen.

Grüße vom marabu

Tom65 7. Sep 2006 11:29

Re: Tastatureingabe an Formularen
 
Ich habe mir das Beispiel von Marabu angeschaut und es entsprechend modifiziert. Wenn das ChildFrm aktiv ist werden trotzdem alle Tastatureingaben, die im OnKeyDown-Ereignis definiert sind, vom DemoFrm(Hauptformular) abgefangen. Die Befehle im OnKeyDown-Ereignis vom ChildFrm werden nicht ausgeführt.

Viele Grüße

Tom

dataspider 7. Sep 2006 11:45

Re: Tastatureingabe an Formularen
 
Hi Tom,

das liegt an der VCL. Ich habe mir an dem Problem auch schon die Zähne ausgebissen.
Jetzt mach ich es so, dass ich über einen Keyboardhook das Form ermittle und eine eigene Nachricht sende.
Dann gibt es noch die Möglichkeit, nicht mit Parent sondern wie schon beschrieben mit Windows.SetParent zu arbeiten. So hab ich mir mal ein FormPanel erstellt.

Delphi-Quellcode:
unit RW_FormPanel;

interface

uses
  Forms, Windows, Messages, Classes, Controls, ExtCtrls;

type
  TRWFormPanel = class(TCustomPanel)
  private
    FForm: TCustomForm;
    FFormSaveParent: THandle;
    FFormSavePosition: TPosition;
    FFormSaveStyle: Integer;
    FFormSaveStyleEx: Integer;
    FFormSaveVisible: Boolean;
    FFormSaveWindowPlacement: TWindowPlacement;
    procedure SetForm(Value:TCustomForm);
  protected
    procedure Notification(AComponent : TComponent; Operation : TOperation);
        override;
    procedure SizeChanged;
    procedure WMSize(var Message:TMessage); message WM_SIZE;
  public
    constructor Create(AOwner:TComponent); override;
    property Form: TCustomForm read FForm write SetForm;
  published
    property Align;
    property Alignment;
    property Anchors;
    property AutoSize;
    property BevelInner;
    property BevelOuter default bvNone;
    property BevelWidth;
    property BiDiMode;
    property BorderStyle;
    property BorderWidth;
    property Caption;
    property Color;
    property Constraints;
    property Ctl3D;
    property DockSite;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Font;
    property FullRepaint;
    property OnCanResize;
    property OnClick;
    property OnConstrainedResize;
    property OnDblClick;
    property OnDockDrop;
    property OnDockOver;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnGetSiteInfo;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnStartDock;
    property OnStartDrag;
    property OnUnDock;
    property ParentBiDiMode;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property UseDockManager default True;
    property Visible;
  end;

implementation

procedure TRWFormPanel.Notification(AComponent : TComponent; Operation :
    TOperation);
begin
  inherited Notification( AComponent, Operation);
  if Assigned(FForm) then
    if (Operation = opRemove) and (AComponent = FForm) then
    begin
      // RemoveFreeNotification(AComponent);
      FForm := nil;
    end;
end;

procedure TRWFormPanel.SetForm(Value:TCustomForm);
begin
  try
    if (FForm = Value) then
      Exit;
    if csDesigning in ComponentState then
      Exit;

    // hat schon ein Form, also wiederherstellen
    if (FForm<>nil) and FForm.HandleAllocated then
    begin
      FForm.Visible := False;
      if not FFormSaveVisible then
        FFormSaveWindowPlacement.showCmd:=SW_HIDE;
      Windows.SetParent(FForm.Handle,FFormSaveParent);
      SetWindowPlacement(FForm.Handle,@FFormSaveWindowPlacement);
      SetWindowLong(FForm.Handle,GWL_STYLE,FFormSaveStyle);
      SetWindowLong(FForm.Handle,GWL_EXSTYLE,FFormSaveStyleEx);
      SetWindowPos(FForm.Handle,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE or
                   SWP_NOZORDER or SWP_FRAMECHANGED or SWP_NOACTIVATE);
      FForm.Visible := FFormSaveVisible;
      TForm(FForm).Position := FFormSavePosition;
    end;

    FForm:=Value;

    if FForm<>nil then
    begin
      FFormSaveStyle       := GetWindowLong(FForm.Handle,GWL_STYLE);
      FFormSaveStyleEx     := GetWindowLong(FForm.Handle,GWL_EXSTYLE);
      FFormSaveVisible     := FForm.Visible;
      FFormSaveParent      := GetParent(FForm.Handle);
      FFormSavePosition    := TForm(FForm).Position;
      TForm(FForm).Position := poDesigned;

      GetWindowPlacement(FForm.Handle,@FFormSaveWindowPlacement);

      SetWindowLong(FForm.Handle,GWL_STYLE,(FFormSaveStyle or WS_CHILD)
          and not WS_OVERLAPPED and not WS_OVERLAPPEDWINDOW and not WS_CAPTION);
      SetWindowLong(FForm.Handle,GWL_EXSTYLE,FFormSaveStyleEx and not WS_EX_MDICHILD);
      Windows.SetParent(FForm.Handle,self.Handle);
      SetWindowPos(FForm.Handle,HWND_BOTTOM,0,0,0,0,SWP_NOMOVE or SWP_NOSIZE or
                   SWP_NOZORDER or SWP_FRAMECHANGED or SWP_NOACTIVATE);
      FForm.Left:=0;
      FForm.Top:=0;
      SizeChanged;
      // FForm.Visible:=True;
      // FForm.SetFocus;
      // Application.ProcessMessages;
      FForm.FreeNotification(Self);
    end;
  except
    FForm := nil;
    if csLoading in ComponentState then
      Application.HandleException(Self)
    else
      raise;
  end;
end;

procedure TRWFormPanel.SizeChanged;
begin
  FForm.Width := ClientWidth;
  FForm.Height := ClientHeight;
end;

procedure TRWFormPanel.WMSize(Var Message:TMessage);
begin
  inherited;
  if FForm <> nil then
    SizeChanged;
end;

constructor TRWFormPanel.Create(AOwner:TComponent);
begin
  inherited;
//  BevelOuter := bvNone;
  Caption   := '';
end;

end.
Vielleicht hilft es dir ja weiter.

Cu, Frank

Tom65 7. Sep 2006 14:59

Re: Tastatureingabe an Formularen
 
@Dataspider

Vielen Dank für Deine Hilfe. Ich werde es testen.

Viele Grüße

Thomas

marabu 7. Sep 2006 18:17

Re: Tastatureingabe an Formularen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo.

In meiner Demo bin ich aus Schusseligkeit nicht auf die Sache mit dem KeyPreview eingegangen. Hier eine erweiterte Demo, die etwas Licht auf dieses Problem wirft.

Dazu muss man wissen, dass Borland die ParentForm eines Controls für die Überprüfung der Eigenschaft KeyPreview ermittelt, indem es den Top-Level-Parent des Controls sucht. Dadurch arbeitet KeyPreview bei ChildForms nicht auf die übliche Weise. KeyPreview muss bei der ParentForm von ChildForm gesetzt werden und nur dort wird die Eigenschaft von den VCL-Machern auch ausgewertet.

Es gibt jetzt zwei Strategien zum Umgang mit der Misere - neben dem Ansatz von Frank, den ich mangels Zeit jetzt nicht nachvollzogen habe: Man berücksichtigt die Designschwäche und gestaltet die event handler OnKeyDown() etc. entsprechend (siehe Demo) oder man verkettet die event handler im Ereignis OnCreate() der ChildForm.

Man beachte die von mir überschriebene Funktion GetParentForm():

Delphi-Quellcode:
function GetParentForm(Control: TControl): TCustomForm;
begin
  Result := nil;
  while Assigned(Control.Parent) do
  begin
    Control := Control.Parent;
    if Control is TCustomForm then
    begin
      Result := TCustomForm(Control);
      Break;
    end;
  end;
end;
So erkenne ich im event handler der DemoForm, ob ein Tastendruck auf einem eigenen Control oder einem Control der ChildForm ausgelöst wurde.

marabu

Tom65 8. Sep 2006 06:55

Re: Tastatureingabe an Formularen
 
@ marabu

Vielen Dank für Deine Hilfe. Jetzt habe ich es verstanden.

Grüße!

Tom


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz