トーナメント表は、ツリー構造をしています。
なので、トーナメント表のデータは、XMLで記述することにします。
要素名はなんでもかまいません。
トーナメント表の性質として、ツリー構造をつぎのように制限します。
- リーフのテキストノードにチーム名や個人名を記述する。
- 中間ノードは、2つのノードをもつ。(二分岐)
描画するアルゴリズムは、2回、再帰的にノードをたどっています。
1回目は、SetLineAttributeメソッドで、リーフの深さと数をカウントし、帰りがけに中間ノードのy座標の位置を計算しています。
2回目は、DrawLineメソッドで、実際の線分を描画しています。
XMLファイルのサンプルです。
<?xml version="1.0" encoding="utf-8" ?>
<game>
<game>
<game>
<team>悟空</team>
<team>ベジータ</team>
</game>
<team>クリリン</team>
</game>
<game>
<team>フリーザ</team>
<team>ヤムチャ</team>
</game>
</game>
このファイルを開くとこうなります。
MainWindow.xaml
<Window x:Class="TournamentTable.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="350" Width="525">
<Window.CommandBindings>
<CommandBinding Command="Open" Executed="OpenCommandHandler"/>
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Command="Open" />
</Menu>
<Canvas Grid.Row="1" Name="canvas1" Margin="10">
<Canvas.Resources>
<Style TargetType="Line">
<Setter Property="Stroke" Value="Black"/>
</Style>
</Canvas.Resources>
</Canvas>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Win32;using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Xml;
namespace TournamentTable
{
public partial class MainWindow : Window
{
private int scale = 40;
private double textWidth = 60;
private int maxLevel;
private int leafCount;
public MainWindow()
{
InitializeComponent();
}
private void OpenCommandHandler(object sender, ExecutedRoutedEventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
if (ofd.ShowDialog() == true)
{
XmlDocument xdoc = new XmlDocument();
xdoc.Load(ofd.FileName);
this.maxLevel = 0;
this.leafCount = 0;
SetLineAttribute(xdoc.DocumentElement, 0);
this.canvas1.Children.Clear();
DrawLine(xdoc.DocumentElement);
}
}
private void DrawLine(XmlElement ele)
{
double level = double.Parse(ele.Attributes["level"].Value);
double y = double.Parse(ele.Attributes["y"].Value) * scale;
if (ele.ChildNodes.Count == 2)
{
XmlElement c1 = (XmlElement)ele.ChildNodes[0];
XmlElement c2 = (XmlElement)ele.ChildNodes[1];
DrawLine(c1);
DrawLine(c2);
Line cLine = new Line();
cLine.X1 = textWidth + (maxLevel - level) * scale;
cLine.Y1 = double.Parse(c1.Attributes["y"].Value) * scale;
cLine.X2 = textWidth + (maxLevel - level) * scale;
cLine.Y2 = double.Parse(c2.Attributes["y"].Value) * scale;
this.canvas1.Children.Add(cLine);
Line line = new Line();
line.X1 = textWidth + (maxLevel - level) * scale;
line.Y1 = y;
line.X2 = textWidth + (maxLevel - level + 1) * scale;
line.Y2 = y;
this.canvas1.Children.Add(line);
}
else
{
Line line = new Line();
line.X1 = textWidth + (maxLevel - level + 1) * scale;
line.Y1 = y;
line.X2 = textWidth;
line.Y2 = y;
this.canvas1.Children.Add(line);
Border border = new Border();
border.Height = scale;
border.Width = textWidth;
border.SetValue(Canvas.TopProperty, y - 0.5 * scale);
TextBlock tb = new TextBlock(new Run(ele.InnerText));
tb.VerticalAlignment = System.Windows.VerticalAlignment.Center;
border.Child = tb;
this.canvas1.Children.Add(border);
}
}
private void SetLineAttribute(XmlElement ele, int level)
{
maxLevel = System.Math.Max(maxLevel, level);
if (ele.ChildNodes.Count == 2)
{
XmlElement c1 = (XmlElement)ele.ChildNodes[0];
XmlElement c2 = (XmlElement)ele.ChildNodes[1];
SetLineAttribute(c1, level + 1);
SetLineAttribute(c2, level + 1);
double y = (double.Parse(c1.Attributes["y"].Value) + double.Parse(c2.Attributes["y"].Value)) / 2.0;
ele.SetAttribute("y", y.ToString());
}
else
{
leafCount++;
ele.SetAttribute("y", leafCount.ToString());
}
ele.SetAttribute("level", level.ToString());
}
}
}
0 件のコメント:
コメントを投稿