diff --git a/HFUTCourseSimulation/HFUTCourseSimulation.csproj b/HFUTCourseSimulation/HFUTCourseSimulation.csproj index bf92600..cc4635b 100644 --- a/HFUTCourseSimulation/HFUTCourseSimulation.csproj +++ b/HFUTCourseSimulation/HFUTCourseSimulation.csproj @@ -38,6 +38,7 @@ + @@ -57,9 +58,11 @@ + Simulation.xaml + MSBuild:Compile diff --git a/HFUTCourseSimulation/ImageExport.cs b/HFUTCourseSimulation/ImageExport.cs new file mode 100644 index 0000000..e59ae37 --- /dev/null +++ b/HFUTCourseSimulation/ImageExport.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Imaging; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace HFUTCourseSimulation { + + public static class ImageExport { + + public static readonly int WeekHeaderHeight = 50; + public static readonly int BodyCellWidth = 150; + public static readonly int BodyCellHeight = 80; + public static readonly int HeaderCellHeight = 40; + public static readonly int LeftCellWidth = 25; + public static readonly int Blank = 20; + + static Dictionary weekDict = new Dictionary() { + {0, "星期一"}, + {1, "星期二"}, + {2, "星期三"}, + {3, "星期四"}, + {4, "星期五"}, + {5, "星期六"}, + {6, "星期日"} + }; + + public static bool Export(DateTime startDate, int weekCount, string file) { + + var simuCore = new SimulationCore(startDate, weekCount); + simuCore.Generate(); + if (simuCore.ErrorList.Count != 0) return false; + + //define size + int weekPerLine = (int)Math.Sqrt(weekCount) + 1; + + var weekWidth = (Blank + LeftCellWidth + 7 * BodyCellWidth); + var weekHeight = (Blank + WeekHeaderHeight + HeaderCellHeight + 11 * BodyCellHeight); + var img = new Bitmap(Blank + weekPerLine * weekWidth, Blank + (weekCount / weekPerLine + (weekCount % weekPerLine == 0 ? 0 : 1)) * weekHeight); + var graphics = Graphics.FromImage(img); + + //declare graphics value + var headerBrush = new SolidBrush(Color.Gray); + var textBrush = new SolidBrush(Color.Black); + Brush cellBrush; + var textFont = new Font("Arial", 12); + + var textMargin = graphics.MeasureString("测试字符", textFont).Height; + + //output each week + for (int i = 0; i < weekCount; i++) { + //generate week data + var weekData = simuCore.Render(i + 1); + + //get start position + var top = Blank + (i / weekPerLine) * weekHeight; + var left = Blank + (i % weekPerLine) * weekWidth; + graphics.TranslateTransform(left, top); + + //draw week head + graphics.DrawString($"教学周:{weekData.WeekIndex}", textFont, textBrush, 0, 0); + //move transform + graphics.TranslateTransform(0, WeekHeaderHeight); + + + //draw header + graphics.FillRectangle(headerBrush, 0, 0, weekWidth, HeaderCellHeight); + graphics.FillRectangle(headerBrush, 0, 0, LeftCellWidth, weekHeight - WeekHeaderHeight); + //draw header text + for (int j = 0; j < 7; j++) { + graphics.DrawString(weekDict[j], textFont, textBrush, LeftCellWidth + j * BodyCellWidth, 0); + graphics.DrawString(weekData.WeekDate[j], textFont, textBrush, LeftCellWidth + j * BodyCellWidth, textMargin); + } + //draw left text + for (int j = 0; j < 11; j++) { + graphics.DrawString((j + 1).ToString(), textFont, textBrush, 0, HeaderCellHeight + j * BodyCellHeight); + } + + //move transform + graphics.TranslateTransform(LeftCellWidth, HeaderCellHeight); + foreach(var courses in weekData.CourseList) { + var cellx = courses.Start.week - 1; + var celly = courses.Start.index - 1; + //background + cellBrush = new SolidBrush(courses.BkColor.ConvertWPFColor()); + graphics.FillRectangle(cellBrush, cellx * BodyCellWidth, celly * BodyCellHeight, BodyCellWidth, BodyCellHeight * courses.Span); + + //draw text + var rect = new RectangleF(cellx * BodyCellWidth, celly * BodyCellHeight, BodyCellWidth, celly * BodyCellHeight); + graphics.DrawString(courses.Name, textFont, textBrush, rect); + var thisTextMargin = graphics.MeasureString(courses.Name, textFont, BodyCellWidth).Height; + graphics.DrawString(courses.Desc, textFont, textBrush, cellx * BodyCellWidth, celly * BodyCellHeight + textMargin); + } + + //reset + graphics.TranslateTransform(-LeftCellWidth, -HeaderCellHeight); + graphics.TranslateTransform(0, -WeekHeaderHeight); + graphics.TranslateTransform(-left, -top); + } + + System.IO.File.Delete(file); + img.Save(file, ImageFormat.Png); + img.Dispose(); + return true; + } + + } + + public static class WPFColorConvert { + public static System.Drawing.Color ConvertWPFColor(this System.Windows.Media.Color c) { + return System.Drawing.Color.FromArgb(c.A, c.R, c.G, c.B); + } + } + +} diff --git a/HFUTCourseSimulation/MainWindow.xaml b/HFUTCourseSimulation/MainWindow.xaml index bbc0100..16d6237 100644 --- a/HFUTCourseSimulation/MainWindow.xaml +++ b/HFUTCourseSimulation/MainWindow.xaml @@ -15,11 +15,16 @@ - + + + + - + + + diff --git a/HFUTCourseSimulation/MainWindow.xaml.cs b/HFUTCourseSimulation/MainWindow.xaml.cs index 3bf1df5..5131ab4 100644 --- a/HFUTCourseSimulation/MainWindow.xaml.cs +++ b/HFUTCourseSimulation/MainWindow.xaml.cs @@ -35,7 +35,10 @@ namespace HFUTCourseSimulation { uiMenuSave.IsEnabled = false; uiMenuClose.IsEnabled = false; uiMenuSimulation.IsEnabled = false; + uiMenuExport.IsEnabled = false; + uiMainTab.Visibility = Visibility.Collapsed; + /* uiCourseBtnAdd.IsEnabled = false; uiCourseBtnDelete.IsEnabled = false; uiCourseBtnUpdate.IsEnabled = false; @@ -56,6 +59,7 @@ namespace HFUTCourseSimulation { uiCoursesList.IsEnabled = false; uiScheduleList.IsEnabled = false; + */ } else { //no file uiMenuNew.IsEnabled = false; @@ -63,7 +67,10 @@ namespace HFUTCourseSimulation { uiMenuSave.IsEnabled = true; uiMenuClose.IsEnabled = true; uiMenuSimulation.IsEnabled = true; + uiMenuExport.IsEnabled = true; + uiMainTab.Visibility = Visibility.Visible; + /* uiCourseBtnAdd.IsEnabled = true; uiCourseBtnDelete.IsEnabled = true; uiCourseBtnUpdate.IsEnabled = true; @@ -84,9 +91,10 @@ namespace HFUTCourseSimulation { uiCoursesList.IsEnabled = true; uiScheduleList.IsEnabled = true; + */ } } - + #region menu private void uiMenuNew_Click(object sender, RoutedEventArgs e) { @@ -149,6 +157,32 @@ namespace HFUTCourseSimulation { win.ShowDialog(); } + private void uiMenuExport_Click(object sender, RoutedEventArgs e) { + //convert data + int weekCount; + DateTime originDate; + try { + originDate = DateTime.Parse(General.GeneralSheet.StartDate); + weekCount = General.GeneralSheet.WeekCount; + } catch (Exception) { + MessageBox.Show("周数或日期转换错误,无法输出", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK); + return; + } + + //open file + var sp = new Microsoft.Win32.SaveFileDialog(); + sp.RestoreDirectory = true; + sp.Filter = "图片文件(*.png)|*.png|所有文件(*.*)|*.*"; + var status = sp.ShowDialog(); + if (!(status.HasValue && status.Value)) return; + var getFile = sp.FileName; + + //export + var res = ImageExport.Export(originDate, weekCount, getFile); + if (!res) MessageBox.Show("当前课程安排存在冲突,请通过实时预览消除所有错误后才能使用此功能来导出为图片", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK); + else MessageBox.Show("导出成功", "关于", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); + } + private void uiMenuAbout_Click(object sender, RoutedEventArgs e) { MessageBox.Show("本程序为开源程序。" + Environment.NewLine + "开源地址:https://gitee.com/yyc12345/HFUTCourseSimulation" + Environment.NewLine + "本程序旨在为各位选课的同学提供一个用于查验课程冲突以及查看课表的功能。如果您想参与开发,提交PullRequest即可,欢迎您的加入。", "关于", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); @@ -172,7 +206,7 @@ namespace HFUTCourseSimulation { MessageBox.Show("课程名不得为空", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK); return; } - + General.GeneralSheet.Courses.Add(General.CourseCache.Clone()); SyncCourseListData(); } @@ -288,7 +322,7 @@ namespace HFUTCourseSimulation { SyncScheduleListData(); } - + private void uiScheduleList_MouseDoubleClick(object sender, MouseButtonEventArgs e) { if (this.uiScheduleList.SelectedIndex < 0) { MessageBox.Show("未选择任何项", "错误", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK); diff --git a/HFUTCourseSimulation/Simulation.xaml.cs b/HFUTCourseSimulation/Simulation.xaml.cs index 103647d..1dfa4da 100644 --- a/HFUTCourseSimulation/Simulation.xaml.cs +++ b/HFUTCourseSimulation/Simulation.xaml.cs @@ -17,6 +17,9 @@ namespace HFUTCourseSimulation { /// Simulation.xaml 的交互逻辑 /// public partial class Simulation : Window { + + SimulationCore simulationKernel; + public Simulation() { InitializeComponent(); @@ -32,7 +35,7 @@ namespace HFUTCourseSimulation { colums.Width = new GridLength(1, GridUnitType.Star); this.uiArrangeGrid.ColumnDefinitions.Add(colums); } - + try { originDate = DateTime.Parse(General.GeneralSheet.StartDate); weekCount = General.GeneralSheet.WeekCount; @@ -44,152 +47,55 @@ namespace HFUTCourseSimulation { return; } - Generate(); + simulationKernel = new SimulationCore(originDate, weekCount); + simulationKernel.Generate(); //refresh error list this.uiArrangeError.Items.Clear(); - foreach (var item in errorList) { + foreach (var item in simulationKernel.ErrorList) { this.uiArrangeError.Items.Add(item); } currentWeek = 1; - Render(); + this.RenderGrid(simulationKernel.Render(currentWeek)); } - Dictionary itemDict = new Dictionary(); - List errorList = new List(); - List uiList = new List(); - - DateTime originDate; - int weekCount; int currentWeek; + int weekCount; + DateTime originDate; - void Generate() { - foreach (var item in General.GeneralSheet.Courses) { - foreach (var inner in item.Schedule) { - var weekRes = GetArrange(inner.Week); - var dayRes = GetArrange(inner.Day); - var indexRes = GetArrange(inner.Index); + void RenderGrid(RenderWeek weekRes) { + //set date + uiWeek.Text = weekRes.WeekIndex.ToString(); + uiWeek1.Text = weekRes.WeekDate[0]; + uiWeek2.Text = weekRes.WeekDate[1]; + uiWeek3.Text = weekRes.WeekDate[2]; + uiWeek4.Text = weekRes.WeekDate[3]; + uiWeek5.Text = weekRes.WeekDate[4]; + uiWeek6.Text = weekRes.WeekDate[5]; + uiWeek7.Text = weekRes.WeekDate[6]; - foreach (var weekItem in weekRes) { - foreach (var dayItem in dayRes) { - foreach (var indexItem in indexRes) { - var vectorCache = new Vector3(weekItem, dayItem, indexItem); - if (this.itemDict.Keys.Contains(vectorCache)) { - errorList.Add($"课程冲突:无法将{item.Name}安排到 {weekItem}周,星期{dayItem},第{indexItem}节。因为此处已被{itemDict[vectorCache].Name}占据"); - } else { - itemDict.Add(vectorCache, new SimulationItem() { Name = item.Name, Desc = item.Description }); - } - } - } - } - - - } - } - } - List GetArrange(string str) { - var res = new List(); - try { - if (str.Contains('-')) { - var strSp = str.Split('-'); - int start = int.Parse(strSp[0]), end = int.Parse(strSp[1]); - for (int i = start; i <= end; i++) { - res.Add(i); - } - - } else if (str.Contains(',')) { - var strSp = str.Split(','); - foreach (var item in strSp) { - res.Add(int.Parse(item)); - } - } else { - res.Add(int.Parse(str)); - } - } catch (Exception) { - errorList.Add("解析错误:" + str); - } - - return res; - } - - void Render() { //remove all old grid this.uiArrangeGrid.Children.Clear(); - uiList.Clear(); - //update date - //comput start date - uiWeek.Text = currentWeek.ToString(); - var pointer = originDate; - pointer = pointer.AddDays(7 * (currentWeek - 1)); - uiWeek1.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek2.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek3.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek4.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek5.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek6.Text = $"{pointer.Month}/{pointer.Day}"; - pointer = pointer.AddDays(1); - uiWeek7.Text = $"{pointer.Month}/{pointer.Day}"; - - //create grid - var query = (from item in itemDict.Keys - where item.teachingweek == currentWeek - select item).ToList(); - - while (query.Count != 0) { - var core = query[0]; - var data = itemDict[core]; - - int length = 1; - //check below - if (core.index != 1 && query.Contains(core + new Vector3(0, 0, -1))) { - if (itemDict[core + new Vector3(0, 0, -1)].Name == data.Name) { - //if below have. jump this->move this to the end - query.RemoveAt(0); - query.Add(core); - continue; - } - } - - //check follow - while (true) { - if (query.Contains(core + new Vector3(0, 0, length)) && itemDict[core + new Vector3(0, 0, length)].Name == data.Name) { - query.Remove(core + new Vector3(0, 0, length)); - length++; - } else break; - } - - //create + //generate new + foreach (var item in weekRes.CourseList) { var warp = new Border(); - warp.Background = new SolidColorBrush(Colors.LightBlue); + warp.Background = new SolidColorBrush(item.BkColor); warp.CornerRadius = new CornerRadius(5); - Grid.SetRowSpan(warp, length); + Grid.SetRowSpan(warp, item.Span); var nGrid = new Grid(); - nGrid.ToolTip = data.Desc; + nGrid.ToolTip = item.Desc; var courseName = new TextBlock(); courseName.VerticalAlignment = VerticalAlignment.Center; - courseName.Text = data.Name; + courseName.Text = item.Name; nGrid.Children.Add(courseName); warp.Child = nGrid; - Grid.SetRow(warp, core.index - 1); - Grid.SetColumn(warp, core.week - 1); + Grid.SetRow(warp, item.Start.index - 1); + Grid.SetColumn(warp, item.Start.week - 1); this.uiArrangeGrid.Children.Add(warp); - - //remove first item - query.RemoveAt(0); } - - foreach (var item in query) { - - } - } private void uiBtnPre_Click(object sender, RoutedEventArgs e) { @@ -199,7 +105,7 @@ namespace HFUTCourseSimulation { } currentWeek--; - Render(); + this.RenderGrid(simulationKernel.Render(currentWeek)); } private void uiBtnNext_Click(object sender, RoutedEventArgs e) { @@ -209,7 +115,7 @@ namespace HFUTCourseSimulation { } currentWeek++; - Render(); + this.RenderGrid(simulationKernel.Render(currentWeek)); } private void uiArrangeError_MouseDoubleClick(object sender, MouseButtonEventArgs e) { @@ -218,7 +124,7 @@ namespace HFUTCourseSimulation { return; } - MessageBox.Show(errorList[this.uiArrangeError.SelectedIndex], "错误详情", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); + MessageBox.Show(this.simulationKernel.ErrorList[this.uiArrangeError.SelectedIndex], "错误详情", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK); } } } diff --git a/HFUTCourseSimulation/SimulationCore.cs b/HFUTCourseSimulation/SimulationCore.cs new file mode 100644 index 0000000..ee80e36 --- /dev/null +++ b/HFUTCourseSimulation/SimulationCore.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; + +namespace HFUTCourseSimulation { + public class SimulationCore { + + public SimulationCore(DateTime startDate, int weekCount) { + this.weekCount = weekCount; + this.originDate = startDate; + } + + Dictionary itemDict = new Dictionary(); + public List ErrorList { get; } = new List(); + + //List uiList = new List(); + + DateTime originDate; + int weekCount; + //int currentWeek; + + public void Generate() { + //pre-generate + foreach (var item in General.GeneralSheet.Courses) { + foreach (var inner in item.Schedule) { + var weekRes = GetArrange(inner.Week); + var dayRes = GetArrange(inner.Day); + var indexRes = GetArrange(inner.Index); + + foreach (var weekItem in weekRes) { + foreach (var dayItem in dayRes) { + foreach (var indexItem in indexRes) { + var vectorCache = new Vector3(weekItem, dayItem, indexItem); + if (this.itemDict.Keys.Contains(vectorCache)) { + ErrorList.Add($"课程冲突:无法将{item.Name}安排到 {weekItem}周,星期{dayItem},第{indexItem}节。因为此处已被{itemDict[vectorCache].Name}占据"); + } else { + itemDict.Add(vectorCache, new SimulationItem() { Name = item.Name, Desc = item.Description, BkColor = Colors.LightBlue }); + } + } + } + } + + + } + } + } + + List GetArrange(string str) { + var res = new List(); + try { + if (str.Contains('-')) { + var strSp = str.Split('-'); + int start = int.Parse(strSp[0]), end = int.Parse(strSp[1]); + for (int i = start; i <= end; i++) { + res.Add(i); + } + + } else if (str.Contains(',')) { + var strSp = str.Split(','); + foreach (var item in strSp) { + res.Add(int.Parse(item)); + } + } else { + res.Add(int.Parse(str)); + } + } catch (Exception) { + ErrorList.Add("解析错误:" + str); + } + + return res; + } + + public RenderWeek Render(int currentWeek) { + //remove all old grid + var result = new RenderWeek(); + result.WeekDate = new List(); + + //update date + //comput start date + result.WeekIndex = currentWeek; + var pointer = originDate; + pointer = pointer.AddDays(7 * (currentWeek - 1)); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + pointer = pointer.AddDays(1); + result.WeekDate.Add($"{pointer.Month}/{pointer.Day}"); + + result.CourseList = new List(); + //create grid + var query = (from item in itemDict.Keys + where item.teachingweek == currentWeek + select item).ToList(); + + while (query.Count != 0) { + var core = query[0]; + var data = itemDict[core]; + + int length = 1; + //check below + if (core.index != 1 && query.Contains(core + new Vector3(0, 0, -1))) { + if (itemDict[core + new Vector3(0, 0, -1)].Name == data.Name) { + //if below have. jump this->move this to the end + query.RemoveAt(0); + query.Add(core); + continue; + } + } + + //check follow + while (true) { + if (query.Contains(core + new Vector3(0, 0, length)) && itemDict[core + new Vector3(0, 0, length)].Name == data.Name) { + query.Remove(core + new Vector3(0, 0, length)); + length++; + } else break; + } + + //create + result.CourseList.Add(new SimulationRenderItem() { Name = data.Name, Desc = data.Desc, BkColor = data.BkColor, Start = core, Span = length }); + /* + var warp = new Border(); + warp.Background = new SolidColorBrush(Colors.LightBlue); + warp.CornerRadius = new CornerRadius(5); + Grid.SetRowSpan(warp, length); + var nGrid = new Grid(); + nGrid.ToolTip = data.Desc; + var courseName = new TextBlock(); + courseName.VerticalAlignment = VerticalAlignment.Center; + courseName.Text = data.Name; + nGrid.Children.Add(courseName); + warp.Child = nGrid; + + Grid.SetRow(warp, core.index - 1); + Grid.SetColumn(warp, core.week - 1); + + this.uiArrangeGrid.Children.Add(warp); + */ + + //remove first item + query.RemoveAt(0); + } + + return result; + } + + + } + + + +} diff --git a/HFUTCourseSimulation/SimulationItem.cs b/HFUTCourseSimulation/SimulationItem.cs index e32e73c..e581aa7 100644 --- a/HFUTCourseSimulation/SimulationItem.cs +++ b/HFUTCourseSimulation/SimulationItem.cs @@ -3,11 +3,14 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows.Media; namespace HFUTCourseSimulation { + public class SimulationItem { public string Name { get; set; } public string Desc { get; set; } + public Color BkColor { get; set; } } public struct Vector3 { @@ -37,4 +40,17 @@ namespace HFUTCourseSimulation { return (Vector3)obj == this; } } + + //=========================================================================== + + public class RenderWeek { + public int WeekIndex { get; set; } + public List WeekDate { get; set; } + public List CourseList { get; set; } + } + + public class SimulationRenderItem : SimulationItem { + public Vector3 Start { get; set; } + public int Span { get; set; } + } }