结对项目之具体实施
- 电梯不工作时的楼层确认
根据和结对伙伴邹鹏华的讨论,我们决定如果电梯不工作时,1,4号电梯将分别停留在1和21层,而2,3号电梯将分别停留在10,11层这样可以尽量减少乘客的等待时间。电梯位置的初始化在窗体还未创建时完成,用窗体的Load事件,因为在一开始设计窗体时是将所有电梯的位置放在0层,所有电梯的当前楼层都是初始化为0,故要在事件中遍历所有的button控件,控件上的文字是“电梯1,“电梯2”,”电梯3“,”电梯4“的button控件的位置发生改变,用switch...case...语句来实现。具体代码如下
private void Bulding_Load(object sender, EventArgs e) { //将一号电梯初始化在一楼,二号电梯在10楼,三号电梯在11楼,四号电梯在20楼 foreach (Control oneCtr in this.Controls) { Button btnElevator = oneCtr as Button;//将control转换成checkbox if (btnElevator != null) { string btntext = btnElevator.Text; Point p = new Point(); switch (btntext) { case "电梯1": { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; currentFloor++; txtCurrentFloor.Text = (currentFloor).ToString(); break; } case "电梯2": { for (; currentFloor2 < 10; currentFloor2++) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; } txtCurrentFloor2.Text = (currentFloor2).ToString(); break; } case "电梯3": { for (; currentFloor3 < 11; currentFloor3++) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; } txtCurrentFloor3.Text = (currentFloor3).ToString(); break; } case "电梯4": { for (; currentFloor4 < 20; currentFloor4++) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; } txtCurrentFloor4.Text = (currentFloor4).ToString(); break; } } } } //取消跨线程访问 Control.CheckForIllegalCrossThreadCalls = false; }
在具体的写电梯运动程序时,主要分成两大部分。
- 电梯内部设置按钮,能使电梯到达相应的楼层
注:以下代码都以电梯1为例
在设置内部按钮时选了21个checkbox控件,用来给乘坐人员选择各自想要到达的楼层保存在selectFloors数组里,在保存时要同原先的selectFloor里的元素比较,按照从大到小的顺序加入原来的数组里,,在选择好之后,,按下确认键后,就开始电梯的移动,每一个电梯都设置了一个属性currentFloor来记录当前电梯所在楼层。如果currentFloor小于想要到达的楼层的最小值时,就开始向上移动(如何移动前文已经介绍了,不在赘述),代码如下
private void elevator1Move(object sender) { elevatorIn(); Button btnElevator = sender as Button; Point p = new Point(); if (Elevator.selFloorNum>=1) { if (currentFloor < Elevator.selectFloors[Elevator.selFloorNum - 1]) { for (int j = Elevator.selFloorNum-1; j >=0; j--)//选择好的楼层 { for (; currentFloor < Elevator.selectFloors[j] ; currentFloor++)//形成运动效果 { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor+1).ToString(); // txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); // Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 } clearcbx(currentFloor); Elevator.selFloorNum--; Elevator.selectFloors[j] = -10; Thread.CurrentThread.Join(4000); // Thread.Sleep(4000 * setInf.perFloorTime); } } if (currentFloor >= Elevator.selectFloors[0] && Elevator.selectFloors[0]!=-10) { while (Elevator.selFloorNum!=-1) { while (currentFloor > Elevator.selectFloors[0] && Elevator.selectFloors[0]!=-10) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y + btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor - 1).ToString(); // txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); //Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 currentFloor--; } clearcbx_D(currentFloor); Elevator.selectFloors[Elevator.selFloorNum] = -10; Elevator.selFloorNum--; Thread.CurrentThread.Join(4000); // Thread.Sleep(4000 * setInf.perFloorTime); } } } } private void elevatorIn() { ele.Visible = false; ele.ShowDialog(); }
在电梯运动时为了不影响其他按键的使用,因此要为电梯的运动创建一个线程,创建线程的代码如下:
private void btnElevator_Click( object sender, EventArgs e) { //创建一个移动电梯的线程,, Thread thr = new Thread(new ParameterizedThreadStart(elevator1Move));//能够传进来一个参数 //Thread thr = new Thread(elevatorMove(sender)); thr.IsBackground = true;//设置为后台线程 thr.Start(sender); }
到达楼层后将按钮变为未选择
在电梯运动时,将当前电梯所在楼层与selectFloors里的每个元素进行比较,如果没有到达元素所代表的楼层,就一层一层的移动,直到当前电梯楼层和元素一样就将选择的对应楼层的checkbox改为未选择,并将它从selectFloors中清除,代码如下
private void clearcbx_D(int currentFloor) { clearcbx(currentFloor); for(int i = 0;i<Elevator.selFloorNum;i++) { Elevator.selectFloors[i] = Elevator.selectFloors[i + 1]; } } private void clearcbx(int currentFloor ) { foreach (Control oneCtr in ele .Controls) { CheckBox ckb = oneCtr as CheckBox;//将control转换成checkbox if(ckb!=null) { if (Convert.ToInt32(ckb.Text) == currentFloor) { ckb.Checked = false; break; } } } }
当到达楼层停留一段时间(用于乘客的上下),,直到将选择的楼层都都停留了一段时间。。
- 各个楼层之间的按钮能达到将电梯叫上或叫下
谁静止谁优先响应(要符合:2号只到奇数层,3号只到偶数层),在所有电梯都是静止时(电梯里的按钮都恢复为未选状态时),叫楼梯的楼层是若是偶数,,就比较1、3、4号电梯谁离叫的楼层得近,谁响应;若是奇数,则比较1、2、4楼层谁离叫的楼层近,谁响应。。都在运动时,和都在静止时的判断响应电梯的方法一致。
当所叫楼层是偶数时的代码如下:
Button btn = sender as Button; string temnum = btn.Text.Trim(); num = Convert.ToInt32(temnum);//获得所叫楼层的楼号 if(num%2 ==0)//偶数楼层叫电梯时 { int tempnum;//保存响应的电梯号 int tempnum1 = Math.Abs(num-currentFloor); int tempnum2 = Math.Abs(num - currentFloor3); int tempnum3 = Math.Abs(num - currentFloor4); if (tempnum1 < tempnum2) { if (tempnum1 < tempnum3) { tempnum = tempnum1;//1号电梯 } else tempnum = tempnum3;//3号电梯 } else { if (tempnum2 < tempnum3) { tempnum = tempnum2;//2号电梯 } else tempnum = tempnum3;//3号电梯 }
奇数楼层的响应代码类似。
- 电梯移动同时响应外部楼层按钮
在电梯运动过程中,逗留楼层也不仅仅只有电梯内部所选择的楼层,还要加上外部所叫楼层,到达所叫楼层也一样需要停留,另外当要要相应的电梯没有选择楼层或静止时只需将电梯运动到所叫楼层即可。在电梯运动的函数中做一些改动,就能达到响应外部楼层,新改动的电梯移动函数如下。
private void elevator1Move(object sender) { elevatorIn(); Button btnElevator = sender as Button; Point p = new Point(); if (Elevator.selFloorNum>=1) { if (currentFloor < Elevator.selectFloors[Elevator.selFloorNum - 1]) { for (int j = Elevator.selFloorNum-1; j >=0; j--)//选择好的楼层 { for (; currentFloor < Elevator.selectFloors[j] || currentFloor<num; currentFloor++)//形成运动效果 { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor+1).ToString(); // txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); // Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 } clearcbx(currentFloor); Elevator.selFloorNum--; Elevator.selectFloors[j] = -10; Thread.CurrentThread.Join(4000); // Thread.Sleep(4000 * setInf.perFloorTime); } } if (currentFloor >= Elevator.selectFloors[0] && Elevator.selectFloors[0]!=-10) { while (Elevator.selFloorNum!=-1) { while (currentFloor > Elevator.selectFloors[0] && Elevator.selectFloors[0]!=-10) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y + btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor - 1).ToString(); // txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); //Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 currentFloor--; } clearcbx_D(currentFloor); Elevator.selectFloors[Elevator.selFloorNum] = -10; Elevator.selFloorNum--; Thread.CurrentThread.Join(4000); // Thread.Sleep(4000 * setInf.perFloorTime); } } } else//没有选择楼层 { if (currentFloor < num) { for (; currentFloor < num; currentFloor++) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y - btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor + 1).ToString(); //txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); // Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 } } else { while (currentFloor >num) { p.X = btnElevator.Location.X; p.Y = btnElevator.Location.Y + btnElevator.Size.Height; btnElevator.Location = p; txtCurrentFloor.Text = (currentFloor - 1).ToString(); //txtCurrentFloor2.Text = upnum; Thread.CurrentThread.Join(1000); //Thread.Sleep(1000 * setInf.perFloorTime);//将当前线程挂起(1000ms),不然看不到运动 currentFloor--; } } // clearcbx(currentFloor); // Elevator.selFloorNum--; // Elevator.selectFloors[j] = -10; Thread.CurrentThread.Join(4000); } } private void elevatorIn() { ele.Visible = false; ele.ShowDialog(); }
结对总结:
因为和结对伙伴邹鹏华都是新接触的有关c#的知识,有很多细节难免做的不到位,不完善。但是在我们的共同努力下还是将电梯的作业按时的完成了,这一点还是值得庆祝下的。非常感谢这两周的结对编程,感谢伙伴——邹鹏华!!!!!
另附:结对伙伴邹鹏华博客 http://www.cnblogs.com/fandaren/
结对项目代码详见:https://coding.net/u/zht01/p/Elevators/git
再附照片一张来纪念这两周。。。。。。。