Erstellen von Kurzhinweisen für die Metropolis-UI

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Entwickeln von Metropolis-UI-Anwendungen


Ein Kurzhinweis im Metropolis-UI-Stil ist ein Popup-Fenster, in dem hilfeähnliche Informationen angezeigt werden, wenn die Maus oder das Touch-Gerät über das Steuerelement geführt wird oder das Steuerelement berührt. In diesem Tutorial wird das Erstellen und Verwenden eines Kurzhinweises mit FireMonkey erläutert.

Erstellen eines neuen FireMonkey-Projekts:

  • Erstellen Sie eine neue Desktop-Anwendung für die Metropolis-UI:
    • Für Delphi: Datei > Neu > FireMonkey-Desktop-Anwendung für Metropolis-UI - Delphi > Leere Desktop-Anwendung für Metropolis-UI.
    • Für C++: Datei > Neu > FireMonkey-Desktop-Anwendung für Metropolis-UI - C++ > Leere Desktop-Anwendung für Metropolis-UI.
  • Speichern Sie das Projekt.

Definieren des ToolTip-Klassenobjekts

Erstellen Sie eine neue TToolTipPanel-Klasse für die Anwendung.

Führen Sie in Ihrer Unit die folgenden Schritte aus:

1. Fügen Sie die folgenden Units in den uses-Abschnitt ein:
  • Delphi:
uses
  FMX.Edit;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) den folgenden Code hinzu:
#include <FMX.Edit.hpp>
2. Definieren Sie die von TPanel abgeleitete Klasse TToolTipPanel.
  • Delphi:
 TToolTipPanel = class(TPanel)
  • C++: Definieren Sie diese neue Klasse in der Header-Datei (.h-Datei):
class TToolTipPanel : public TPanel { 
//class definition goes here
}
3. Fügen Sie ein TLabel als private-Feld hinzu, um Text für den Kurzhinweis hinzuzufügen: FLabel. Definieren Sie die public-Eigenschaft Text zusammen mit den Getter- und Setter-Funktionen der Eigenschaft Text, um auf den Text des Kurzhinweises zuzugreifen.
  • Delphi:
type
  TToolTipPanel = class(TPanel)
  private
    FLabel: TLabel;
    function GetToolTipText: string;
    procedure SetToolTipText(const Value: string);
  public
    property Text: string read GetToolTipText write SetToolTipText;
  end;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) den folgenden Code hinzu:
class TToolTipPanel : public TPanel {
private:
    TLabel *FLabel;
    UnicodeString _fastcall GetToolTipText();
    void _fastcall SetToolTipText (const UnicodeString Value);
public:
	
__published:
    __property UnicodeString Text = {read = GetToolTipText, write = SetToolTipText};     
	 
};
4. Implementieren Sie die Getter- und Setter-Funktionen der Eigenschaft Text wie folgt:
function TToolTipPanel.GetToolTipText: string;
begin
  Result := FLabel.Text;
end;
procedure TToolTipPanel.SetToolTipText(const Value: string);
begin
  FLabel.Text := Value ;
end;
  • C++:
    • Fügen Sie in der CPP-Datei den folgenden Code hinzu:
UnicodeString _fastcall TToolTipPanel::GetToolTipText() {
    return FLabel->Text;
}
// ---------------------------------------------------------------------------

void _fastcall TToolTipPanel::SetToolTipText(const UnicodeString Value) {
    FLabel->Text = Value;
}
5. Fügen Sie der Klasse TToolTipPanel zusätzlich zu den oben hinzugefügten die folgenden private-Member hinzu:
  • Delphi:
  private
    FMousePoint : TPointF; //keeps the current position for the mouse cursor
    FActiveControl : TFmxObject; //keeps the current active control for which the tooltip is displayed
    FTimer : TTimer; //the timer is used to decide when, in time, the tooltip is displayed and for how long,
                     // for the FActiveControl
    FCounter : Cardinal;//keeps a counter used on timer execution
    FOnlyInputFields : Boolean ; //this flag is used to decides if the tooltip is displayed only for
                                 // input controls 
    procedure OnTimer(Sender: TObject); //define the OnTime event handler for the FTimer
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) der Klasse TToolTipPanel den folgenden Code hinzu:
    TPointF FMousePoint;
    TFmxObject *FActiveControl;
    TTimer *FTimer;
    unsigned FCounter;
    bool FOnlyInputFields;
	
    void _fastcall OnTimer (TObject *Sender);
