WPF应用程序之最小生成树
这其实就是一个课程设计,我选的第三个,用C#做过一个,刚学了WPF,用WPF做个简单的,有向图的最小生成树我不知道怎么用画图表示,就先不做了。
界面:鼠标在有色区域取点,取点后可以移动点,取点和移动点时点会自动靠近大整数坐标,也就是你可以调整所有点到一个规则的五边形。
取完点后用鼠标滚轮取权值,权值越大,连线颜色越深,权值为0时透明度为0.05
也可以点击连线在输入框里面输入
滚轮输入:
输入框输入
权值是通过鼠标浮在连线上滚轮取值的,结果:
点和直线用的是Shapes里面的Ellipse和Line
程序过于简单,看WPF时看了数据绑定,自定义空间风格,依赖属性,但是这个里面都没有用到。
实现就很简单了:
取点一次加一个Ellipse,n-1个Line
输入权值,我没仔细做权值对应透明度的部分,所以权值超过9就没分别了,粗糙。
最小生成树的算法也很拙劣,没优化。
数学系的想做程序,自学至此,努力的空间很大。
代码:
XAML代码:
1: <Window x:Class="WpfAppMathmeticalModelEx3.MainWindow"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: Title="数学模型课程设计 无向图的最小生成树" Height="580" Width="800" WindowStartupLocation="CenterScreen" Loaded="Window_Loaded">
5:
6: <Grid Name="gridBord">
7: <Grid.RowDefinitions>
8: <RowDefinition Height="20"></RowDefinition>
9: <RowDefinition Height="300"></RowDefinition>
10: <RowDefinition Height="100"></RowDefinition>
11: <RowDefinition Height="100"></RowDefinition>
12: <RowDefinition></RowDefinition>
13: </Grid.RowDefinitions>
14: <Grid.ColumnDefinitions>
15: <ColumnDefinition Width="20"></ColumnDefinition>
16: <ColumnDefinition Width="500"></ColumnDefinition>
17: <ColumnDefinition></ColumnDefinition>
18: </Grid.ColumnDefinitions>
19: <Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="3">
20: <Canvas Name="canvasBord" Width="500" Height="500">
21: <Rectangle Name="rectangleBord" Width="500" Height="500" Fill="Beige"></Rectangle>
22: </Canvas>
23: </Border>
24: <Border Grid.Column="2" Grid.Row="1" BorderBrush="YellowGreen" BorderThickness="3" Margin="10">
25: <Canvas Name="canvasSummary" Grid.Column="2" Grid.Row="1" Margin="20">
26: <TextBlock Name="tBSummary" FontSize="12" Width="190" Height="235" TextWrapping="WrapWithOverflow"></TextBlock>
27: </Canvas>
28: </Border>
29: <Border Grid.Column="2" Grid.Row="2" Margin="10">
30: <Canvas Name="canvasModel" Margin="20">
31: <Button Name="btnModel" Width="190" Height="35" Click="btnModel_Click">计算最小生成树</Button>
32: </Canvas>
33: </Border>
34: <Border Grid.Column="2" Grid.Row="3" BorderBrush="YellowGreen" BorderThickness="3" Margin="10">
35: <Canvas Name="canvasResult" Margin="20">
36: <TextBlock Name="tBResult" Width="190" Height="35" TextWrapping="WrapWithOverflow"></TextBlock>
37: </Canvas>
38: </Border>
39: </Grid>
40: </Window>
CS代码:
1: using System;
2: using System.Collections.Generic;
3: using System.Windows;
4: using System.Windows.Controls;
5: using System.Windows.Input;
6: using System.Windows.Media;
7: using System.Text;
8: using System.Windows.Shapes;
9:
10: namespace WpfAppMathmeticalModelEx3
11: {
12: /// <summary>
13: /// MainWindow.xaml 的交互逻辑
14: /// </summary>
15: public partial class MainWindow : Window
16: {
17: public MainWindow()
18: {
19: InitializeComponent();
20: rectangleBord.MouseLeftButtonDown += rectangleBord_MouseLeftButtonDown;
21: rectangleBord.MouseLeftButtonUp += rectangleBord_MouseLeftButtonUp;
22: }
23:
24: private void Window_Loaded(object sender, RoutedEventArgs e)
25: {
26: listPoints = new List<Point>();
27: listEllipses = new List<Ellipse>();
28: tBInputW = new TextBox { Height = 20, Width = 80, Background = Brushes.YellowGreen };
29: canvasBord.Children.Add(tBInputW);
30: tBInputW.Visibility = Visibility.Hidden;
31: tBInputW.KeyUp += new KeyEventHandler(tBInputW_KeyUp);
32:
33: StringBuilder strBuilder = new StringBuilder();
34: strBuilder.AppendLine("操作步骤:\n");
35: strBuilder.AppendLine("1.用鼠标在左侧区域取点\n");
36: strBuilder.AppendLine("2.用鼠标调整点的位置\n");
37: strBuilder.AppendLine("3.把鼠标放在两个点之间的连线上滑动滚轮,即可调整这两个点之间的权值\n");
38: strBuilder.AppendLine("4.权值越大,连线颜色越深\n");
39: strBuilder.AppendLine("5.确定权值后点击 计算最小生成树 按钮\n");
40: tBSummary.Text = strBuilder.ToString();
41: }
42:
43: TextBox tBInputW;
44: List<Ellipse> listEllipses;
45: Point canvasBordStartPoint;
46:
47: void rectangleBord_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
48: {
49: canvasBordStartPoint = e.GetPosition(canvasBord);
50: }
51:
52: void rectangleBord_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
53: {
54: if (e.ClickCount > 1)
55: return;
56: if (canvasBordStartPoint.X != e.GetPosition(canvasBord).X || canvasBordStartPoint.Y != e.GetPosition(canvasBord).Y)
57: return;
58:
59: Point tmpPoint = e.GetPosition(canvasBord);
60: tmpPoint.X = ConvertToInt(autoMoveRadius, tmpPoint.X);
61: tmpPoint.Y = ConvertToInt(autoMoveRadius, tmpPoint.Y);
62: listPoints.Add(tmpPoint);
63: addNewPoint(tmpPoint);
64: addNewLine();
65: }
66:
67: bool isMouseDown;
68: Point startPoint;
69: Point currentPoint;
70: Point ellipseStartPoint;
71: //Point
72: const double radius = 10;
73: const int autoMoveRadius = 15;
74: readonly Brush pointBrush = Brushes.BlueViolet;
75: List<Point> listPoints;
76: //Line
77: const double lineWidth = 10;
78:
79: void ellipse_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
80: {
81: isMouseDown = true;
82: startPoint = e.GetPosition(canvasBord);
83: ellipseStartPoint = new Point(Canvas.GetLeft((Ellipse)sender), Canvas.GetTop((Ellipse)sender));
84: }
85:
86: void ellipse_MouseMove(object sender, MouseEventArgs e)
87: {
88: if (isMouseDown && e.LeftButton == MouseButtonState.Pressed)
89: {
90: currentPoint = e.GetPosition(canvasBord);
91: Ellipse ellipse = (Ellipse)sender;
92: Canvas.SetLeft(ellipse, ellipseStartPoint.X + currentPoint.X - startPoint.X);
93: Canvas.SetTop(ellipse, ellipseStartPoint.Y + currentPoint.Y - startPoint.Y);
94: listPoints[int.Parse(ellipse.Name.Substring(5))] = new Point(Canvas.GetLeft(ellipse) + radius, Canvas.GetTop(ellipse) + radius);
95: AutoMoveLine(sender);
96: }
97: }
98:
99: void ellipse_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
100: {
101: isMouseDown = false;
102: Ellipse ellipse = (Ellipse)sender;
103: Point tmpPoint = listPoints[int.Parse(ellipse.Name.Substring(5))];
104: tmpPoint.X = ConvertToInt(autoMoveRadius, tmpPoint.X);
105: tmpPoint.Y = ConvertToInt(autoMoveRadius, tmpPoint.Y);
106: Canvas.SetLeft(ellipse, tmpPoint.X - radius);
107: Canvas.SetTop(ellipse, tmpPoint.Y - radius);
108: listPoints[int.Parse(ellipse.Name.Substring(5))] = tmpPoint;
109: AutoMoveLine(sender);
110: }
111:
112: void addNewPoint(Point newPoint)
113: {
114: Ellipse ellipse = new Ellipse();
115: ellipse.Name = "point" + (listPoints.Count - 1);
116: ellipse.Width = 2 * radius; ellipse.Height = 2 * radius;
117: ellipse.Stroke = pointBrush;
118: ellipse.Fill = pointBrush;
119: ellipse.ToolTip = "Point " + (listPoints.Count - 1);
120: Canvas.SetLeft(ellipse, newPoint.X - radius);
121: Canvas.SetTop(ellipse, newPoint.Y - radius);
122: Canvas.SetZIndex(ellipse, 99);
123: canvasBord.Children.Add(ellipse);
124: listEllipses.Add(ellipse);
125: ellipse.MouseLeftButtonDown += ellipse_MouseLeftButtonDown;
126: ellipse.MouseMove += ellipse_MouseMove;
127: ellipse.MouseLeftButtonUp += ellipse_MouseLeftButtonUp;
128: }
129:
130: void addNewLine()
131: {
132: for (int i = 0; i < listPoints.Count - 1; i++)
133: {
134: Line line = new Line { Stroke = pointBrush, Opacity = 0.05, StrokeThickness = lineWidth,
135: X1 = listPoints[i].X, Y1 = listPoints[i].Y,
136: X2 = listPoints[listPoints.Count - 1].X, Y2 = listPoints[listPoints.Count - 1].Y,
137: Name = String.Format("i{0}j{1}", i, (listPoints.Count - 1)),
138: ToolTip = "0" };
139: line.MouseWheel += line_MouseWheel;
140: line.MouseLeftButtonDown += line_MouseLeftButtonDown;
141: canvasBord.Children.Add(line);
142: }
143: }
144:
145: void line_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
146: {
147: Canvas.SetLeft(tBInputW, e.GetPosition(canvasBord).X);
148: Canvas.SetTop(tBInputW, e.GetPosition(canvasBord).Y);
149: tBInputW.Visibility = Visibility.Visible;
150: Line line = (Line)sender;
151: tBInputW.Text = line.ToolTip.ToString();
152: tBInputW.Tag = sender;
153: }
154:
155: void tBInputW_KeyUp(object sender, KeyEventArgs e)
156: {
157: if (e.Key==Key.Enter)
158: {
159: int w;
160: if (int.TryParse(tBInputW.Text,out w))
161: {
162: Line line = (Line)tBInputW.Tag;
163: line.ToolTip = w;
164: line.Opacity = 0.05 + 0.1 * w;
165: tBInputW.Visibility = Visibility.Hidden;
166: }
167: else { MessageBox.Show("Input error", "Error", MessageBoxButton.OK, MessageBoxImage.Error); }
168: }
169: }
170:
171: void line_MouseWheel(object sender, MouseWheelEventArgs e)
172: {
173: Line line = (Line)sender;
174: int currentW = int.Parse(line.ToolTip.ToString());
175: if (e.Delta > 0)
176: {
177: currentW++;
178: if (line.Opacity == 0.95) { return; } else { line.Opacity += 0.1; }
179: }
180: else
181: {
182: if (currentW > 0) { currentW--; line.Opacity -= 0.1; }
183: }
184: if (currentW < 0) { line.Opacity = 0.05; }
185: line.ToolTip = currentW;
186: }
187:
188: private void btnModel_Click(object sender, RoutedEventArgs e)
189: {
190: int count=0;
191: foreach (UIElement tmp in canvasBord.Children)
192: {
193: if (tmp is Ellipse) { count++; }
194: }
195: int[,] matrix = new int[count, count];
196: int[,] minSpanningTree = new int[count, count];
197: for (int i = 0; i < count; i++) { matrix[i, i] = 0; }
198: Line line = null;
199: foreach (UIElement tmp in canvasBord.Children)
200: {
201: if (tmp is Line)
202: {
203: line = (Line)tmp;
204: int i, j;
205: i = int.Parse(line.Name.Substring(1, line.Name.IndexOf("j") - 1));
206: j = int.Parse(line.Name.Substring(line.Name.IndexOf("j") + 1));
207: if (line.ToolTip.ToString() == "0")
208: { matrix[i, j] = -1; matrix[j, i] = -1; }
209: else
210: { matrix[i, j] = int.Parse(line.ToolTip.ToString()); matrix[j, i] = matrix[i, j]; }
211: }
212: }
213: minSpanningTree = PrimMinSpanningTree(matrix);
214: int minSpanningTreeW = 0;
215: for (int i = 0; i < count; i++)
216: {
217: for (int j = i; j < count; j++)
218: {
219: if (minSpanningTree[i, j] != 0 && minSpanningTree[i, j] != -1)
220: {
221: line = FindLineInCanvasByName(canvasBord, String.Format("i{0}j{1}", i, j));
222: line.Opacity = 1;
223: line.Stroke = Brushes.Brown;
224: minSpanningTreeW += minSpanningTree[i, j];
225: }
226: }
227: }
228: tBResult.Text = "最小生成树的权值为:" + minSpanningTreeW;
229: }
230:
231: /// <summary>
232: /// Find Shape Line in a Canvas By Line Property Name
233: /// </summary>
234: /// <param name="canvas">Shapes container:canvas</param>
235: /// <param name="name">Line property:name</param>
236: /// <returns>Return a Line Object</returns>
237: static Line FindLineInCanvasByName(Canvas canvas, string name)
238: {
239: foreach (UIElement tmp in canvas.Children)
240: {
241: Line line = null;
242: if (tmp is Line)
243: {
244: line = (Line)tmp;
245: if (line.Name == name) { return line; }
246: }
247: }
248: return null;
249: }
250:
251: static Ellipse FindEllipseInCanvasByName(Canvas canvas, string name)
252: {
253: foreach (UIElement tmp in canvas.Children)
254: {
255: Ellipse ellipse = null;
256: if (tmp is Ellipse)
257: {
258: ellipse = (Ellipse)tmp;
259: if (ellipse.Name == name) { return ellipse; }
260: }
261: }
262: return null;
263: }
264:
265: static int ConvertToInt(int container, double i)
266: {
267: int k = (int)(i / container) * container;
268: if (k + 1 - i > i - k)
269: return k;
270: else
271: return k + 1;
272: }
273:
274: void AutoMoveLine(object sender)
275: {
276: Ellipse ellipse = (Ellipse)sender;
277: int k = int.Parse(ellipse.Name.Substring(5)); //Selected Ellipse index
278: for (int i = 0; i < listPoints.Count; i++)
279: {
280: //i k
281: if (k == i) { continue; }
282: int m = i; int n = k;
283: if (m > n)
284: { int tmp = m; m = n; n = tmp; }
285: string lineName = String.Format("i{0}j{1}", m, n);
286: Line line = FindLineInCanvasByName(canvasBord, lineName);
287: line.X1 = listPoints[m].X; line.Y1 = listPoints[m].Y;
288: line.X2 = listPoints[n].X; line.Y2 = listPoints[n].Y;
289: }
290: }
291:
292: static int[,] PrimMinSpanningTree(int[,] matrix)
293: {
294: int[,] MinSpanningTree = new int[matrix.GetLength(0), matrix.GetLength(0)];
295: int[] num = new int[matrix.GetLength(0)];
296: //Initialize MinSpanning Tree
297: //Initialize num to 0
298: for (int i = 0; i < MinSpanningTree.GetLength(0); i++)
299: {
300: num[i] = 0;
301: for (int j = 0; j < MinSpanningTree.GetLength(0); j++)
302: {
303: MinSpanningTree[i, j] = -1;
304: MinSpanningTree[i, j] = -1;
305: }
306: MinSpanningTree[i, i] = 0;
307: }
308: num[0] = 1;
309: bool check = false;
310: int a = -1, b = -1, k;
311: do
312: {
313: int minW = int.MaxValue;
314: for (k = 0; k < num.GetLength(0); k++)
315: {
316: if (num[k] == 1)//U
317: //Find the minimum number
318: for (int j = 0; j < matrix.GetLength(0); j++)
319: {
320: //if point j has included,jump to next
321: if (num[j] == 1 || j == k) { continue; }
322: if (matrix[k, j] != -1) { if (matrix[k, j] < minW) { minW = matrix[k, j]; a = k; b = j; } }
323: }
324: }
325: num[b] = 1;
326: MinSpanningTree[a, b] = matrix[a, b];
327: MinSpanningTree[b, a] = matrix[a, b];
328: //check if all points included
329: check = true;
330: for (int i = 0; i < num.Length; i++)
331: {
332: if (num[i] == 0) { check = false; break; }
333: }
334: } while (!check);
335: return MinSpanningTree;
336: }
337: }
338: }
我自己都觉得这篇文章没有多大价值,做的东西也才粗糙简单了,但是改进方向在哪里?
硬啃开源项目?还是先把计算机学科基础包括数据结构、计算机组成原理、操作系统、计算机网络基础扎实了?
时间不多了,争分夺秒吧。