2007年06月04日

ファイルのパス名の一部を ... に置き換え短縮表示する  

   このエントリーをはてなブックマークに追加 mixiチェック Clip to Evernote
ファイルのパス名を表示する際に、表示幅にあわせ、パス名の途中を ... に置き換え短縮して表示するプログラムがあります。
これと同じような表示を Labelでやろうとしたら、Label って、オーナー描画のテクニックが使えないんですね。

Paintイベントハンドラを書いても、標準の描画処理が必ず走ってしまうようなので、うまくいきません。

表示幅を計算するには、Graphicsの値が必要ですが、これは、Paintイベントハンドラ内でしか有効ではないので、この値を保持しておいて、別のタイミングで文字列の調整をするわけにもいきません。

カスタムコントロールを作成するしかないみたいです。といっても、この程度のカスタムコントロールの作成ならば、それほど難しくはありません。
あまり経験のない僕でも、プロパティの属性部分以外は、それほど迷うことなく書けました。


public partial class PathLabel : System.Windows.Forms.Label {
public CustomLabel() {
InitializeComponent();
}

[DefaultValue(false)]
[Browsable(false)]
public override bool AutoSize {
get { return false; }
}

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e) {
RectangleF rect = new RectangleF(ClientRectangle.X,
ClientRectangle.Y,
ClientRectangle.Width,
ClientRectangle.Height);
e.Graphics.DrawString(
AdjustPathString(e.Graphics, this.Text),
Font, new SolidBrush(ForeColor), rect
);
}

private string AdjustPathString(Graphics grx, string text) {
SizeF size = grx.MeasureString(text, this.Font);
while ( this.Size.Width < size.Width ) {
string text2 = ShortenPathString(text);
if ( text == text2 )
break;
size = grx.MeasureString(text2, this.Font);
text = text2;
}

return text;
}

private string ShortenPathString(string text) {
List<string> list = new List<string>(text.Split('\\'));
int i = list.Count / 2;
if ( list[i] != "..." ) {
list[i] = "...";
} else {
if ( list.Count % 2 == 0 && i > 1 )
list.RemoveAt(i - 1);
else if ( list.Count % 2 == 1 && i < list.Count - 2 )
list.RemoveAt(i + 1);
}

StringBuilder sb = new StringBuilder(list[0]);
for ( int n = 1; n < list.Count; n++ ) {
sb.Append('\\').Append(list[n]);
}
return sb.ToString();
> }
}

Textプロパティにパス名を設定すれば、その幅に合わせて短縮表示してくれます。

... にする部分(ShortenPathString)は、パスのどの部分を ... にするのかという問題がありますが、ここは自己流です。アルゴリズムももっと良い方法があるかもしれませんが、
いちおう動いているので、これで良しとしておきます。

ところで、こういった GUIに関するユニットテストってどうやるんだろう?
良いやり方を思いつきません。


 

この記事へのトラックバックURL

http://trackback.blogsys.jp/livedoor/gushwell/50815731