So stellen Sie das Flag FOnlyInputFields bereit:
  • Delphi: Fügen Sie die public-Eigenschaft OnlyInputFields wie folgt hinzu:
  public
    property OnlyInputFields : Boolean read FOnlyInputFields write FOnlyInputFields;
  • C++: Fügen Sie OnlyInputFields wie folgt als published-Eigenschaft hinzu:
    __property  bool OnlyInputFields = {read = FOnlyInputFields, write = FOnlyInputFields };
6. Fügen Sie für ein ansprechendes Design das private-Feld FBorderWidth und die public-Eigenschaft BorderWidth hinzu, um die Breite der Ränder des Kurzhinweises festzulegen und zu ermitteln. Die Ränder werden bei der Anzeige des Kurzhinweises berücksichtigt.
  • Delphi:
  private
    FBorderWidth : Single;
  public
    property BorderWidth : Single read FBorderWidth write FBorderWidth;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) der Klasse TToolTipPanel den folgenden Code hinzu:
private:
    float FBorderWidth;
__published:	 
    __property float BorderWidth = {read = FBorderWidth, write = FBorderWidth };
7. Definieren und implementieren Sie den Konstruktor und den Destruktor für die Klasse TToolTipPanel wie folgt:
  • Deklaration
  • Delphi:
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  • C++:
      • Fügen Sie in der Header-Datei (.h-Datei) der Klasse TToolTipPanel den folgenden Code hinzu:
public:
    __fastcall TToolTipPanel(TComponent* Owner);
    __fastcall virtual ~TToolTipPanel(void);
  • Implementierung
  • Delphi:
constructor TToolTipPanel.Create(AOwner: TComponent);
begin
  inherited; //inherits the behavior from TPanel 
  Visible := False; //initially, the tootltip is not visible
  StyleLookup := 'tooltippanel'; // sets the name of the ToolTip style
  //initialize FLabel
  FLabel := TLabel.Create(AOwner);
  FLabel.Parent := Self;
  FLabel.StyleLookup := 'tooltiplabel';
  FLabel.Text := Self.ToString;
  if assigned(FLabel.Canvas) then
    Height := FLabel.Canvas.TextHeight(FLabel.Text);
  FLabel.Align := TAlignLayout.Client;
  FLabel.TextAlign := TTextAlign.Center;
  FLabel.VertTextAlign := TTextAlign.Center;
  //initialize FTimer
  FTimer := TTimer.Create(AOwner);
  FTimer.OnTimer := OnTimer;
  FTimer.Enabled := True;
  FTimer.Interval := 500;
  FActiveControl := nil; //initially, there is no control for which to display the tootltip
  FCounter := 1000; //FCounter is initially set to a high value
  FBorderWidth := 10; //an initial value for the tooltip borders
end;

destructor TToolTipPanel.Destroy;
begin
  inherited;
end;
  • C++:
    • Fügen Sie in der CPP-Datei der Klasse TToolTipPanel den folgenden Code hinzu:
__fastcall TToolTipPanel::TToolTipPanel(TComponent* Owner) : TPanel(Owner){

    Visible = False;
    StyleLookup =  "tooltippanel";
    FLabel = new TLabel(this);
    FLabel->Parent = this;
    FLabel->StyleLookup =  "tooltiplabel";
    FLabel->Text = this->ToString();
    if (FLabel->Canvas != NULL) {  
        Height = FLabel->Canvas->TextHeight(FLabel->Text);
    }
    FLabel->Align = TAlignLayout::Client;
    FLabel->TextAlign = TTextAlign::Center;
    FLabel->VertTextAlign = TTextAlign::Center;
    FTimer = new TTimer(Owner);
    FTimer->OnTimer = OnTimer;
    FTimer->Enabled = true;
    FTimer->Interval = 500;
    FActiveControl = NULL;
    FCounter = 1000;
    FBorderWidth = 10;
    }
	//---------------------------------------------------------------------------
	
