Delphi Programming / Object Pascal
[掲載 2012年07月24日] [更新 2014年06月27日] Delphi サンプルプログラム集
083_TStringGrid 等のセル編集とインプレイスエディタ
動作確認等
Windows XP(SP3) + Delphi XE Pro + Microsoft Office IME 2007
Windows 7 U64(SP1) + Delphi XE Pro + Microsoft Office IME 2010
083_InplaceEditor.zip [5,114 KB] 2014年06月27日版 (EXE 同梱)
2014年04月26日
TStringGrid と TDBGrid の日本語 IME の無効化のコードを変更して,Delphi XE2 以降にも対応したサンプルとした
日本語 IME の無効化関係の記事を追加
TStringGrid 等のセル編集とインプレイスエディタ
主に,TStringGrid や TDBGrid のセルを編集する際に,日本語入力用の IME を制御するサンプルプログラムです.
TStringGrid や TDBGrid のセルのテキストの編集を開始すると,インプレイスエディタというエディタが起動します.セルのテキストの編集は,このエディタで行われます.
インプレイスエディタのクラス名は,TInplaceEdit で,TCustomEdit,TCustomMaskEdit から継承されているクラスです.TEditには,TCustomEditから拡張された機能はありませんから,TInplaceEdit は TEditの持つ機能を全て持っているということになります.
TInpaceEdit は protected 部にあるため,そのままでは利用できません.そこで,このページのサンプルでは TStringGrid 等の継承クラスを作成して操作しています.
継承クラスを作成するということは,コンポーネントを作成するということですが,作成したコンポーネントを登録,インストールするのは面倒なので,[派生元のコンポーネントと交換する方法]で説明しているユニットを使用してテストしています.
TListView,TTreeView には TInplaceEdit に相当するクラスの実装はありません.インプレイスエディタのハンドルを取得して操作することになります.
マイクロソフトでは,このエディタを単に「エディトコントロール」としていますが,ここでは,インプレイスなエディタなので,そのままインプレイスエディタと呼ぶことにします.
01_ TStringGrid - GetEditText イベントで処理
GetEditText イベントは,セルの編集を開始すると発生します.このイベント内でインプレイスエディタのハンドルを取得し,IME を設定します.
ACol の値が 1 の時だけ IME を imHira にし,それ以外では imDisable にします.また,編集中の背景色を変更しています.
図1
設計時画面
図2
imHira の列の場合
図3
imDisable の列の場合
リスト1
TStringGrid のセル編集時に日本語 IME を制御する
protected 部の GetEditText イベントで処理
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ExtCtrls;
type
TForm1 = class (TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
procedure StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: string );
procedure StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string );
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
{$R *.dfm}
// protected部にアクセスするためのクラス宣言
type
TMyStringGrid = class (TStringGrid);
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
// StringGrid1のセルを編集可能にする
StringGrid1.Options := StringGrid1.Options + [goEditing];
end ;
// =============================================================================
// StringGrid1のOnGetEditTextイベント処理
//
// インプレイスエディタが起動し,セルの値を取得してセットする時に発生する
// 引数のValueに値をセットすると,インプレイスエディタ起動時にその値となる
// =============================================================================
procedure TForm1.StringGrid1GetEditText(Sender: TObject; ACol, ARow: Integer;
var Value: string );
var
InpEdit : TInplaceEdit;
hInpEdit : HWND;
begin
// インプレイスエディタのオブジェクトを取得
InpEdit := TMyStringGrid(StringGrid1).InplaceEditor;
if Assigned(InpEdit) then begin
// インプレイスエディタのハンドルを取得して,IMEモードを設定
hInpEdit := InpEdit.Handle;
if ACol = 1 then begin
SetImeMode(hInpEdit, imHira);
end else begin
Win32NLSEnableIME(hInpEdit, False);
end ;
// InplaceEditの背景色の設定
InpEdit.Brush.Color := clSkyBlue;
end ;
end ;
// =============================================================================
// StringGrid1のOnSetEditTexイベント処理
// インプレスエディタの値が変化すると自動的に実行される
// =============================================================================
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol, ARow: Integer;
const Value: string );
begin
// Panel1にインプレイスエディトの値を逐次表示
Panel1.Caption := Value;
end ;
end .
02_ TStringGrid - 継承クラスの CanEditShow メソッドで処理
TStringGrid の継承クラスを作成して,protected 部の CanEditShow メソッド内で処理する例です.
CanEditShow メソッドは,セルの編集開始時に,自動的に実行されるメソッドです.動作仕様は,上のサンプルと同じです.
図4
設計時画面
リスト2
TStringGrid のセル編集時に日本語 IME を制御する
継承クラスの
CanEditShow
メソッドで処理
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ExtCtrls;
type
TMyStringGrid = class (TStringGrid)
protected
function CanEditShow: Boolean; override ;
function GetEditText(ACol: Integer; ARow: Integer): string ; override ;
procedure SetEditText(ACol: Integer; ARow: Integer; const Value: string );
override ;
end ;
TForm1 = class (TForm)
StringGrid1: TStringGrid;
Panel1: TPanel;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
MyStringGrid1 : TMyStringGrid;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plChgCompo;
{$R *.dfm}
// インプレイスエディタのprotected部にアクセスするための宣言
type
TMyInpEdit = class (TInplaceEdit);
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
// フォーム作成時にコンポーネントを入れ換えて,セルを編集可能にする
MyStringGrid1 := TMyStringGrid(ChangeComponent(StringGrid1, TMyStringGrid));
MyStringGrid1.Options := MyStringGrid1.Options + [goEditing];
end ;
{ TMyStringGrid }
// =============================================================================
// TStringGridのCanEditShowメソッド
// インプレースエディタが起動した時に実行される
// =============================================================================
function TMyStringGrid.CanEditShow: Boolean;
begin
Result := inherited CanEditShow;
// フォントのサイズと背景色を設定
if InplaceEditor <> nil then begin
TMyInpEdit(InplaceEditor).Font.Size := 12 ;
InplaceEditor.Brush.Color := clSkyBlue;
if Col = 1 then begin
SetImeMode(InplaceEditor.Handle, imHira);
end else begin
Win32NLSEnableIME(InplaceEditor.Handle, False);
end ;
end ;
end ;
// =============================================================================
// TStringGridのGetEditTextメソッド
// インプレイスエディタがセルの値を受け取る時に実行される
// 戻り値の値がインプレイスエディタ起動時にセットされる
// =============================================================================
function TMyStringGrid.GetEditText(ACol, ARow: Integer): string ;
begin
Result := inherited GetEditText(ACol, ARow);
end ;
// =============================================================================
// TStringGridのSetEditTexメソッド
// インプレスエディタの値が変化すると自動的に実行される
// =============================================================================
procedure TMyStringGrid.SetEditText(ACol, ARow: Integer; const Value: string );
begin
inherited ;
// Panel1にインプレイスエディトの値を逐次表示
Form1.Panel1.Caption := Value;
end ;
end .
03_ TDBGrid - 継承クラスの CanEditShow メソッドで処理
TDBGrid にも CanEditShow メソッドがあります.TDBGrid の継承クラスを作成して,このメソッド内で処理する例です.
このサンプルは,Delphi 付属のデータベースエンジンの BDE 接続で,Paradox のデータベースを使用しています.
図5
設計時画面
図6
実行開始画面
図7
日本語 IME は imHira
図8
日本語 IME は imHira
リスト3
TDBgGrid のセル編集時に日本語 IME を制御する
継承クラスの CanEditShow メソッドで処理
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids, ExtCtrls, DB, DBTables, DBGrids;
type
TMyDBGrid = class (TDBGrid)
protected
function CanEditShow: Boolean; override ;
function GetEditText(ACol: Integer; ARow: Integer): string ; override ;
procedure SetEditText(ACol: Integer; ARow: Integer; const Value: string );
override ;
end ;
TForm1 = class (TForm)
Panel1: TPanel;
DBGrid1: TDBGrid;
DataSource1: TDataSource;
Table1: TTable;
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
MyDBGrid1 : TMyDBGrid;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plChgCompo;
{$R *.dfm}
// インプレイスエディタのprotected部にアクセスするための宣言
type
TMyInpEdit = class (TInplaceEdit);
// =============================================================================
// フォーム生成時の処理
//
// 配置コンポーネント類の設定は以下の通り
//
// Table1.DatabaseName := DBDEMOS;
// Table1.TableName := customer.db;
// DataSource1.DataSet := Table1;
// DBGrid1.DataSource := DataSource1;
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
// フォーム作成時にコンポーネントを入れ換える
MyDBGrid1 := TMyDBGrid(ChangeComponent(DBGrid1, TMyDBGrid));
// データベースの表を開く
Table1.Active := True;
// 行の高さを設定
MyDBGrid1.DefaultRowHeight := 23 ;
end ;
{ TMyDBGrid }
// =============================================================================
// TDBGridのCanEditShowメソッド
// インプレースエディタが起動した時に自動的に実行される
// =============================================================================
function TMyDBGrid.CanEditShow: Boolean;
begin
Result := inherited CanEditShow;
if InplaceEditor <> nil then begin
// セルの背景色
InplaceEditor.Brush.Color := clMoneyGreen;
// フォントの設定
TMyInpEdit(InplaceEditor).Font.Color := clBlue;
// セルの枠線
TMyInpEdit(InplaceEditor).BorderStyle := bsSingle;
// キャレットの位置
InplaceEditor.SelStart := 0 ;
if Col = 2 then begin
SetImeMode(InplaceEditor.Handle, imHira);
end else begin
Win32NLSEnableIME(InplaceEditor.Handle, False);
end ;
end ;
end ;
// =============================================================================
// TDBGridのGetEditTextメソッド
// インプレイスエディタがセルから値を受け取る時に自動的に実行される
// 戻り値の値がインプレイスエディタにセットされる
// 本サンプルでは使用していないので実装しなくともよい.参考用
// =============================================================================
function TMyDBGrid.GetEditText(ACol, ARow: Integer): string ;
begin
Result := inherited GetEditText(ACol, ARow);
end ;
// =============================================================================
// TDBGridのSetEditTexメソッド
// インプレスエディタの値が変化すると自動的に実行される
// =============================================================================
procedure TMyDBGrid.SetEditText(ACol, ARow: Integer; const Value: string );
begin
inherited ;
// Panel1にインプレイスエディトの値を逐次表示
Form1.Panel1.Caption := Value;
end ;
end .
04_ TListView - Editing イベントで処理
ListView の Editing イベントは,Item の Caption の編集を開始されると実行されます.このイベント内で処理する例です.
図9
設計時画面
図10
実行結果
編集を開始したら,日本語 IME を imHira にする
リスト4
TListView の Caption 編集時に日本語 IME を制御する
Editing イベントで処理
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm1 = class (TForm)
Button1: TButton;
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure ListView1Editing(Sender: TObject; Item: TListItem;
var AllowEdit: Boolean);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses CommCtrl;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
AColumn : TListColumn;
AItem : TListItem;
begin
ListView1.ViewStyle := vsReport;
// カラムを作成
AColumn := ListView1.Columns.Add;
AColumn.Width := 130 ;
AColumn.Caption := '項目' ;
AColumn := ListView1.Columns.Add;
AColumn.Width := 60 ;
AColumn.Caption := '値' ;
// テスト用のデータをセット
AItem := ListView1.Items.Add;
AItem.Caption := 'A' ;
AItem.SubItems.Add('Sub A' );
AItem := ListView1.Items.Add;
AItem.Caption := 'B' ;
AItem.SubItems.Add('Sub B' );
AItem := ListView1.Items.Add;
AItem.Caption := 'C' ;
AItem.SubItems.Add('Sub C' );
end ;
// =============================================================================
// ListViewのItemが0のCaptionを編集状態にする
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
ListView1.ItemIndex := 0 ;
ListView1.Selected.EditCaption;
end ;
// =============================================================================
// ListView1のOnEditingイベント
// Captionの編集開始時に呼ばれるイベント
//
// ListView_GetEditControlの使用には,usesにCommCtrlが必要
// =============================================================================
procedure TForm1.ListView1Editing(Sender: TObject; Item: TListItem;
var AllowEdit: Boolean);
var
EditHandle : HWND;
begin
// インプレースエディタのハンドルを取得
EditHandle := ListView_GetEditControl(ListView1.Handle);
if EditHandle > 0 then begin
SetImeMode(EditHandle, imHira);
end ;
end ;
end .
05_ TListView - 継承クラスの CNNotify メソッドで処理
TListView のようなコモンコントロールでは,通知メッセージが発生すると,CNNotify メソッドが自動的に実行されます.このメソッド内で処理する例です.
インプレイスエディタの起動時の通知メッセージ
LVN_BEGINLABELEDI で IME を imHira にし,インプレイスエディタが閉じるときの通知メッセージ
LVN_ENDLABELEDIT で imClose にします.
図11
設計時画面
図12
編集開始
図13
編集終了
リスト5
TListView の Caption 編集時に日本語 IME を制御する
継承クラスの CNNotify メソッドを使用
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, CommCtrl, ExtCtrls;
type
TMyListView = class (TListView)
protected
procedure CNNotify(var Message: TWMNotifyLV); message CN_NOTIFY;
function CanEdit(Item: TListItem): Boolean; override ;
procedure Edit(const Item: tagLVITEMW); override ;
end ;
TForm1 = class (TForm)
Button1: TButton;
ListView1: TListView;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
MyListView1 : TMyListView;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plChgCompo;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
AColumn : TListColumn;
AItem : TListItem;
begin
// フォーム作成時にコンポーネントを入れ換える
MyListView1 := TMyListView(ChangeComponent(ListView1, TMyListView));
MyListView1.ViewStyle := vsReport;
// カラムを作成
AColumn := MyListView1.Columns.Add;
AColumn.Width := 130 ;
AColumn.Caption := '項目' ;
AColumn := MyListView1.Columns.Add;
AColumn.Width := 60 ;
AColumn.Caption := '値' ;
// テスト用のデータをセット
AItem := MyListView1.Items.Add;
AItem.Caption := 'A' ;
AItem.SubItems.Add('Sub A' );
AItem := MyListView1.Items.Add;
AItem.Caption := 'B' ;
AItem.SubItems.Add('Sub B' );
AItem := MyListView1.Items.Add;
AItem.Caption := 'C' ;
AItem.SubItems.Add('Sub C' );
end ;
// =============================================================================
// ListViewのCaptionを編集状態にする
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
MyListView1.ItemIndex := 0 ;
MyListView1.Selected.EditCaption;
end ;
{ TMyListView }
// =============================================================================
// CanEditメソッド
// 編集状態に入ると自動実行される
// 本サンプルでは使用していないので実装しなくともよい.参考用
// =============================================================================
function TMyListView.CanEdit(Item: TListItem): Boolean;
begin
Result := inherited CanEdit(Item);
end ;
// =============================================================================
// Editメソッド
// 編集が終了すると自動実行される
// 編集状態を[キャンセル]した場合は実行されない
// 本サンプルでは使用していないので実装しなくともよい.参考用
// =============================================================================
procedure TMyListView.Edit(const Item: tagLVITEMW);
begin
inherited ;
end ;
// =============================================================================
// CNNotifyメソッド(WM_NOTIFYメッセージ処理)
// TWMNotifyLVはDelphi 2007以降の実装.それより前ではTWMNotifyを使用する
// =============================================================================
procedure TMyListView.CNNotify(var Message: TWMNotifyLV);
var
hWindow : HWND;
begin
// 編集状態に入ればこの値はインプレイスエディタのハンドル
hWindow := Message.NMHdr.hwndFrom;
// 通知メッセージを判定して操作
if Message.NMHdr.code = LVN_BEGINLABELEDIT then begin
SetImeMode(hWindow, imHira);
end else
if Message.NMHdr.code = LVN_ENDLABELEDIT then begin
SetImeMode(hWindow, imClose);
end ;
inherited ;
end ;
end .
06_ TTreeView - 継承クラスの CNNotify メソッドで処理
コモンコントロールである TTreeView も通知メッセージが発生すると,CNNotify メソッドが自動的に実行されます.このメソッド内で処理する例です.
インプレイスエディタの起動時の通知メッセージは,TVN_BEGINLABELEDIT で,インプレイスエディタが閉じるときの通知メッセージは,TVN_ENDLABELEDIT です.
図14
設計時画面
図15
編集開始
図16
編集終了
リスト6
TTreeView の Cation 編集時に日本語 IME を制御する
継承クラスの CNNotify メソッドを使用
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, CommCtrl;
type
TMyTreeView = class (TTreeView)
protected
function CanEdit(Node: TTreeNode): Boolean; override ;
procedure Edit(const Item: tagTVITEMW); override ;
procedure CNNotify(var Message: TWMNotifyTV); message CN_NOTIFY;
end ;
TForm1 = class (TForm)
Button1: TButton;
TreeView1: TTreeView;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
MyTreeView1 : TMyTreeView;
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses plChgCompo;
{$R *.dfm}
// =============================================================================
// フォーム生成時の処理
// =============================================================================
procedure TForm1.FormCreate(Sender: TObject);
var
Node : TTreeNode;
begin
// フォーム作成時にコンポーネントを入れ換える
MyTreeView1 := TMyTreeView(ChangeComponent(TreeView1, TMyTreeView));
// テスト用のノード(Item)を作成
Node := TreeView1.Items.Add(nil , 'NODE_0' );
TreeView1.Items.AddChild(Node, 'NODE_0_ SUB1' );
TreeView1.Items.AddChild(Node, 'NODE_0_ SUB2' );
TreeView1.Items.AddChild(Node, 'NODE_0_ SUB3' );
Node := TreeView1.Items.Add(nil , 'NODE_1' );
TreeView1.Items.AddChild(Node, 'NODE_1_ SUB1' );
TreeView1.Items.AddChild(Node, 'NODE_1_ SUB2' );
// ノードを全て展開
TreeView1.FullExpand;
end ;
// =============================================================================
// TreeView1のItemを選択して編集状態にする
// =============================================================================
procedure TForm1.Button1Click(Sender: TObject);
begin
TreeView1.SetFocus;
TreeView1.Items[2 ].Selected := True;
// 編集開始
TreeView1.Selected.EditText;
end ;
{ TMyTreeView }
// =============================================================================
// CanEditメソッド
// 編集状態に入ると自動実行される
// 本サンプルでは使用していないので実装しなくともよい.参考用
// =============================================================================
function TMyTreeView.CanEdit(Node: TTreeNode): Boolean;
begin
Result := inherited CanEdit(Node);
end ;
// =============================================================================
// Editメソッド
// 編集が終了すると自動実行される
// 編集状態を[キャンセル]した場合は実行されない
// 本サンプルでは使用していないので実装しなくともよい.参考用
// =============================================================================
procedure TMyTreeView.Edit(const Item: tagTVITEMW);
begin
inherited ;
end ;
// =============================================================================
// CNNotifyメソッド(WM_NOTIFYメッセージ処理)
// TWMNotifyTVはDelphi 2007以降の実装.それより前ではTWMNotifyを使用する
// =============================================================================
procedure TMyTreeView.CNNotify(var Message: TWMNotifyTV);
var
hWindow : HWND;
begin
// 編集状態に入ればこの値はインプレイスエディタのハンドル
hWindow := Message.NMHdr.hwndFrom;
// 通知メッセージを判定して操作
if Message.NMHdr.code = TVN_BEGINLABELEDIT then begin
SetImeMode(hWindow, imHira);
end else
if Message.NMHdr.code = TVN_ENDLABELEDIT then begin
SetImeMode(hWindow, imClose);
end ;
inherited ;
end ;
end .
07_ インプレイスエディタにおける日本語 IME の無効化
本ページの最初の方の TStringGrid と TDBGrid のインプレイスエディタで,日本語 IME を閉じて無効にするのに,Win32NLSEnableIME 関数を使用しています.
一般に,日本語 IME を閉じて無効にするには,次のようなコードを実行します.ここで,Edit.Handle は,入力コントロールのハンドルです.インプレイスエディタの場合は,そのハンドルです.
SetImeMode(Edit.Handle, imDisable);
上のコードは,TStringGrid と TDBGrid のインプレイスエディタでは,Delphi XE2 UP1 以降で正常に機能しないことがあります.Delphi XE では正常に動作します.
上のコードで日本語 IME を無効にすると,その後,日本語 IME が制御できなくなる場合があります.つまり,かな漢字入力状態にするこができなくなります.
この現象をを回避するために,2014年04月26日の更新で,Win32NLSEnableIME を使用するコードに変更しました.Win32NLSEnableIME は,内部で WINNLSEnableIME を実行しているだけです.
下図は,Delphi XE5(UP2) Pro での実行結果です.
最初のサンプルで,SetImeMode(hInpEdit, imDisable); を使用した場合です.
「文字列」という文字列を入力した後,「ABC」を入力しています.その後,第 1 列目にフォーカスを移動していますが,日本語 IME が ON にならないため,キーボードでタイプした文字がそのまま入力されています.
[備考]
Win32NLSEnableIME 関数を使用して日本語 IME を無効にする方法は,全てのインプレイスエディタで正常に機能するわけではないようです.次項の ImmAssociateContext 関数で無効化した方が正常に機能する場合もあります.これは,コントロールの内部仕様によるものと思われます.
図17
1 列目の IME が ON にならない
08_ TEdit 等の入力コントロールの日本語 IME の無効化
前項の説明は,Delphi XE2 UP1 以降の場合でした.今度は Delphi XE2 UP1 よりも前の Delphi で日本語 IME を閉じて無効にする際の参考です.インプレイスエディタではなく,TEdit 等,一般の入力コントロールの場合です.
前項で示した SetImeMode の ImeMode を imDisable にして,日本語 IME を無効にした後,他の入力コントロールにフォーカスを移動しても,日本語 IME が制御できなくなる現象が発生することがあります.また,かな漢字入力にした後,imDisable のコントロールでの入力が半角の英数字にならないことがあります.
この現象を回避するには,下のサンプルのように,ImmAssociateContext 関数を使用します.
この現象は,Delphi XE2 UP1 で修正されていますが,実際には内部で ImmAssociateContext 関数を実行しているだけです.したがって,Delphi XE2 UP1 以降でも,そのまま使用可能です.
一般の入力コントロールの場合も,本ページのこれまでのサンプルのように入力コントロールにフォーカスが移動したら設定します.オブジェクトインスペクタの設定や,フォーム生成時の設定は,コントロールにフォーカス移動しても設定内容が反映されない場合があります.
また,imDisable が正常に機能しない環境で,オブジェクトインスペクタやフォームの OnCreate 等で imDisable を設定しまっては,ImmAssociateContext 関数を使用する意味がありません.その場合,当然ですが,下のサンプルコードは正常に機能しません.
[備考]
ImmAssociateContext 関数を使用して日本語 IME を無効にする方法は,全ての入力コントロールで正常に機能するわけではないようです.前項の Win32NLSEnableIME 関数で無効化した方が正常に機能する場合もあります.これは,コントロールの内部仕様によるものと思われます.
事実,Delphi XE2 UP1 より前の Delphi では,日本語 IME の無効化に,Win32NLSEnableIME 関数が使用されています.
そのため,Delphi XE2 UP1 より前の Delphi では,TStringGrid 等のインプレイスエディタの日本語 IME の無効化は正常に機能し,逆に,TEdit 等の日本語 IME の無効化が正常に機能しない現象が発生するものと思われます.
図18
設計時画面
図19
実行時画面
日本語 IME のモードの切り替えが正常に行われる
リスト7
TEdit 等の入力コントロールの日本語 IME の操作コード
Delphi XE2 UP1 よりも前の Delphi の場合
copy code
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class (TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
procedure Edit1Enter(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end ;
var
Form1: TForm1;
implementation
uses imm;
{$R *.dfm}
// =============================================================================
// Edit1,Edit2,Edit3共有のOnEnterイベント
// 日本語IMEのモードを切り替える
//
// オブジェクトインスペクタやForm1のOnCreate等でImeModeをimDisableにしないこと
// =============================================================================
procedure TForm1.Edit1Enter(Sender: TObject);
begin
if Sender = Edit1 then begin
ImmAssociateContext(TEdit(Sender).Handle, 0 );
end else
if Sender = Edit2 then begin
SetImeMode(TEdit(Sender).Handle, imHira);
end else
if Sender = Edit3 then begin
ImmAssociateContext(TEdit(Sender).Handle, 0 );
end ;
end ;
end .
09_ インプレイスエディタのインスタンスをコントロール配列から取得
インプレイスエディタのインスタンスは,次のように,コントロールの配列からも取得できます.
インプレイスエディタが起動すると,コントロールが増えます.その中で検索します.
var
i : Integer;
InpEdit : TInplaceEdit;
begin
for i := 0 to StringGrid1.ControlCount -1 do begin
if (StringGrid1.Controls[i] is TInPlaceEdit) then begin
InpEdit := StringGrid1.Controls[i] as TInPlaceEdit;
break;
end ;
end ;
TStringGrid の場合,コントロール配列の要素数は,通常は 0 です.インプレイスエディタが起動すると要素数は 1 になります.したがって,次のように,1 番目の要素がインプレイスエディタ・コントロールということになります.
var
InpEdit : TInplaceEdit;
begin
if StringGrid1.ControlCount > 0 then
InpEdit := TInplaceEdit(StringGrid1.Controls[0 ]);