Adsense_top

2010年3月21日日曜日

C# TreeViewNodeの文字列複数行表示

TreeViewのノードで長いラベルを使うと下図のようにスクロールバーが表示されたり、幅が広くなるのが気になりましたので、ラベルの複数行表示するように考えてみました。


FormにTreeVeiwをtreeView1として配置しています。
何をしているかはコメントを参考にしてください。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
treeView1.Nodes.Clear();
// ラベル部分のみ手動で描画する
treeView1.DrawMode = TreeViewDrawMode.OwnerDrawText;
// ノードごとには高さが変えられないので、
// 今回は2行分の高さにしておく
treeView1.ItemHeight =26;
// 仮に今回はお気に入りを登録しています。
// リストに登録しているのは、単に子ノードを複数登録するので
// 同じ事を複数回書かずにループで回すためで、実際に使用する時は、
// メソッドを分けた方が良いと思います。
List<TreeNodeText> lst = new List<TreeNodeText>();
lst.Add(new TreeNodeText(
"Android Developer\r\n[ http://developer.android.com/ ]"));
lst.Add(new TreeNodeText(
"MSDN ホームページ\r\n[ http://msdn.microsoft.com/ ]"));
lst.Add(new TreeNodeText(
"MSDN Code Gallery\r\n[ http://code.msdn.microsoft.com/ ]"));
lst.Add(new TreeNodeText(
"Eclipse.org home\r\n[ http://www.eclipse.org/ ]"));
TreeNode rootNode = treeView1.Nodes.Add("お気に入り");
Graphics graphics = treeView1.CreateGraphics();
Font font = treeView1.Font;
foreach (TreeNodeText treeNodeText in lst)
{
TreeNode node = new TreeNode();
// ノードのタグにTreeNodeTextクラスのインスタンスを登録
node.Tag = treeNodeText;
// ラベルの領域幅は文字列の幅で決まるために、複数行中の
// 一番幅の広い文字列を仮のラベルとしておく
node.Text =
MaxWidthString(graphics, font, treeNodeText.TextList);
rootNode.Nodes.Add(node);
}
font.Dispose();
graphics.Dispose();
}
private void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
// タグに TreeNodeText のインスタンスが登録されている場合は、
// インスタンスに登録されている文字列を描画し、それ以外は
// ラベルに登録されている文字列を描画する
// 通常のノードの描画を e.DrawDefault を使ってシステムに任すと、
// 左上に描画されるために、オーナードローしている。
string text =
e.Node.Tag == null ? e.Node.Text :
((TreeNodeText)e.Node.Tag).DisplayText;
TextRenderer.DrawText(
e.Graphics, text, treeView1.Font, e.Bounds, Color.Black,
TextFormatFlags.VerticalCenter | TextFormatFlags.Left);
}
/// <summary>
/// 文字列のリストからTreeViewに描画した場合に、
/// 幅が最長の文字列を返します。
/// </summary>
/// <param name="graphics">TreeViewのGraphicsオブジェクト</param>
/// <param name="font">文字列の描画に使用するTreeViewのフォント</param>
/// <param name="list">文字列のリスト</param>
/// <returns>最長の文字列</returns>
private string MaxWidthString( Graphics graphics, Font font,
List<string> list)
{
int maxWidth = 0;
string maxString = string.Empty;
foreach (string text in list)
{
TextRenderer.DrawText(
graphics, text, font, new Point(0, 0), Color.Black);
Size stringSize =
TextRenderer.MeasureText(graphics, text, font);
if (maxWidth < stringSize.Width)
{
maxWidth = stringSize.Width;
maxString = text;
}
}
return maxString;
}
/// <summary>
/// TreeViewのタグに登録する情報をラップするクラス
/// </summary>
class TreeNodeText
{
private List<string> textList = new List<string>();

public TreeNodeText(string text)
{
string[] array =
text.Split(new string[]{"\r\n","\n"},
StringSplitOptions.RemoveEmptyEntries);
foreach(string s in array)
textList.Add(s);
}
// 表示する文字列を各行ごとのリストを返します。
public List<string> TextList
{
get { return textList; }
set { textList = value; }
}
// 表示する文字列を行ごとに改行を挟む形で返します。
public string DisplayText
{
get { return string.Join("\r\n", textList.ToArray()); }
}
}
}

以下のように表示されます。



各ノードの高さは、ラベル表示が出来る分をあらかじめ設定しています。
TreeViewのDrawModeをOwnerDrawAllにすれば細かな調整が出来そうですが、+/-ボタンや、ノード間の線の描画、およびインデントの幅等も計算もする必要が出てきそうなので、今回は多少の格好の悪さは我慢しこのようにしました。



0 件のコメント:

コメントを投稿