这是“使用 C# 开发智能手机软件:推箱子” 系列文章的第二十四篇。在这篇文章中,介绍 Window/MainForm.cs 源程序文件。这个源程序文件是 MainForm 类的主体部分,该类继承自 System.Windows.Forms.Form 类,表示推箱子的主窗体,如下图所示:

下面就是 MainForm.cs 的源程序代码:
1 using System;
2 using System.ComponentModel;
3 using System.Drawing;
4 using System.Threading;
5 using System.Windows.Forms;
6 using Skyiv.Ben.PushBox.Common;
7
8 namespace Skyiv.Ben.PushBox.Window
9 {
10 /// <summary>
11 /// 程序的主窗体
12 /// </summary>
13 public partial class MainForm : Form
14 {
15 Env env; // 工作环境
16
17 public MainForm()
18 {
19 env = new Env();
20 InitializeComponent();
21 }
22
23 protected override void OnLoad(EventArgs e)
24 {
25 base.OnLoad(e);
26 miTopMost.Enabled = (Environment.OSVersion.Platform != PlatformID.WinCE);
27 env.LoadConfig();
28 env.LoadGroup();
29 LoadLevel(true);
30 if (env.IsSave) Restore(env.Steps);
31 }
32
33 protected override void OnClosing(CancelEventArgs e)
34 {
35 if (env.IsDesign || env.IsReplay)
36 {
37 MessageBox.Show("正在“" + (env.IsDesign ? "设计" : "回放") + "”,不能退出。请" +
38 (env.IsDesign ? "先“保存”或者“放弃”。" : "等待“回放”完成,或者停止回放。"), "提醒");
39 e.Cancel = true;
40 }
41 else
42 {
43 env.SaveConfig();
44 env.Dispose();
45 }
46 base.OnClosing(e);
47 }
48
49 protected override void OnResize(EventArgs e)
50 {
51 base.OnResize(e);
52 ClientSizeChanged();
53 }
54
55 protected override void OnKeyDown(KeyEventArgs e)
56 {
57 if (!env.IsReplay && !env.IsDesign)
58 {
59 Direction dir = Direction.None;
60 switch (e.KeyCode)
61 {
62 case Keys.Right: dir = Direction.East; break;
63 case Keys.Down: dir = Direction.South; break;
64 case Keys.Left: dir = Direction.West; break;
65 case Keys.Up: dir = Direction.North; break;
66 }
67 StepIt(dir, true);
68 e.Handled = true;
69 }
70 base.OnKeyDown(e);
71 }
72
73 protected override void OnMouseDown(MouseEventArgs e)
74 {
75 base.OnMouseDown(e);
76 if (!env.IsReplay) env.ToPixel = new Point(e.X, e.Y);
77 }
78
79 protected override void OnClick(EventArgs e)
80 {
81 if (env.IsDesign) Design();
82 else if (!env.IsReplay && !TryPush()) TryMove();
83 base.OnClick(e);
84 }
85
86 protected override void OnPaint(PaintEventArgs e)
87 {
88 base.OnPaint(e);
89 env.Draw(e.Graphics, e.ClipRectangle);
90 }
91
92 private void miExit_Click(object sender, EventArgs e)
93 {
94 Close();
95 }
96
97 private void miOption_Click(object sender, EventArgs e)
98 {
99 using (OptionDlg dlg = new OptionDlg(TopMost))
100 {
101 dlg.MaxLevelSize = env.MaxLevelSize;
102 dlg.StepDelay = env.StepDelay;
103 dlg.ReplayDelay = env.ReplayDelay;
104 dlg.IsSave = env.IsSave;
105 if (dlg.ShowDialog() == DialogResult.OK)
106 {
107 env.MaxLevelSize = dlg.MaxLevelSize;
108 env.StepDelay = dlg.StepDelay;
109 env.ReplayDelay = dlg.ReplayDelay;
110 env.IsSave = dlg.IsSave;
111 }
112 }
113 }
114
115 private void miErrorMsg_Click(object sender, EventArgs e)
116 {
117 using (ErrorMsgDlg dlg = new ErrorMsgDlg(TopMost))
118 {
119 dlg.ErrorMsg = env.ErrorMsg;
120 dlg.DebugMsg = env.DebugMsg;
121 dlg.ShowDialog();
122 }
123 }
124
125 private void miAbout_Click(object sender, EventArgs e)
126 {
127 using (Form dlg = new AboutDlg(TopMost))
128 {
129 dlg.ShowDialog();
130 }
131 }
132
133 private void miTopic_Click(object sender, EventArgs e)
134 {
135 using (Form dlg = new TopicDlg(TopMost))
136 {
137 dlg.ShowDialog();
138 }
139 }
140
141 private void miStatusbar_Click(object sender, EventArgs e)
142 {
143 miStatusbar.Checked = !miStatusbar.Checked;
144 sbrMain.Visible = miStatusbar.Checked;
145 ClientSizeChanged();
146 }
147
148 private void miTopMost_Click(object sender, EventArgs e)
149 {
150 TopMost = miTopMost.Checked = !miTopMost.Checked;
151 }
152
153 private void miRestartOrStopOrSave_Click(object sender, EventArgs e)
154 {
155 if (env.IsDesign)
156 {
157 env.SaveDesign();
158 LoadLevel(true);
159 }
160 else if (env.IsReplay) workerThreadIsStop = true;
161 else LoadLevel(false);
162 }
163
164 private void miUndoOrCancel_Click(object sender, EventArgs e)
165 {
166 if (env.IsDesign)
167 {
168 if (env.Active == Action.Create) env.Level = env.LeveLOem;
169 LoadLevel(true);
170 }
171 else
172 {
173 for (bool isFirst = true; ; isFirst = false)
174 {
175 if (!isFirst && env.StepDelay > 0) Thread.Sleep(env.StepDelay);
176 if (Back()) break;
177 }
178 }
179 }
180
181 private void miRecordOrBrick_Click(object sender, EventArgs e)
182 {
183 if (env.IsDesign)
184 {
185 env.Pen = Block.Brick;
186 UpdateStatus();
187 }
188 else
189 {
190 env.Record();
191 UpdateStatus();
192 miRecordOrBrick.Enabled = false;
193 Update();
194 }
195 }
196
197 private void miBackOrManOrBox_Click(object sender, EventArgs e)
198 {
199 if (env.IsDesign)
200 {
201 env.Pen = env.HasWorker ? Block.Box0 : Block.Man0;
202 UpdateStatus();
203 }
204 else Back();
205 }
206
207 private void miConfig_Click(object sender, EventArgs e)
208 {
209 using (ConfigDlg dlg = new ConfigDlg(TopMost))
210 {
211 dlg.Groups = env.Groups;
212 if (dlg.ShowDialog() == DialogResult.OK)
213 {
214 env.Init();
215 env.SaveConfig(dlg.Groups);
216 env.LoadConfig();
217 env.LoadGroup();
218 LoadLevel(true);
219 }
220 }
221 }
222
223 private void miTran_Click(object sender, EventArgs e)
224 {
225 env.Dispose();
226 using (TranDlg dlg = new TranDlg(TopMost))
227 {
228 dlg.MaxLevelSize = env.MaxLevelSize;
229 dlg.Groups = env.Groups;
230 dlg.ShowDialog();
231 }
232 env.Init();
233 env.LoadGroup();
234 LoadLevel(true);
235 }
236
237 private void miFirstLevel_Click(object sender, EventArgs e)
238 {
239 env.Level = 0;
240 LoadLevel(true);
241 }
242
243 private void miPrevLevel2OrSlot_Click(object sender, EventArgs e)
244 {
245 if (env.IsDesign)
246 {
247 env.Pen = Block.Slot;
248 UpdateStatus();
249 }
250 else
251 {
252 if (env.Level <= 0) return;
253 env.Level--;
254 LoadLevel(true);
255 }
256 }
257
258 private void miNextLevel2OrWall_Click(object sender, EventArgs e)
259 {
260 if (env.IsDesign)
261 {
262 env.Pen = Block.Wall;
263 UpdateStatus();
264 }
265 else
266 {
267 if (env.Level >= env.MaxLevel - 1) return;
268 env.Level++;
269 LoadLevel(true);
270 }
271 }
272
273 private void miLastLevel_Click(object sender, EventArgs e)
274 {
275 env.Level = env.MaxLevel - 1;
276 LoadLevel(true);
277 }
278
279 private void miSelectLevel_Click(object sender, EventArgs e)
280 {
281 using (SelectLevelDlg dlg = new SelectLevelDlg(TopMost))
282 {
283 dlg.MaxLevel = env.MaxLevel;
284 dlg.Level = env.Level;
285 if (dlg.ShowDialog() == DialogResult.OK)
286 {
287 env.Level = dlg.Level;
288 LoadLevel(true);
289 }
290 }
291 }
292
293 private void miFirstGroup_Click(object sender, EventArgs e)
294 {
295 env.Group = 0;
296 env.LoadGroup();
297 LoadLevel(true);
298 }
299
300 private void miPrevGroup_Click(object sender, EventArgs e)
301 {
302 if (env.Group <= 0) return;
303 env.Group--;
304 env.LoadGroup();
305 LoadLevel(true);
306 }
307
308 private void miNextGroup_Click(object sender, EventArgs e)
309 {
310 if (env.Group > env.Groups.Length - 1) return;
311 env.Group++;
312 env.LoadGroup();
313 LoadLevel(true);
314 }
315
316 private void miLastGroup_Click(object sender, EventArgs e)
317 {
318 env.Group = env.Groups.Length - 1;
319 env.LoadGroup();
320 LoadLevel(true);
321 }
322
323 private void miSelectGroup_Click(object sender, EventArgs e)
324 {
325 using (SelectGroupDlg dlg = new SelectGroupDlg(TopMost))
326 {
327 dlg.Groups = env.Groups;
328 dlg.Group = env.Group;
329 if (dlg.ShowDialog() == DialogResult.OK)
330 {
331 env.Group = dlg.Group;
332 env.LoadGroup();
333 LoadLevel(true);
334 }
335 }
336 }
337 }
338 }
2 using System.ComponentModel;
3 using System.Drawing;
4 using System.Threading;
5 using System.Windows.Forms;
6 using Skyiv.Ben.PushBox.Common;
7
8 namespace Skyiv.Ben.PushBox.Window
9 {
10 /// <summary>
11 /// 程序的主窗体
12 /// </summary>
13 public partial class MainForm : Form
14 {
15 Env env; // 工作环境
16
17 public MainForm()
18 {
19 env = new Env();
20 InitializeComponent();
21 }
22
23 protected override void OnLoad(EventArgs e)
24 {
25 base.OnLoad(e);
26 miTopMost.Enabled = (Environment.OSVersion.Platform != PlatformID.WinCE);
27 env.LoadConfig();
28 env.LoadGroup();
29 LoadLevel(true);
30 if (env.IsSave) Restore(env.Steps);
31 }
32
33 protected override void OnClosing(CancelEventArgs e)
34 {
35 if (env.IsDesign || env.IsReplay)
36 {
37 MessageBox.Show("正在“" + (env.IsDesign ? "设计" : "回放") + "”,不能退出。请" +
38 (env.IsDesign ? "先“保存”或者“放弃”。" : "等待“回放”完成,或者停止回放。"), "提醒");
39 e.Cancel = true;
40 }
41 else
42 {
43 env.SaveConfig();
44 env.Dispose();
45 }
46 base.OnClosing(e);
47 }
48
49 protected override void OnResize(EventArgs e)
50 {
51 base.OnResize(e);
52 ClientSizeChanged();
53 }
54
55 protected override void OnKeyDown(KeyEventArgs e)
56 {
57 if (!env.IsReplay && !env.IsDesign)
58 {
59 Direction dir = Direction.None;
60 switch (e.KeyCode)
61 {
62 case Keys.Right: dir = Direction.East; break;
63 case Keys.Down: dir = Direction.South; break;
64 case Keys.Left: dir = Direction.West; break;
65 case Keys.Up: dir = Direction.North; break;
66 }
67 StepIt(dir, true);
68 e.Handled = true;
69 }
70 base.OnKeyDown(e);
71 }
72
73 protected override void OnMouseDown(MouseEventArgs e)
74 {
75 base.OnMouseDown(e);
76 if (!env.IsReplay) env.ToPixel = new Point(e.X, e.Y);
77 }
78
79 protected override void OnClick(EventArgs e)
80 {
81 if (env.IsDesign) Design();
82 else if (!env.IsReplay && !TryPush()) TryMove();
83 base.OnClick(e);
84 }
85
86 protected override void OnPaint(PaintEventArgs e)
87 {
88 base.OnPaint(e);
89 env.Draw(e.Graphics, e.ClipRectangle);
90 }
91
92 private void miExit_Click(object sender, EventArgs e)
93 {
94 Close();
95 }
96
97 private void miOption_Click(object sender, EventArgs e)
98 {
99 using (OptionDlg dlg = new OptionDlg(TopMost))
100 {
101 dlg.MaxLevelSize = env.MaxLevelSize;
102 dlg.StepDelay = env.StepDelay;
103 dlg.ReplayDelay = env.ReplayDelay;
104 dlg.IsSave = env.IsSave;
105 if (dlg.ShowDialog() == DialogResult.OK)
106 {
107 env.MaxLevelSize = dlg.MaxLevelSize;
108 env.StepDelay = dlg.StepDelay;
109 env.ReplayDelay = dlg.ReplayDelay;
110 env.IsSave = dlg.IsSave;
111 }
112 }
113 }
114
115 private void miErrorMsg_Click(object sender, EventArgs e)
116 {
117 using (ErrorMsgDlg dlg = new ErrorMsgDlg(TopMost))
118 {
119 dlg.ErrorMsg = env.ErrorMsg;
120 dlg.DebugMsg = env.DebugMsg;
121 dlg.ShowDialog();
122 }
123 }
124
125 private void miAbout_Click(object sender, EventArgs e)
126 {
127 using (Form dlg = new AboutDlg(TopMost))
128 {
129 dlg.ShowDialog();
130 }
131 }
132
133 private void miTopic_Click(object sender, EventArgs e)
134 {
135 using (Form dlg = new TopicDlg(TopMost))
136 {
137 dlg.ShowDialog();
138 }
139 }
140
141 private void miStatusbar_Click(object sender, EventArgs e)
142 {
143 miStatusbar.Checked = !miStatusbar.Checked;
144 sbrMain.Visible = miStatusbar.Checked;
145 ClientSizeChanged();
146 }
147
148 private void miTopMost_Click(object sender, EventArgs e)
149 {
150 TopMost = miTopMost.Checked = !miTopMost.Checked;
151 }
152
153 private void miRestartOrStopOrSave_Click(object sender, EventArgs e)
154 {
155 if (env.IsDesign)
156 {
157 env.SaveDesign();
158 LoadLevel(true);
159 }
160 else if (env.IsReplay) workerThreadIsStop = true;
161 else LoadLevel(false);
162 }
163
164 private void miUndoOrCancel_Click(object sender, EventArgs e)
165 {
166 if (env.IsDesign)
167 {
168 if (env.Active == Action.Create) env.Level = env.LeveLOem;
169 LoadLevel(true);
170 }
171 else
172 {
173 for (bool isFirst = true; ; isFirst = false)
174 {
175 if (!isFirst && env.StepDelay > 0) Thread.Sleep(env.StepDelay);
176 if (Back()) break;
177 }
178 }
179 }
180
181 private void miRecordOrBrick_Click(object sender, EventArgs e)
182 {
183 if (env.IsDesign)
184 {
185 env.Pen = Block.Brick;
186 UpdateStatus();
187 }
188 else
189 {
190 env.Record();
191 UpdateStatus();
192 miRecordOrBrick.Enabled = false;
193 Update();
194 }
195 }
196
197 private void miBackOrManOrBox_Click(object sender, EventArgs e)
198 {
199 if (env.IsDesign)
200 {
201 env.Pen = env.HasWorker ? Block.Box0 : Block.Man0;
202 UpdateStatus();
203 }
204 else Back();
205 }
206
207 private void miConfig_Click(object sender, EventArgs e)
208 {
209 using (ConfigDlg dlg = new ConfigDlg(TopMost))
210 {
211 dlg.Groups = env.Groups;
212 if (dlg.ShowDialog() == DialogResult.OK)
213 {
214 env.Init();
215 env.SaveConfig(dlg.Groups);
216 env.LoadConfig();
217 env.LoadGroup();
218 LoadLevel(true);
219 }
220 }
221 }
222
223 private void miTran_Click(object sender, EventArgs e)
224 {
225 env.Dispose();
226 using (TranDlg dlg = new TranDlg(TopMost))
227 {
228 dlg.MaxLevelSize = env.MaxLevelSize;
229 dlg.Groups = env.Groups;
230 dlg.ShowDialog();
231 }
232 env.Init();
233 env.LoadGroup();
234 LoadLevel(true);
235 }
236
237 private void miFirstLevel_Click(object sender, EventArgs e)
238 {
239 env.Level = 0;
240 LoadLevel(true);
241 }
242
243 private void miPrevLevel2OrSlot_Click(object sender, EventArgs e)
244 {
245 if (env.IsDesign)
246 {
247 env.Pen = Block.Slot;
248 UpdateStatus();
249 }
250 else
251 {
252 if (env.Level <= 0) return;
253 env.Level--;
254 LoadLevel(true);
255 }
256 }
257
258 private void miNextLevel2OrWall_Click(object sender, EventArgs e)
259 {
260 if (env.IsDesign)
261 {
262 env.Pen = Block.Wall;
263 UpdateStatus();
264 }
265 else
266 {
267 if (env.Level >= env.MaxLevel - 1) return;
268 env.Level++;
269 LoadLevel(true);
270 }
271 }
272
273 private void miLastLevel_Click(object sender, EventArgs e)
274 {
275 env.Level = env.MaxLevel - 1;
276 LoadLevel(true);
277 }
278
279 private void miSelectLevel_Click(object sender, EventArgs e)
280 {
281 using (SelectLevelDlg dlg = new SelectLevelDlg(TopMost))
282 {
283 dlg.MaxLevel = env.MaxLevel;
284 dlg.Level = env.Level;
285 if (dlg.ShowDialog() == DialogResult.OK)
286 {
287 env.Level = dlg.Level;
288 LoadLevel(true);
289 }
290 }
291 }
292
293 private void miFirstGroup_Click(object sender, EventArgs e)
294 {
295 env.Group = 0;
296 env.LoadGroup();
297 LoadLevel(true);
298 }
299
300 private void miPrevGroup_Click(object sender, EventArgs e)
301 {
302 if (env.Group <= 0) return;
303 env.Group--;
304 env.LoadGroup();
305 LoadLevel(true);
306 }
307
308 private void miNextGroup_Click(object sender, EventArgs e)
309 {
310 if (env.Group > env.Groups.Length - 1) return;
311 env.Group++;
312 env.LoadGroup();
313 LoadLevel(true);
314 }
315
316 private void miLastGroup_Click(object sender, EventArgs e)
317 {
318 env.Group = env.Groups.Length - 1;
319 env.LoadGroup();
320 LoadLevel(true);
321 }
322
323 private void miSelectGroup_Click(object sender, EventArgs e)
324 {
325 using (SelectGroupDlg dlg = new SelectGroupDlg(TopMost))
326 {
327 dlg.Groups = env.Groups;
328 dlg.Group = env.Group;
329 if (dlg.ShowDialog() == DialogResult.OK)
330 {
331 env.Group = dlg.Group;
332 env.LoadGroup();
333 LoadLevel(true);
334 }
335 }
336 }
337 }
338 }
几点说明:
- env 字段表示推箱子的工作环境,其类型为 Env,请参见:使用 C# 开发智能手机软件:推箱子(十一)。
- OnLoad 方法在主窗体装入时被调用,完成必要的初始化工作。首先根据本程序是否在智能手机上运行来决定是否禁用“前端显示”功能,然后依次读取配置文件,装入当前组,装入当前关,再根据需要恢复现场(即本程序上次退出时已经走过的步骤)。
- OnClosing 方法将在程序主窗体关闭(也就是退出本程序)时被调用,首先判断是否正在“设计”或者“回放”,如果是,则不允许退出本程序。否则,保护现场后退出本程序。
- OnResize 方法是主窗体尺寸发生变化时要采取的动作。在智能手机上主要是横屏和竖屏之间的切换。
- OnKeyDown 方法处理键盘动作,也就是处理上下左右四个方向键。这主要用于 Smartphone 的情况。如果是 Pocket PC Phone 或者计算机,一般会使用触摸屏或鼠标。
- OnMouseDown 方法在鼠标点击时记录其坐标。
- OnClick 方法处理鼠标点击动作。
- OnPaint 方法负责绘制程序的主窗体。
- miExit_Click 方法表示用户点击“菜单 -> 退出”时的动作,她只是简单地调用 Form 类的 Close 方法关闭程序主窗体,从而退出本程序。
- miOption_Click 方法表示用户点击“菜单 -> 选项”时的动作,她调用 OptionDlg 类来显示“选项”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十五)。
- miErrorMsg_Click 方法表示用户点击“菜单 -> 帮助 -> 错误信息”时的动作,她调用 ErrorMsgDlg 类来显示“错误信息”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十四)。
- miAbout_Click 方法表示用户点击“菜单 -> 帮助 -> 关于”时的动作,她调用 AboutDlg 类来显示“关于”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十二)。
- miTopic_Click 方法表示用户点击“菜单 -> 帮助 -> 帮助主题”时的动作,她调用 TopicDlg 类来显示“帮助”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十三)。
- miStatusbar_Click 方法表示用户点击“菜单 -> 状态栏”时的动作,用来切换是否显示状态栏。
- miTopMost_Click 方法表示用户点击“菜单 -> 前端显示”时的动作,用来切换本程序是否总是显示在最前面。注意:在智能手机上本功能被禁用,因为智能手机上的所有程序都是全屏的,以免本程序始终占据屏幕最前端而影响手机的使用。
- miConfig_Click 方法表示用户点击“菜单 -> 数据 -> 配置”时的动作,她调用 ConfigDlg 类来显示“配置”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十六)。
- miTran_Click 方法表示用户点击“菜单 -> 数据 -> 转换”时的动作,她调用 TranDlg 类来显示“转换”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十九)。
- miSelectLevel_Click 方法表示用户点击“菜单 -> 关 -> 选关”时的动作,她调用 SelectLevelDlg 类来显示“选关”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十八)。
- miSelectGroup_Click 方法表示用户点击“菜单 -> 组 -> 选组”时的动作,她调用 SelectGroupDlg 类来显示“选组”对话框,请参见:使用 C# 开发智能手机软件:推箱子(十七)。
上一篇:使用 C# 开发智能手机软件:推箱子(二十三)
返回目录
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述