文字列省略時の...の位置

解決


Manbon  2008-11-27 23:33:09  No: 32736

以下のコードを実行しますと、フォーム上に
「1234567...」
と表示されます。これを、
「...3456789」
というふうに、また、
「1234...789」
というふうに表示させたいのですが、何か方法はあるでしょうか?

var
  R: TRect;
begin
  R.Top := 0;
  R.Left := 0;
  R.Right := 50;
  R.Bottom := 20;
  DrawText(Canvas.Handle, PChar('123456789'), -1, R, DT_END_ELLIPSIS);
end;


とりあえず  2008-11-28 01:45:41  No: 32737

先頭の省略は簡単だけど、中の省略はチョット面倒。

function MinimizeString(const aStr: string; Canvas: TCanvas; MaxLen: Integer): string;
const
  MINIMIZESTR = '...';
var
  cLen: Integer;
  p: PChar;  
begin
  result := aStr;
  if (Canvas.TextWidth(aStr) < MaxLen) then exit;
  p := PChar(aStr);
  cLen := Canvas.TextWidth(MINIMIZESTR);
  while (Canvas.TextWidth(p) + cLen > MaxLen) do begin
   if IsDBCSLeadByte(Byte(p^)) then inc(p, 2) else inc(p);
  end;
  result := MINIMIZESTR + p;
end;


monaa  2008-11-28 02:00:55  No: 32738

「1234...789」は
Win32API: DrawTextの
dwFormat : DT_PATH_ELLIPSIS
がそれに相当します。
「...3456789」に相当するものはありません
by MSDN
http://msdn.microsoft.com/ja-jp/library/cc428474.aspx


おや?  2008-11-28 02:29:29  No: 32739

>「...3456789」に相当するものはありません
文字列に \ が含まれないか1個だけだと、DT_PATH_ELLIPSISは先頭を省略する仕様らしい...


やっぱり  2008-11-29 03:59:51  No: 32740

DT_PATH_ELLIPSISは、ファイルPATHでない普通の文字列の省略には
むかないね。

function MinimizeString(const aStr: string; Canvas: TCanvas; MaxWidth: Integer;
 isMiddle: Boolean=True; LeftLen: Integer=3): string;
const
  MINIMIZESTR = '...';
var
  i, cWidth, fWidth: Integer;
  pT, pL, pB: PChar;
  cc: Char;
  sLeft: string;
begin
  result := aStr;
  if (Canvas.TextWidth(aStr) < MaxWidth) then exit;
  pT := PChar(aStr);
  cWidth := Canvas.TextWidth(MINIMIZESTR);
  if not isMiddle then begin
   while (Canvas.TextWidth(pT) + cWidth > MaxWidth) do begin
    if IsDBCSLeadByte(Byte(pT^)) then inc(pT, 2) else inc(pT);
   end;
   result := MINIMIZESTR + pT;
  end else begin
   pL := pT + Length(aStr);
   pB := pT;
   for i:=1 to LeftLen do begin
    if IsDBCSLeadByte(Byte(pB^)) then inc(pB, 2) else inc(pB);
   end;
   cc := pB^;
   pB^ := #0;
   sLeft := pT;
   fWidth := Canvas.TextWidth(sLeft) + cWidth;
   pB^ := cc;
   while (Canvas.TextWidth(pB) > MaxWidth - fWidth) do begin
    if pB > pL then break;
    if IsDBCSLeadByte(Byte(pB^)) then inc(pB, 2) else inc(pB);
   end;
   result := sLeft + MINIMIZESTR + pB;
  end;
end;


う〜ん...やはり  2008-11-29 08:22:35  No: 32741

中を省略する場合は、'...'が文字列の中央あたりにあった方がイイね。

function MinimizeString(const aStr: string; Canvas: TCanvas; MaxWidth: Integer;
 isMiddle: Boolean=True): string;
const
  MINIMIZESTR = '...';
var
  i, cWidth, fWidth: Integer;
  pT, pL, pB: PChar;
  cc: Char;
  sLeft: string;
begin
  result := aStr;
  if (Canvas.TextWidth(aStr) < MaxWidth) then exit;
  pT := PChar(aStr);
  cWidth := Canvas.TextWidth(MINIMIZESTR);
  if not isMiddle then begin
   while (Canvas.TextWidth(pT) + cWidth > MaxWidth) do begin
    if IsDBCSLeadByte(Byte(pT^)) then inc(pT, 2) else inc(pT);
   end;
   result := MINIMIZESTR + pT;
  end else begin
   pL := pT + Length(aStr);
   pB := pT;
   repeat
    if IsDBCSLeadByte(Byte(pB^)) then inc(pB, 2) else inc(pB);
    cc := pB^;
    pB^ := #0;
    sLeft := pT;
    fWidth := Canvas.TextWidth(sLeft) + cWidth;
    pB^ := cc;
   until fWidth > (MaxWidth div 2);
   while (Canvas.TextWidth(pB) > MaxWidth - fWidth) do begin
    if pB > pL then break;
    if IsDBCSLeadByte(Byte(pB^)) then inc(pB, 2) else inc(pB);
   end;
   result := sLeft + MINIMIZESTR + pB;
  end;
end;


Manbon  2008-12-02 20:24:46  No: 32742

遅くなりました。ありがとうございます。
先頭の...はばっちりでした。
ですが、途中の省略では、「pB^ := #0;」の部分で
書込み違反が出てしまいます・・・。
問題ないように見えるのですが、わかりませんでした。
もうちょっと調べてみます。


そう...だったら  2008-12-02 22:20:18  No: 32743

ここを、
>   cc := pB^;
>   pB^ := #0;
>   sLeft := pT;
>   fWidth := Canvas.TextWidth(sLeft) + cWidth;
>   pB^ := cc;

こう変えてみたらどう?
    sLeft := Copy(aStr, 1, pB-pT);
    fWidth := Canvas.TextWidth(sLeft) + cWidth;


Manbon  2008-12-02 23:24:15  No: 32744

ありがとうございます!!できました。
Copy関数の中でのPCharの引き算など、
何故こういうことができるのか、まださっぱりですので、
ちょっと勉強しようと思います。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加