Metropolis UI ツールチップの作成

提供: RAD Studio
移動先: 案内検索

Metropolis UI アプリケーションの開発 への移動


Metropolis UI スタイル ツールチップは、マウスをコントロールの上に置いたりタッチ デバイスでコントロールをタッチしたときにヘルプのような情報を表示するポップアップ ウィンドウです。このチュートリアルでは、FireMonkey を使用したツールチップの作成と利用について説明します。

新しい FireMonkey プロジェクトを作成するには:

  • Metropolis UI デスクトップ アプリケーションを新規作成します。
    • Delphi の場合: [ファイル|新規作成|FireMonkey Metropolis UI デスクトップ アプリケーション - Delphi|新しい Metropolis UI デスクトップ アプリケーション]
    • C++ の場合: [ファイル|新規作成|FireMonkey Metropolis UI デスクトップ アプリケーション - C++Builder|新しい Metropolis UI デスクトップ アプリケーション]
  • プロジェクトを保存します。

ToolTip クラス オブジェクトの定義

アプリケーション用に新しいクラス TToolTipPanel を作成します。

ユニットで以下の手順を実施します。

1. uses セクションに以下のユニットを追加します。
  • Delphi の場合:
uses
  FMX.Edit;
  • C++ の場合:
    • ヘッダー ファイル(.h ファイル)に以下のコードを追加します。
#include <FMX.Edit.hpp>
2. TPanel から派生した TToolTipPanel クラスを定義します。
  • Delphi の場合:
 TToolTipPanel = class(TPanel)
  • C++ の場合: この新しいクラスをヘッダー ファイル(.h ファイル)で定義します。
class TToolTipPanel : public TPanel { 
//class definition goes here
}
3. ツールチップにテキストを追加するために、TLabel 型の private フィールド FLabel を追加します。ツールチップのテキストにアクセスできるよう、public の Text プロパティと、その Text プロパティの取得アクセサ関数および設定アクセサ関数を定義します。
  • 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++ の場合:
    • ヘッダー ファイル(.h ファイル)に以下のコードを追加します。
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. Text プロパティの取得アクセサ関数および設定アクセサ関数を次のように実装します。
function TToolTipPanel.GetToolTipText: string;
begin
  Result := FLabel.Text;
end;
procedure TToolTipPanel.SetToolTipText(const Value: string);
begin
  FLabel.Text := Value ;
end;
  • C++ の場合:
    • .cpp ファイルに以下のコードを追加します。
UnicodeString _fastcall TToolTipPanel::GetToolTipText() {
    return FLabel->Text;
}
// ---------------------------------------------------------------------------

void _fastcall TToolTipPanel::SetToolTipText(const UnicodeString Value) {
    FLabel->Text = Value;
}
5. 上で追加した他に、次の private メンバを TToolTipPanel クラスに追加します。
  • 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++ の場合:
    • ヘッダー ファイル(.h ファイル)内の TToolTipPanel クラスに以下のコードを追加します。
    TPointF FMousePoint;
    TFmxObject *FActiveControl;
    TTimer *FTimer;
    unsigned FCounter;
    bool FOnlyInputFields;
	
    void _fastcall OnTimer (TObject *Sender);
FOnlyInputFields フラグを公開するには:
  • Delphi の場合: public の OnlyInputFields プロパティを追加します。
  public
    property OnlyInputFields : Boolean read FOnlyInputFields write FOnlyInputFields;
  • C++ の場合: OnlyInputFields を published プロパティとして追加します。
    __property  bool OnlyInputFields = {read = FOnlyInputFields, write = FOnlyInputFields };
6. デザイン用に、private のフィールド FBorderWidth と public のプロパティ BorderWidth を追加して、ツールチップの境界の幅を設定および取得できるようにします。この境界は、ツールチップを表示するときに使用します。
  • Delphi の場合:
  private
    FBorderWidth : Single;
  public
    property BorderWidth : Single read FBorderWidth write FBorderWidth;
  • C++ の場合:
    • ヘッダー ファイル(.h ファイル)内の TToolTipPanel クラスに以下のコードを追加します。
