📄 maindlg.cpp
字号:
// MainDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Elevator.h"
#include "MainDlg.h"
#include "math.h"
#include "Splash.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/*####################################################################
模块名称: 主控中心
开发作者: 漫步阳光
开发时间: @2005.11
####################################################################*/
/////////////////////////////////////////////////////////////////////////////
// CMainDlg dialog
CMainDlg::CMainDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMainDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMainDlg)
//}}AFX_DATA_INIT
try
{
CreateDirectory("logs",NULL);//创建存放日志的目录
}catch(CException* e){
AfxMessageBox("无法创建日志目录,可能是没有权限。\n\n因此本系统日志功能将失效。但不会影响系统正常运行。");
}
try{
m_cLogFile.Open("logs\\log0.txt", CFile::modeCreate|CFile::modeNoTruncate|CFile::modeWrite\
| CFile::typeText , &m_Except);//打开日志文件
m_cLogFile.SeekToEnd();
}catch(CException* e){}
str_arrElevatorName[0]='A';
str_arrElevatorName[1]='B';
str_arrElevatorName[2]='C';
str_arrElevatorName[3]='D';
iTotalFailTimes = 0;
}
void CMainDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMainDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMainDlg, CDialog)
//{{AFX_MSG_MAP(CMainDlg)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_BTN_ABOUT, OnBtnAbout)
ON_WM_TIMER()
ON_WM_CREATE()
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(IDC_FLOORBUTTONS,IDC_FLOORBUTTONS+20,OnFloorBtnClk)
ON_MESSAGE(WM_ARRIVE_ONEFLOOR,OnOneFloorArrived)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMainDlg message handlers
void CMainDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: Add your message handler code here
for(int i=0;i<ELEVATOR_NUM;i++)
{
delete m_elevatorArr[i];
}
for(i=0;i<FLOOR_NUM;i++)
{
delete m_pFloorButton[i][0];
delete m_pFloorButton[i][1];
}
KillTimer(1);
lWaitQueue.~CircleSingleLink();
try{
Write2Log("系统成功关闭...");
m_cLogFile.Close();
}catch(CException* e){}
}
BOOL CMainDlg::OnInitDialog()
{
CDialog::OnInitDialog();
//让窗体呆在最上层:)
//SetWindowPos(&this->wndTopMost,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE);
// TODO: Add extra initialization here
//===========创建动态楼层按钮
CString strCaption;
int iPanelLeft = 795;
int iPanelTop = 70;
int iColWidth = 60;
int iRowHeight = 60;
int iBtnWidth = 55;
int iBtnHeight = 25;
int i;
try{
for(i=FLOOR_NUM;i>0;i--)
{
strCaption.Format("%d",i);
m_pFloorButton[i-1][0]=new CButton;
m_pFloorButton[i-1][1]=new CButton;
m_pFloorButton[i-1][0]->Create(strCaption+"↑",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\
CRect(\
iPanelLeft,\
iPanelTop+(10-i)*iRowHeight/2,\
iPanelLeft+iBtnWidth,\
iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\
this,IDC_FLOORBUTTONS+2*(i-1));//left,top,right,bottom
m_pFloorButton[i-1][1]->Create(strCaption+"↓",BS_PUSHBUTTON|WS_CHILD|WS_VISIBLE,\
CRect(\
iPanelLeft+iColWidth,\
iPanelTop+(10-i)*iRowHeight/2,\
iPanelLeft+iColWidth+iBtnWidth,\
iPanelTop+(10-i)*iRowHeight/2+iBtnHeight),\
this,IDC_FLOORBUTTONS+2*(i-1)+1);//left,top,right,bottom
}//for
}catch(CException* e){
AfxMessageBox("无法创建楼层按钮,程序不能正常运行。");
return FALSE;//退出!
}
//隐藏掉两个无用的按钮
m_pFloorButton[9][0]->ShowWindow(FALSE);
m_pFloorButton[0][1]->ShowWindow(FALSE);
try{
for(i=0;i<ELEVATOR_NUM;i++)
{
m_elevatorArr[i] = new CElevatorDlg(i+1,MAX_PASSENGER_NUM,(1+i*2)%FLOOR_NUM,this);
m_elevatorArr[i]->Create(IDD_ELEVATOR_DIALOG,this);
m_elevatorArr[i]->MoveWindow(CRect(i*195,0,(i+1)*195,500));
m_elevatorArr[i]->ShowWindow(SW_SHOW);
}
}catch(CException* e){
AfxMessageBox("无法创建电梯,程序不能正常运行。");
return FALSE;//退出!
}
Write2Log("系统成功启动...");
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
/*####################################################################
// name: OnFloorBtnClk
// input1: UINT curBtn
楼层按钮序号
// ouput: void
// 功能描述: 响应楼层按钮的动作
// 开发作者: 漫步阳光
// 开发时间: @2005.11
// 版本说明: v1.0
####################################################################*/
void CMainDlg::OnFloorBtnClk(UINT curBtn)
{
// TODO: Add your control notification handler code here
int iReqFloor =curBtn-1100+1;
sOuterRequest tmpOuterRequest = No2ReqStruct(iReqFloor);
if((lWaitQueue.searchNode(tmpOuterRequest)) > 0)
{
AfxMessageBox("请不要重复请求。");
return;
}
/*
//将请求加入队列
if(!(lWaitQueue.appendTail(tmpOuterRequest)))
{
AfxMessageBox("无法将您的请求加入请求队列,请稍后再试。");
return;
}
*/
GetDlgItem(curBtn)->EnableWindow(FALSE);
trytoSchedule(tmpOuterRequest);//立即尝试分派!
}
void CMainDlg::OnCancel()
{
// TODO: Add extra cleanup here
if(IDYES==MessageBox("是否真的结束?","电梯系统",MB_YESNO))
CDialog::OnCancel();
}
/*####################################################################
// name: No2ReqStruct
// input1: int iNo
楼层按钮序号
// ouput: sOuterRequest
该按钮对应的楼层和方向结构体
// 功能描述: 将楼层按钮序号转换成对应的楼层和方向
// 开发作者: 漫步阳光
// 开发时间: @2005.11
// 版本说明: v1.0
####################################################################*/
sOuterRequest CMainDlg::No2ReqStruct(int iNo)
{
sOuterRequest tempVal;
if(iNo%2==0)
{
tempVal.eReqDirection =DOWN;
}
else
{
tempVal.eReqDirection =UP;
iNo++;
}
tempVal.iReqFloor = iNo/2;
tempVal.iAge =0;
tempVal.bReClaimed = FALSE;
return tempVal;
}
int CMainDlg::ReqStruct2No(const sOuterRequest& tmpRequest)
{
return (tmpRequest.eReqDirection==UP) ? (2*(tmpRequest.iReqFloor-1)) : (2*(tmpRequest.iReqFloor-1)+1);
}
/*####################################################################
// name: Goodness
// input1: sOuterRequest tmpOuterRequest
用户请求结构体
// ouput: int
找到的最佳接收电梯(优先数最小的)的ID
// 功能描述: 为用户请求寻找一个最佳接收电梯
// 开发作者: 漫步阳光
// 开发时间: @2005.11
// 版本说明: v1.0
####################################################################*/
int CMainDlg::Goodness(const sOuterRequest& tmpOuterRequest)
{
int returnVal = -1;
//挨个查看各正常电梯的状态
int tmpCurFloor;
int tmpCurWeight;
int tmpPrioValue;
bool tmpCanSchedule;
enum state tmpState;
int iPrioValue = 10000;//优先数,优先数越小优先级越大
for(int i=0;i<ELEVATOR_NUM; i++)
{
tmpState = m_elevatorArr[i]->getState();
tmpCurFloor = m_elevatorArr[i]->getCurFloor();
tmpCurWeight = m_elevatorArr[i]->getCurWeight();
tmpCanSchedule = m_elevatorArr[i]->canSchedule();
if(tmpState!=MAL_FUNCTION && tmpCanSchedule)
{
if(tmpState==IDLE || \
(tmpOuterRequest.eReqDirection==UP && (tmpState==UP_RUN || tmpState==UP_PAUSE)) || \
(tmpOuterRequest.eReqDirection==DOWN && (tmpState==DOWN_RUN || tmpState==DOWN_PAUSE)) )
{
if(tmpState==IDLE)
{
//计算该电梯的优先数
tmpPrioValue = DIST_PRIO*abs(tmpOuterRequest.iReqFloor-tmpCurFloor)+\
WEIGHT_PRIO*tmpCurWeight;
if(tmpPrioValue<iPrioValue)
{
iPrioValue = tmpPrioValue;
returnVal = i;
}
}
if(tmpOuterRequest.eReqDirection==UP && tmpOuterRequest.iReqFloor>=tmpCurFloor)
{
//计算该电梯的优先数
tmpPrioValue = DIST_PRIO*(tmpOuterRequest.iReqFloor-tmpCurFloor)+\
WEIGHT_PRIO*tmpCurWeight;
if(tmpPrioValue<iPrioValue)
{
iPrioValue = tmpPrioValue;
returnVal = i;
}
}
if(tmpOuterRequest.eReqDirection==DOWN && tmpOuterRequest.iReqFloor<=tmpCurFloor)
{
//计算该电梯的优先数
tmpPrioValue = DIST_PRIO*(tmpCurFloor-tmpOuterRequest.iReqFloor)+\
WEIGHT_PRIO*tmpCurWeight;
if(tmpPrioValue<iPrioValue)
{
iPrioValue = tmpPrioValue;
returnVal = i;
}
}
}
}
}//for
return returnVal;
}
/*####################################################################
// name: Schedule
// input1:
// ouput: void
// 功能描述: 定时处理主控中心请求队列中请求
// 开发作者: 漫步阳光
// 开发时间: @2005.11
// 版本说明: v1.0
// 行为说明:
该函数被周期性激活,以定时分发请求队列中的请求
该函数在队列空时停止定时器并直接返回,否则
对于当前等待队列中的每个请求尝试分发::
将成功分发出去的请求删除,未成功分发的做好标记并增加年龄后重新放回队列
对于年龄大于一定值(也就是超过一定时间仍未得到分派)的请求则直接删除
####################################################################*/
void CMainDlg::Schedule()
{
if(lWaitQueue.getLength() == 0)
{
KillTimer(1);//队列空了,歇会
return;
}
int iReqFloor;
CString tempString,tempString1;
sOuterRequest tmpOuterRequest;
while(lWaitQueue.cutHead(tmpOuterRequest) && !tmpOuterRequest.bReClaimed)
{
if(tmpOuterRequest.iAge < BAD_REQUEST_AGE)//如果此请求长时间没有得到分配,则直接删除
{
trytoSchedule(tmpOuterRequest);
}
else//对于长时间不能调度出去的请求也要处理一下后事:(
{
iReqFloor = ReqStruct2No(tmpOuterRequest);//转换成请求按钮号
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE);
iTotalFailTimes++;//递增总调度失败次数
tempString.Format("%d",tmpOuterRequest.iReqFloor);
tempString1 = (tmpOuterRequest.eReqDirection==UP) ? "↑":"↓";
AfxMessageBox("很抱歉,下面的请求因超时而被系统取消,请重新请求。\r\n"+tempString+tempString1);
}
}
//将本次追加到队尾的请求标识位恢复
if(tmpOuterRequest.bReClaimed){
tmpOuterRequest.bReClaimed = FALSE;
lWaitQueue.appendTail(tmpOuterRequest);
}
lWaitQueue.refreshLink();
}
void CMainDlg::trytoSchedule(sOuterRequest& tmpRequest)
{
int targetElevator=-1,iReqFloor;
CString tempString,tempString1;
if((targetElevator = Goodness(tmpRequest))<0)//目前没有找到合适的接受者,再放入
{
tmpRequest.iAge++;
tmpRequest.bReClaimed = TRUE;
lWaitQueue.appendTail(tmpRequest);
}
else //发消息给目标电梯
{
//对于电梯刚好在当前楼层的情况,电梯的返回往往比下面的程序段还要快!
//所以此段程序不能跟下面的那行调换位置!!!
tempString1.Format("%c",str_arrElevatorName[targetElevator]);
iReqFloor = ReqStruct2No(tmpRequest);//转换成请求按钮号
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString);
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString+"("+tempString1+")");
m_elevatorArr[targetElevator]->acceptReq(tmpRequest);
}
KillTimer(1);
SetTimer(1,SCHEDULE_INTERVAL*1000,NULL);//启动主控中心调度定时器
}
void CMainDlg::OnBtnAbout()
{
::AfxMessageBox("关于本电梯系统", MB_USERDEFINE);
}
void CMainDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
switch(nIDEvent)
{
case 1:
Schedule();
break;
}
CDialog::OnTimer(nIDEvent);
}
LONG CMainDlg::OnOneFloorArrived(WPARAM wP,LPARAM lP)
{
int iReqFloor=(int)wP;
CString tempString;
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->EnableWindow(TRUE);
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->GetWindowText(tempString);
if(tempString.GetLength() >4 )
{
tempString = tempString.Mid(0,tempString.GetLength()-3);
GetDlgItem(IDC_FLOORBUTTONS+iReqFloor)->SetWindowText(tempString);
}
//Invalidate(); //重画窗体
return 0;
}
void CMainDlg::Write2Log(const CString& content)
{
// TODO: Add your control notification handler code here
if(content=="") return;
CTime m_SysTime = CTime::GetCurrentTime();
try{
m_cLogFile.WriteString(content+"\t("+m_SysTime.Format("%Y-%m-%d %H:%M:%S")+")\n");
}catch(CException* e){}
}
int CMainDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
CSplashWnd::ShowSplashScreen(this); //显示启动画面
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -