☆カーソル下のテキストを選択する。
実行させるとこんな感じです。
ここで問題になるのが、TEdit、TMemoは「ランタイムテーマの影響を受けてしまう」ことです。 TRichEditは、ランタイムテーマの影響を受けず、常にバイト数で扱いますが、TEdit、TMemoは ランタイムテーマが有効時-文字数、無効時-バイト数となります。 今回、ランタイムテーマが有効、無効にかかわらず、バイト数で扱う処理を考えてみます。
uses GetWordAndPhrase, AdjustedEdit; procedure TForm1.Edit1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var CursolPos, sp, ep: Integer; S: String; begin Exit; CursolPos := LoWord(Edit1.Perform(EM_CHARFROMPOS, 0, MakeLParam(X, Y))); CursolPos := GetSelStart_Byte(Edit1.Text, CursolPos); S := GetWordAndPhraseUnderMouse(CursolPos, Edit1.Text, sp, ep); if S <> ''then begin if GetSelStart(Edit1) <> sp then begin SetSelStart(Edit1, sp); SetSelLength(Edit1, ep-sp+1); end; end; if ActiveControl <> Edit1 then ActiveControl := Edit1; end; procedure TForm1.Memo1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var CursolPos, sp, ep: Integer; S: String; begin CursolPos := LoWord(Memo1.Perform(EM_CHARFROMPOS, 0, MakeLParam(X, Y))); CursolPos := GetSelStart_Byte(Memo1.Text, CursolPos); S := GetWordAndPhraseUnderMouse(CursolPos, Memo1.Text, sp, ep); if S <> ''then begin if GetSelStart(Memo1) <> sp then begin SetSelStart(Memo1, sp); SetSelLength(Memo1, ep-sp+1); end; end; if ActiveControl <> Memo1 then ActiveControl := Memo1; end; procedure TForm1.RichEdit1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var CursolPos, sp, ep: Integer; S: String; Pt:TPoint; begin Pt := Point(X,Y); CursolPos := RichEdit1.Perform(EM_CHARFROMPOS, 0, Integer(@Pt)); S := GetWordAndPhraseUnderMouse(CursolPos, RichEdit1.Text, sp, ep); if S <> ''then begin if RichEdit1.SelStart <> sp then begin RichEdit1.SelStart := sp; RichEdit1.SelLength := ep-sp+1; end; end; if ActiveControl <> RichEdit1 then ActiveControl := RichEdit1; end;
ランタイムテーマの設定にかかわらず、バイト単位で扱うための処理を集めた名前空間 AdjustedEdit (名前が変なのは無視して~)
unit AdjustedEdit; { ランタイムテーマの設定にかかわらず、バイト単位で扱います。 } interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, StdCtrls, Buttons, ExtCtrls, Themes; // SelTextを取得します。 function GetSelText(CustomEdit: TCustomEdit): String; // SelStartをバイト数で設定します。 procedure SetSelStart(Edit: TCustomEdit; Position_Byte: Integer); // SelStartをバイト数で取得します。 function GetSelStart(Edit: TCustomEdit): Integer; // SelLengthをバイト数で設定します。 procedure SetSelLength(Edit: TCustomEdit; Length_Byte: Integer); // SelLengthをバイト数で取得します。 function GetSelLength(Edit: TCustomEdit): Integer; // 文字数で指定された位置のバイト数を返します。 function GetSelStart_Byte(S: WideString; Position_Moji: Integer): Integer; implementation // 指定位置のバイト数分の文字数を返します。 function GetMoji(S: String; Position: Integer): Integer; var P: PChar; I: Integer; Check: String; begin if not ThemeServices.ThemesEnabled then begin Result := Position; Exit; end; Check := Copy(S, 1, Position); P := PChar(Check+#0); I := 0; while (P^ <> #0) do begin if IsDBCSLeadByte(Byte(P^)) then Inc(P,2) else Inc(P); Inc(I); end; Result := I; end; // SelTextを取得します。 function GetSelText(CustomEdit: TCustomEdit): String; var S, Str: WideString; I, Start, Len: Integer; begin if not ThemeServices.ThemesEnabled then begin Result := CustomEdit.SelText; Exit; end; S := WideString(CustomEdit.Text); Start := CustomEdit.SelStart + 1; Len := Start + CustomEdit.SelLength -1; Str := ''; for I := Start to Len do Str := Str + S[I]; Result := Str; end; // SelStartをバイト数で設定します。 procedure SetSelStart(Edit: TCustomEdit; Position_Byte: Integer); begin Edit.SelStart := GetMoji(Edit.Text, Position_Byte); end; // SelStartをバイト数で取得します。 function GetSelStart(Edit: TCustomEdit): Integer; begin Result := GetSelStart_Byte(Edit.Text, Edit.SelStart); end; // SelLengthをバイト数で設定します。 procedure SetSelLength(Edit: TCustomEdit; Length_Byte: Integer); var I,J: Integer; begin I := GetSelStart(Edit); if I = 0 then I := 1; J := GetMoji(Edit.Text, I + Length_Byte); Edit.SelLength := J-GetMoji(Edit.Text,I); end; // SelLengthをバイト数で取得します。 function GetSelLength(Edit: TCustomEdit): Integer; begin Result := Length(GetSelText(Edit)); end; // 文字数で指定された位置のバイト数を返します。 function GetSelStart_Byte(S: WideString; Position_Moji: Integer): Integer; var Check: String; begin if not ThemeServices.ThemesEnabled then Result := Position_Moji else begin Check := Copy(S, 1, Position_Moji); Result := Length(Check); end; end; end.
上記、名前空間にSetSelTextという処理がないのは、次の処理がランタイムの設定に関係なく正常に動作するからです。
Edit1.Seltext := 'ややこしい!';SelTextを表示させたら、でたらめなのに、この処理が正常に動作する理由がわかりません。
こんなややこしい処理で悩むのなら、TMemoだけでなく、TEditもTRichEditを次の設定にして代用した方が簡単なのかも知れませんね。
RichEdit1.WantReturns := False; RichEdit1.WordWrap := False;
| 固定リンク