__fastcall TToolTipPanel::~TToolTipPanel() {

    }
8. Fügen Sie eine public-Methode hinzu, um den Kurzhinweis an der angegebenen Position anzuzeigen:
  • Delphi:
public
   procedure ShowToolTip(AX, AY: Single);

implementation
procedure TToolTipPanel.ShowToolTip(AX, AY: Single);
begin
  Position.Point := PointF(AX,AY); //sets the tooltip position to the specified point
  //calculates the size of the tooltip depending on the text to be displayed
  Height := FLabel.Canvas.TextHeight(FLabel.Text) + 2 * FBorderWidth;
  Width  := FLabel.Canvas.TextWidth(FLabel.Text) + 2 * FBorderWidth;
  //sets the tooltip as visible
  Visible := True;
end;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) der Klasse TToolTipPanel den folgenden Code hinzu:
public:
    __fastcall void ShowToolTip(float AX, float AY);
  • Fügen Sie in der CPP-Datei der Klasse TToolTipPanel den folgenden Code hinzu:
void __fastcall TToolTipPanel::ShowToolTip(float AX, float AY){
    Position->Point = PointF(AX,AY);
    Height = FLabel->Canvas->TextHeight(FLabel->Text)+ 2 * FBorderWidth;
    Width = FLabel->Canvas->TextWidth(FLabel->Text) + 2 * FBorderWidth;
    Visible = True;
    }
9. Ein Kurzhinweis wird typischerweise für die aktuelle Position des Cursors angezeigt. Ein Kurzhinweis zeigt auch Text an, der Informationen über die aktuelle Position enthält.
  • In diesem Fall zeigt der Kurzhinweis den folgenden Text an:
"ToolTip for component: "
und den Namen der Komponente, auf der sich der Mauszeiger befindet.
  • Wird keine Komponente gefunden, wird Folgendes angezeigt:
"ToolTip for mouse pos "
und die Koordinaten des Mauszeigers.
  • Wenn der Kurzhinweis nur für Eingabesteuerelemente definiert ist, wird dieser Text angezeigt:
"ToolTip for "
und der Name des Eingabesteuerelements mit dem Fokus. Der Kurzhinweis wird unter dem Eingabesteuerelement angezeigt, damit das Steuerelement nicht verdeckt wird und der Benutzer den Text eingeben kann.
Der angezeigte Text kann natürlich entsprechend Ihren Wünschen geändert werden.

Die OnTimer-Implementierung sollte wie folgt vorgenommen werden:

  • Delphi:
procedure TToolTipPanel.OnTimer;
var
  LActiveControl : IControl;
  LControl : TControl;
  LMousePos : TPointF;
  LObject : IControl ;