private:
    float FBorderWidth;
__published:	 
    __property float BorderWidth = {read = FBorderWidth, write = FBorderWidth };
7. TToolTipPanel クラスのコンストラクタおよびデストラクタを次のように定義し実装します。
  • 宣言
  • Delphi の場合:
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  • C++ の場合:
      • ヘッダー ファイル(.h ファイル)内の TToolTipPanel クラスに以下のコードを追加します。
public:
    __fastcall TToolTipPanel(TComponent* Owner);
    __fastcall virtual ~TToolTipPanel(void);
  • 実装
  • 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++ の場合:
    • .cpp ファイル内の TToolTipPanel クラスに以下のコードを追加します。
__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. 指定した位置にツールチップを表示するための public メソッドを追加します。
  • 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++ の場合:
    • ヘッダー ファイル(.h ファイル)内の TToolTipPanel クラスに以下のコードを追加します。
public:
    __fastcall void ShowToolTip(float AX, float AY);
  • .cpp ファイル内の TToolTipPanel クラスに以下のコードを追加します。
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. 通常、ツールチップはカーソルの現在位置に表示されます。また、ツールチップには現在位置についての情報を示すテキストも表示されます。
  • ここでは、ツールチップに次のテキストを表示します。
"ToolTip for component: "
それに続いて、マウス カーソルが置かれているコンポーネントの名前を表示します。
  • コンポーネントが見つからない場合の表示は次のようになります。
"ToolTip for mouse pos "
そして、その後にマウス カーソルの座標を表示します。
  • 入力コントロールだけにツールチップを表示するよう設定した場合には、ツールチップに次のテキストを表示します。
"ToolTip for "
続けて、フォーカスが当たっている入力コントロールの名前を表示します。また、ツールチップがコントロールを隠すことなくユーザーがテキストを入力できるよう、ツールチップを入力コントロールの下に表示します。
表示するテキストは、もちろん、必要に応じて変更可能です。

OnTimer の実装は次のようになります。

  • 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++ の場合:
    • ヘッダー ファイル(.h ファイル)内の TToolTipPanel クラスに以下のコードを追加します。
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. TToolTipPanel の最終的なインターフェイスは次のようになります。
  • 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 };   
};


ToolTip の使用

1. フォーム デザイナで、コンポーネントを追加します(例: TButtonTCheckBoxTEditTMemoTRectangle)。
2. フォーム ユニット宣言に、上で定義した ToolTip ユニットを追加します。
3. TToolTipPanel 型の private メンバをフォームに追加します。
  • Delphi の場合:
  private
   TT : TToolTipPanel;
  • C++ の場合:
    • ヘッダー ファイル(.h ファイル)で TForm の private 宣言に以下のコードを追加します。
private:	// User declarations
    TToolTipPanel *TT;
4. フォームの OnCreate イベント内で、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. OnlyInputFields プロパティが True または False に設定されたときのツールチップの動作をテストできるよう、TCheckBox の OnChange イベントに以下のコードを追加します。
  • Delphi の場合:
procedure TForm1.CheckBox1Change(Sender: TObject);
begin
   TT.OnlyInputFields := CheckBox1.IsChecked;
end;
  • C++ の場合:
void __fastcall TForm1::CheckBox1Change(TObject *Sender){
    TT->OnlyInputFields = CheckBox1->IsChecked;
}
6. アプリケーションを実行します。
次に示すのは、作成したツールチップのサンプル画像です。
Tooltip over a component.pngTooltip mouse position.png
次の画像は、OnlyInputFields プロパティを True に設定したときの、入力コンポーネントのツールチップの推測です。
OnlyInputFields False.pngOnlyInputFields True.png

関連項目