Metropolis UI ツールチップの作成
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 クラスに以下のコードを追加します。
-
- C++ の場合:
-
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 クラスに以下のコードを追加します。
- C++ の場合:
-
__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. フォーム デザイナで、コンポーネントを追加します(例: TButton、TCheckBox、TEdit、TMemo、TRectangle)。
- 2. フォーム ユニット宣言に、上で定義した ToolTip ユニットを追加します。
- 3. TToolTipPanel 型の private メンバをフォームに追加します。
-
- Delphi の場合:
private
TT : TToolTipPanel;
-
- C++ の場合:
- ヘッダー ファイル(.h ファイル)で TForm の private 宣言に以下のコードを追加します。
- C++ の場合:
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. アプリケーションを実行します。
- 次に示すのは、作成したツールチップのサンプル画像です。
-
- 次の画像は、OnlyInputFields プロパティを True に設定したときの、入力コンポーネントのツールチップの推測です。