begin
  //test to detect for which kind of controls to display the control  
  if not FOnlyInputFields then
  begin
    // tests if the FMousePoint is actualized
    if Screen.MousePos <> FMousePoint then
    begin
      FMousePoint := Screen.MousePos ;
      FCounter := 0;
      Visible := False;
    end ;
    Inc(FCounter);
    case FCounter of
      0..2: Visible := False ;//simulates a delay on displaying the tooltip
      3:
      begin
        Text := '';
        if Parent is TForm then
        begin
          //identifies the object on which the mouse cursor is located
          LObject := (Parent as TForm).ObjectAtPoint(FMousePoint) ;
          if Assigned(LObject) then
            Text := LObject.GetObject.Name;
        end;
        //if no object is found, the tooltip displays the mouse cursor coordinates  
        if Text = '' then
          Text := 'ToolTip for mouse pos ' + PointToString(FMousePoint)
        else
          Text := 'ToolTip for component: ' + Text ;
        LMousePos := (Parent as TForm).ScreenToClient(FMousePoint);
        //displays the tooltip
        ShowToolTip(LMousePos.X, LMousePos.Y);
      end;
      // the tooltip is displayed for a limited time. In this case it is displayed until FCounter reaches 10
      4..10:;
    else
      FCounter := 1000;
      Visible := False ;
    end;
  end
  else
  begin
    //identifies the active control (the control in focus)
    if Parent is TForm then
      LActiveControl := (Parent as TForm).Focused;
    // checks if the object in focus is an input control (and a TEdit or a TEdit descendant) 
    if Assigned(LActiveControl) and (LActiveControl.GetObject <> FActiveControl) then
    begin
      Visible := False ;
      FActiveControl := LActiveControl.GetObject;
      if (FActiveControl is TEdit) then
        FCounter := 0;
    end;
    Inc(FCounter);
    case FCounter of
      0..2: Visible := False ;//simulates a delay on displaying the tooltip
      3..10: // the tooltip is displayed for the FActiveControl control, if it exists, under the input control,
             // so the tooltip doesn't cover the input area 
      begin
        if assigned(LActiveControl) then
        begin
          LControl := (LActiveControl as TControl);
          Text := 'ToolTip for ' + LControl.Name ;
          ShowToolTip(LControl.Position.X + 20, LControl.Position.Y + LControl.Height);
        end;
      end
    else
      FCounter := 1000;
      Visible := False ;
    end;
  end;
end;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) der Klasse TToolTipPanel den folgenden Code hinzu:
void __fastcall TToolTipPanel::OnTimer(TObject* Sender) {

    IControl *LActiveControl;
    TControl *LControl;
    TPointF LMousePos;
    IControl *LObject;

    if (!FOnlyInputFields) {
        if (Screen->MousePos() != FMousePoint) {
            FMousePoint = Screen->MousePos();
            FCounter = 0;
            Visible = False;
        }
        FCounter++;

        switch (FCounter) {
        case 0:
        case 1:
        case 2:
            Visible = False;
            break;
        case 3:
            Text = "";
            if ((dynamic_cast<TForm*>(Parent)) != NULL) {
                TForm& ref_object = dynamic_cast<TForm&>(*Parent);
                LObject = ref_object.ObjectAtPoint(FMousePoint);
                if (LObject != NULL) {
                    Text = LObject->GetObjectW()->Name;
                }
            }
            if (Text == "") {
                Text = "ToolTip for mouse pos " + PointToString(FMousePoint);
            }
            else {
                Text = "ToolTip for component: " + Text;
            }
            LMousePos = dynamic_cast<TForm*>(Parent)->ScreenToClient(FMousePoint);
            ShowToolTip(LMousePos.X, LMousePos.Y);
            break;
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
        case 9:
        case 10:
            break;
        default:
            FCounter = 1000;
            Visible = False; ;
        }
    }
    else {
        if ((dynamic_cast<TForm*>(Parent)) != NULL) {
            TForm& ref_LObject = dynamic_cast<TForm&>(*Parent);
            LActiveControl = ref_LObject.Focused;
            if ((LActiveControl != NULL) & (LActiveControl->GetObjectW()!= FActiveControl)) {
                Visible = False;
                FActiveControl = LActiveControl->GetObjectW();
                if ((dynamic_cast<TEdit*>(FActiveControl)) != NULL) {
                    FCounter = 0;
                }
            }
            FCounter++;
            switch (FCounter) {
            case 0:
            case 1:
            case 2:
                Visible = False;
                break;
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
            case 10:
                if (LActiveControl != NULL) {
                    LControl = System::interface_cast<TControl, IControl>(LActiveControl);
                    Text = "ToolTip for " + LControl->Name;
                    ShowToolTip(LControl->Position->X + 20, LControl->Position->Y + LControl->Height);
                }
                break;
            default:
                FCounter = 1000;
                Visible = False; ;
            }
        }
    }
}
10. Das endgültige Interface von TToolTipPanel sollte folgendermaßen aussehen:
  • Delphi:
type
  TToolTipPanel = class(TPanel)
  private
    FOnlyInputFields: Boolean;
    FMousePoint: TPointF;
    FCounter: Cardinal;
    FActiveControl: TFmxObject;
    FLabel: TLabel;
    FTimer: TTimer;
    FBorderWidth: Single;
    function GetToolTipText: string;
    procedure SetToolTipText(const Value: string);
    procedure OnTimer(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure ShowToolTip(AX, AY: Single);
    property Text: string read GetToolTipText write SetToolTipText;
    property BorderWidth: Single read FBorderWidth write FBorderWidth;
    property OnlyInputFields: Boolean read FOnlyInputFields
      write FOnlyInputFields;
  end;
  • C++:
class TToolTipPanel : public TPanel{
private:
    TLabel *FLabel;
    TPointF FMousePoint;
    TFmxObject *FActiveControl;
    TTimer *FTimer;
    unsigned FCounter;
    bool FOnlyInputFields;
    float FBorderWidth;
    UnicodeString _fastcall GetToolTipText();
    void _fastcall SetToolTipText (const UnicodeString Value);
    void _fastcall OnTimer (TObject *Sender);

public:
    __fastcall TToolTipPanel(TComponent* Owner);
    __fastcall virtual ~TToolTipPanel(void);
    __fastcall void ShowToolTip(float AX, float AY);   
__published:
     __property UnicodeString Text = {read = GetToolTipText, write = SetToolTipText};     
     __property  bool OnlyInputFields = {read = FOnlyInputFields, write = FOnlyInputFields }; 
     __property float BorderWidth = {read = FBorderWidth, write = FBorderWidth };   
};


Verwenden des Kurzhinweises

1. Fügen Sie im Formular-Designer Ihre Komponenten hinzu, zum Beispiel: eine TButton-Komponente, eine TCheckBox-Komponente, eine TEdit-Komponente, eine TMemo-Komponente, eine TRectangle-Komponente.
2. Fügen Sie in die Unit-Deklaration des Formulars die oben definierte Unit ToolTip ein.
3. Fügen Sie dem Formular einen private-Member mit dem Typ TToolTipPanel hinzu.
  • Delphi:
  private
   TT : TToolTipPanel;
  • C++:
    • Fügen Sie in der Header-Datei (.h-Datei) der private-Deklaration von TForm den folgenden Code hinzu:
private:	// User declarations
    TToolTipPanel *TT;
4. Erstellen Sie im Ereignis OnCreate des Formulars ein TToolTipPanel.
  • Delphi:
procedure TForm1.FormCreate(Sender: TObject);
begin
  TT := TToolTipPanel.Create(Form1);
  TT.Parent := Self ;
end;
  • C++:
__fastcall TForm1::TForm1(TComponent* Owner): TForm(Owner){
    TT = new TToolTipPanel(this);
    TT->Parent = this;
}
5. Um das Verhalten des Kurzhinweises für die Werte True oder False der Eigenschaft OnlyInputFields zu testen, fügen Sie Folgendes in das Ereignis OnChange des Steuerelements TCheckBox ein:
  • Delphi:
procedure TForm1.CheckBox1Change(Sender: TObject);
begin
   TT.OnlyInputFields := CheckBox1.IsChecked;
end;
  • C++:
void __fastcall TForm1::CheckBox1Change(TObject *Sender){
    TT->OnlyInputFields = CheckBox1->IsChecked;
}
6. Führen Sie die Anwendung aus.
Die folgenden Abbildungen zeigen den erstellten Kurzhinweis:
Tooltip over a component.png Tooltip mouse position.png
Die nächste Abbildung zeigt die Auswirkung eines Kurzhinweises für eine Eingabekomponente mit der auf True gesetzten Eigenschaft OnlyInputFields:
OnlyInputFields False.png OnlyInputFields True.png

Siehe auch