收藏 分销(赏)

物流单据管理系统.doc

上传人:精**** 文档编号:4129519 上传时间:2024-07-31 格式:DOC 页数:21 大小:83.04KB 下载积分:10 金币
下载 相关 举报
物流单据管理系统.doc_第1页
第1页 / 共21页
物流单据管理系统.doc_第2页
第2页 / 共21页


点击查看更多>>
资源描述
物流单据管理系统 一、 案例预览 运行该系统,主界面如图一所示,有“开销售单”、“开进货单”、“查看单据”等业务,下面按业务依次说明最后实现的程序界面和操作方法。 图一 (1) 开销售单。单击程序主界面的【开销售单】按钮,弹出“销售单据”对话框,如图二所示。填完单据的各项内容后,单击【保持】按钮.如果程序提示保存成功,会返回主界面,单据列表中又增加了一张销售单据。 图二 (2) 开进货单。单击程序主界面的【开进货单】按钮,弹出“进货单据”对话框,如图三所示。开单操作和销售单类似。 图三 (3) 查看单据.在主界面中,选择要查看的单据,然后单击【查看单据】按钮,弹出对应的单据,如图四所示。此时单据不能被编辑,查看完后单击【关闭】按钮退出查看操作。 图四 二分析与创建数据库 本例采用Access 2002作为数据库,使用ADO方式访问数据库。 首先创建一个数据库,命名为“bills.mdb",并且将该数据库文件放在本实例应用程序的根目录中,便于访问。 从前面的分析知道。本例需要两个数据表bill和goods。表bill用来保持单据,包括进货单据和销售单据,单据类型用一个数字类型的字段type来区分,0表示进货单,1表示销售单。表goods用来保持单据中填写的流通商品,通过字段billid来对应某张单据,字段index表示在该单据中的表格位置。表结构如图五和图六所示。 id 文本 单据编号 type 数字 单据类型(0=进货单,1=销售单) time 日期/时间 制单日期 storage 文本 交易时使用的仓库 client 文本 交易的客户名称 operator 文本 经手人 account 文本 交易时使用的银行帐户 comment 文本 单据的附加说明 字段名称 数据类型 说明 图五(bill表) 图六(goods表) 字段名称 数据类型 说明 name 文本 商品名称 unit 文本 商品的度量单位 account 数字 商品数量 price 数字 商品单价 comment 文本 商品说明 billid 文本 所在单据的编号 index 数字 所处单据表格的位置索引 三创建VC工程 创建给予对话框的应用程序,从第二步到第六步全部采用默认方式. 四引入控件 1、表格(Grid)控件 在用VC开发关于数据库的项目时,通常使用DataGrid作为数据库表格控件。本例中介绍另外一个共享表格控件CGridCtrl,非常好用,也很美观,进货单据和销售单据显示商品时使用的就是CGridCtrl控件。 CGridCtrl和一般的GRID的不同之处在于,一般的GRID并不适合显示大的数据量,如果一个查询结果有上万条记录的话,如果都要插入到GRID中,这将是个很慢的过程,并且在GRID中移动滚动条的话,它的记录的滚动也是很慢的.而CGridCtrl并不会真正把这些记录的数据全部插入到控件中,当CGridCtrl的滚动条滚动时,它会根据CGridCtrl的显示面积的大小和查询得到的总的记录数计算当前应该显示哪些行,然后会把那几行的记录数据插入到表格中,这样速度当然是很快的,而且没有数据量多少的限制。 将表格控件CGridCtrl引入本例工程中需要如下步骤. (1) 将光盘中的相关文件拷贝到创建的工程目录下,它们位于本例工程的gridctrl_src目录中. (2) 选择菜单【Project】->【Add To Project】->【Files】,打开“Insert Files into Project”对话框。选中gridctrl_src目录下的所有文件,单击【OK】按钮,将表格控件CGridCtrlDE 所有相关文件都加入到工程中。 引入表格控件完成后,可以看到新增了数个与该控件相关的类。为了使工作区整洁,增加一个文件夹“grid”,将这些新增的文件拖入其中。如下图所示: 2、位图按钮 VC提供的默认按钮形态比较单调,这里介绍一个共享按钮控件CTrackLookButton。该按钮将图标和文字一起显示,并且呈flat形式。将控件CTrackLookButton引入本例工程中需要如下步骤。 (1) 将光盘中的文件TrackLookButton.h和TrackLookButton。cpp拷贝到创建的工程目录中. (2) 选择菜单【Project】-〉【Add To Project】—〉【Files】,打开“Insert Files into Project”对话框,将文件TrackLookButton。h和TrackLookButton.cpp加入工程中. 五使用ADO连接数据库 (1)VC中通过在程序中使用预编译指令#import来告诉编译器将此指令中指定的动态链接库引入工程中。在应用程序的文件stdafx.h中加入如下语句: #import ”c:\program files\common files\system\ado\msado15。dll" no_namespace rename(”EOF”,”adoEOF") (2) 在应用程序类CBillsManagerAPP的头文件中分别声明一个_ConnectionPtr和_RecordsetPtr类型的指针,访问类型为public.其代码如下: public: _ConnectionPtr m_pConnection; _RecordsetPtr m_pRecordset; (3)在CBillsManagerApp::InitInstance()成员函数里,初始化OLE/COM库环境,创建连接对象,打开与数据源的连接,以及创建记录集对象。其代码如下: BOOL CBillsManagerApp::InitInstance() { AfxEnableControlContainer(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need. #ifdef _AFXDLL Enable3dControls(); // Call this when using MFC in a shared DLL #else Enable3dControlsStatic(); // Call this when linking to MFC statically #endif //初始化com环境 ::CoInitialize(NULL); //创建连接对象和记录集对象 HRESULT hr; try { hr = m_pConnection。CreateInstance(”ADODB。Connection");//创建Connection对 象 if(SUCCEEDED(hr)) { hr = m_pConnection-〉Open( ”Provider=Microsoft。Jet。OLEDB。4.0;Data Source=bills。mdb", ””,"",adModeUnknown);///连接数据库 ///上面一句中连接字串中的Provider是针对ACCESS2000环境的, //对于ACCESS97,需要改为:Provider=Microsoft.Jet。OLEDB.3。51 } } catch(_com_error e)///捕捉异常 { CString errormessage; errormessage.Format("连接数据库失败!\r\n错误信息:%s",e。ErrorMessage()); AfxMessageBox(errormessage);///显示错误信息 } m_pRecordset.CreateInstance(__uuidof(Recordset)); CBillsManagerDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg。DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; } (4) 通过ClassWizard为类CBillsManagerApp增加ExitInstance() 成员函数,该函数在退出系统时被调用。在其中关闭数据库连接,并且还原OLE/COM库环境。其代码如下: int CBillsManagerApp::ExitInstance() { m_pConnection-〉Close(); //还原com环境 ::CoUninitialize(); return CWinApp::ExitInstance(); } 六实现单据对话框功能 该对话框用来开销售单、开进货单、查看单据。 (一) 制作对话框 (1)为对话框添加控件,最后效果如下: 其中2个按钮都还只是普通按钮,但我们要重画它们,所以设置它们的“Owner draw"属性。灰色部分是Custom Control控件。就是控件工具栏中的人头控件。其具体设置如下所示: 这里MFCGridCtrl是前面加入工程的表格控件CGridCtrl的窗口类,在GridCtrl。h中有定义。 (2)为单据对话框新建一个对话框类,命名为CBillDlg. (3)为CBillDlg类作变量关联。相关的变量设置如下: 上面的有些错误,其中保存和退出按钮的关联变量m_btSave和m_btExit都是CButton型的,而不是CTrackLookButton型。 (二) 定义成员变量 (1)为了使用前面引入的图标按钮CTrackLookButton和表格控件CGridCtrl,在BillDlg。h中的类CBillDlg定义前加入如下头文件,代码如下: #include "GridCtrl_src/GridCtrl.h” #include "TrackLookButton。h” (2) 在BillDlg.h中更改已经定义的变量m_btSave和m_btExit的类型,由原来的CButton型变为CTrackLookButton型: CTrackLookButton m_btExit; CTrackLookButton m_btSave; (3)在BillDlg.h中定义CGridCtrl类型的变量m_Grid,然后在void CBillDlg::DoDataExchange(CDataExchange* pDX)中使其与对话框资源中的ID为IDC_GRID的Custom Control控件关联,代码分别如下: void CBillDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CBillDlg) //}}AFX_DATA_MAP DDX_GridControl(pDX, IDC_GRID, m_Grid); } (4) 在BillDlg.h中定义表示表格控件m_Grid的行数、列数、固定行数和固定列数,便用在程序中用代码灵活控制这些参数,定义如下: protected: int m_nRows,m_nCols,m_nFixRows,m_nFixCols; (5)在BillDlg。h中定义表格控件中商品名称、计量单位、数量、单价、金额和备注等所处的列,基数为0: //定义商品信息处于grid中的位置 int m_nNameCol,m_nUnitCol,m_nAmountCol,m_nPriceCol,m_nMoneyCol,m_nCommentCol; (6)由于对话框CBillDlg既用来开销售单,又用来开进货单,因此为了区分开它们,在BillDlg。h中定义表示单据类型的变量m_nBillType,并且是public类型的: int m_nBillType; //0表示进货单,1表示销售单 (7)由于对话框类CBillDlg既用来开单据,又用来查看单据,而且查看单据时编辑框和网格控件都是不能操作的.为了区分开来,在BillDlg。h中定义表示状态的变量m_bShowBill,并且是public类型的: BOOL m_bShowBill; //TRUE表示查看单据,FALSE表示是开进货单或者销售单 (8) 在构造函数CBillDlg(CWnd* pParent)中初始化前面定义的所有变量,其代码如下: CBillDlg::CBillDlg(CWnd* pParent /*=NULL*/) : CDialog(CBillDlg::IDD, pParent) { //{{AFX_DATA_INIT(CBillDlg) m_strAccount = _T("”); m_strBillID = _T(”"); m_strClient = _T(””); m_strComment = _T(""); m_strStorage = _T(”"); m_tTime = CTime::GetCurrentTime();; m_strOperator = _T(””); //}}AFX_DATA_INIT m_nRows = 16; m_nCols = 6; m_nFixRows = 1; m_nFixCols = 0; m_nNameCol = 0; m_nUnitCol = 1; m_nAmountCol = 2; m_nPriceCol = 3; m_nMoneyCol = 4; m_nCommentCol = 5; m_nBillType = 1;//销售单 m_bShowBill = FALSE; } (三) 在BOOL CBillDlg::OnInitDialog() 函数中初始化对话框 通过ClassWizard引入对话框的OnInitDialog()函数,在该函数中加入一些初始化的代码,包括:根据单据类型设置窗口标题,设置图标按钮的风格,初始化表格控件的风格,设置表格控件的行数、列数、固定行数、固定列数等参数,设置列表控件的表头和列宽,如果是查看单据的话还显示要查看的单据.其完整的代码如下: BOOL CBillDlg::OnInitDialog() { CDialog::OnInitDialog(); //根据单据类型,设置对话框的标题 if(m_nBillType == 0) SetWindowText(”进货单据"); else SetWindowText(”销售单据”); //设置按钮风格 m_btSave.LoadBitmaps(IDB_SAVE,IDB_SAVE,IDB_SAVE); m_btSave.SetTextAlignment(CTrackLookButton::AlignRight); m_btExit。LoadBitmaps(IDB_EXIT,IDB_EXIT,IDB_EXIT); m_btExit。SetTextAlignment(CTrackLookButton::AlignRight); //初始化grid并设置其风格 m_Grid.EnableDragAndDrop(TRUE); m_Grid.SetTextBkColor(RGB(0xFF, 0xFF, 0xE0)); //设置grid的行数、列数、固定行数、固定列数 m_Grid.SetRowCount(m_nRows); m_Grid。SetColumnCount(m_nCols); m_Grid。SetFixedRowCount(m_nFixRows); m_Grid.SetFixedColumnCount(m_nFixCols); char gridHeader[6][10] = {"商品名称”,"单位",”数量”,"单价","金额","备注"}; //填充表格的表头,并且设置列宽 for (int col = 0; col 〈 m_Grid。GetColumnCount(); col++) { GV_ITEM Item; Item。mask = GVIF_TEXT|GVIF_FORMAT; Item.row = 0; Item.col = col; Item。nFormat = DT_LEFT|DT_WORDBREAK|DT_NOPREFIX; Item。strText = gridHeader[col]; m_Grid。SetItem(&Item); m_Grid.SetColumnWidth(col,78); } //如果是查看单据,则显示该单据 if(m_bShowBill) ShowBill(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } 上面的代码中调用了函数ShowBill()来显示要查看的单据,于是需要给类CBillDlg增加该成员函数,在BillDlg.h中声明为Protected类型,在BillDlg.cpp中实现。由于是在查看单据时调用该函数,需要实现的功能包括:使编辑框等都无效:在【保存】按钮隐藏,并且将【退出】按钮的Caption变为“关闭”;让表格中的商品名称、编号等列不能编辑;根据单据编号查询数据表bill,返回一条记录,填充表格外的记录(录单日期、客户、银行帐户、仓库、附加说明、经手人等);根据单据编号查询数据表goods,返回多条对应的记录,填充表格内的数据;调用函数UpdateData(FALSE)更新单据的显示。其完整代码如下: void CBillDlg::ShowBill() { //使编辑框都无效 CWnd* pWnd = GetDlgItem(IDC_TIME); pWnd-〉EnableWindow(FALSE); pWnd = GetDlgItem(IDC_BILL_ID); pWnd—>EnableWindow(FALSE); pWnd = GetDlgItem(IDC_COMMENT); pWnd—〉EnableWindow(FALSE); pWnd = GetDlgItem(IDC_CLIENT); pWnd-〉EnableWindow(FALSE); pWnd = GetDlgItem(IDC_ACCOUNT); pWnd—〉EnableWindow(FALSE); pWnd = GetDlgItem(IDC_STORAGE); pWnd—〉EnableWindow(FALSE); pWnd = GetDlgItem(IDC_OPERATOR); pWnd-〉EnableWindow(FALSE); //将“Save"按钮隐藏,并且将“退出"按钮的Caption变为“关闭” pWnd = GetDlgItem(IDC_SAVE); pWnd—〉ShowWindow(FALSE); pWnd = GetDlgItem(IDC_EXIT); pWnd-〉SetWindowText("关闭"); //让商品名称,编号等列不能编辑 for (int row = m_Grid.GetFixedRowCount(); row < m_Grid。GetRowCount(); row++) { for (int col = m_Grid.GetFixedColumnCount(); col 〈 m_Grid.GetColumnCount(); col++) { m_Grid。SetItemState(row,col,m_Grid.GetItemState(row,col) | GVIS_READONLY); } } CString strSql,str; CBillsManagerApp* pApp = (CBillsManagerApp*)AfxGetApp(); //填充表格外的数据 strSql.Format("SELECT * FROM bill where id = '%s’”,m_strBillID); HRESULT hr = pApp-〉m_pRecordset->Open(strSql。AllocSysString(), pApp->m_pConnection.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText); if(!SUCCEEDED(hr)) { AfxMessageBox("打开bill表出错"); return; } if(pApp-〉m_pRecordset->adoEOF) { AfxMessageBox("错误的单据编号”); pApp—〉m_pRecordset-〉Close(); return; } m_strBillID = (char*)(_bstr_t)pApp->m_pRecordset—〉GetCollect(_variant_t(”id")); str = (char*)(_bstr_t)pApp—>m_pRecordset->GetCollect(_variant_t("time")); GetTimeFromStr(str,m_tTime); m_strClient = (char*)(_bstr_t)pApp—>m_pRecordset—〉GetCollect(_variant_t("client")); m_strAccount = (char*)(_bstr_t)pApp—>m_pRecordset—〉GetCollect(_variant_t("account")); m_strStorage = (char*)(_bstr_t)pApp->m_pRecordset—〉GetCollect(_variant_t("storage")); m_strOperator = (char*)(_bstr_t)pApp—〉m_pRecordset—〉GetCollect(_variant_t("operator”)); m_strComment = (char*)(_bstr_t)pApp-〉m_pRecordset—〉GetCollect(_variant_t(”comment”)); pApp—>m_pRecordset—〉Close(); //填充表格内的数据 strSql.Format("select * from goods where billid = ’%s'”,m_strBillID); hr = pApp-〉m_pRecordset-〉Open(strSql。AllocSysString(), pApp->m_pConnection。GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText); if(!SUCCEEDED(hr)) { AfxMessageBox(”打开goods表出错"); return; } while(!pApp—>m_pRecordset->adoEOF) { //该商品条目在表格中的位置 str = (char*)(_bstr_t)pApp—>m_pRecordset-〉GetCollect(_variant_t(”index")); int nRow = atoi(str.GetBuffer(0)); //商品名称 str = (char*)(_bstr_t)pApp—〉m_pRecordset->GetCollect(_variant_t(”name")); m_Grid.SetItemText(nRow,m_nNameCol,str); //计量单位 str = (char*)(_bstr_t)pApp—>m_pRecordset—>GetCollect(_variant_t(”unit”)); m_Grid.SetItemText(nRow,m_nUnitCol,str); //数量 str = (char*)(_bstr_t)pApp-〉m_pRecordset—>GetCollect(_variant_t(”amount”)); m_Grid。SetItemText(nRow,m_nAmountCol,str); //单价 str = (char*)(_bstr_t)pApp-〉m_pRecordset—>GetCollect(_variant_t("price")); m_Grid。SetItemText(nRow,m_nPriceCol,str); //金额 double fMoney = atoi(m_Grid。GetItemText(nRow,m_nAmountCol)。GetBuffer(0)) * atof(m_Grid。GetItemText(nRow,m_nPriceCol)。GetBuffer(0)); str.Format("%f”,fMoney); m_Grid.SetItemText(nRow,m_nMoneyCol,str); //备注 str = (char*)(_bstr_t)pApp->m_pRecordset->GetCollect(_variant_t(”comment")); m_Grid.SetItemText(nRow,m_nCommentCol,str); pApp—>m_pRecordset->MoveNext(); } pApp->m_pRecordset-〉Close(); //更新对话框的显示 UpdateData(FALSE); } 由于从数据库中获得的“录单日期”是一个字符串,需要将它转换为一个CTime类型的变量,才能将它赋给m_tTime。于是给类CBillDlg增加一个Protected类型的函数GetTimeFromStr,该函数在上面的ShowBill()函数中被调用,它将一个CString类型的变量转换为CTime类型的变量,其实现代码如下: void CBillDlg::GetTimeFromStr(CString strTm, CTime &tm) { int nPos = strTm。Find(”-”); CString strYear = strTm.Left(nPos); CString strRight = strTm.Right(strTm.GetLength()—nPos—1); nPos = strRight.Find(”-"); CString strMonth = strRight。Left(nPos); CString strDay = strRight.Right(strRight。GetLength()—nPos—1); int nYear,nMonth,nDay; nYear = atoi(strYear.GetBuffer(0)); if(nYear 〈 100) nYear += 2000; nMonth = atoi(strMonth。GetBuffer(0)); nDay = atoi(strDay.GetBuffer(0)); tm = CTime(nYear,nMonth,nDay,0,0,0); } (四) 处理表格控件CGridCtrl的GVN_ENDLABELEDIT消息 在单据的商品表格里,有单价、数量和金额等3项,其中金额是根据单价和数量来计算的。所以金额这一项不需要开单人填写,只要把单价和数量填写好后,金额这一项就会自动计算出来并且自动填写.表格控件CGridCtrl定义了GVN_ENDLABELEDIT消息,当完成对一个表格项的输入后,控件会发出这个消息。于是在对话框类CBillDlg中定义了一个处理该消息的响应函数OnGridEndInPlaceEdit(),由于GVN_ENDLABELEDIT属于自定义消息,不能通过ClassWizard完成添加响应函数的任务,完全需要自己手动完成,其步骤如下: (1) 在BillDlg.h中声明OnGridEndInPlaceEdit()函数,其代码如下: afx_msg void OnGridEndInPlaceEdit(NMHDR *pNotifyStruct, LRESULT* pResult); (2)在BillDlg。cpp中完成消息映射,其代码如下: ON_NOTIFY(GVN_ENDLABELEDIT, IDC_GRID, OnGridEndInPlaceEdit) (3) 在BillDlg.cpp中实现函数OnGridEndInPlaceEdit(),其代码如下: void CBillDlg::OnGridEndInPlaceEdit(NMHDR *pNotifyStruct, LRESULT* /*pResult*/) { //如果是查看单据就没有必要处理 if(m_bShowBill) return; //判断位置的有效性 NM_GRIDVIEW* pItem = (NM_GRIDVIEW*) pNotifyStruct; if(pItem->iRow < 0) return; //处理数量或单价列 if(pItem-〉iColumn == m_nAmountCol || pItem->iColumn == m_nPriceCol) { CString strAmount = m_Grid.GetItemText(pItem—〉iRow,m_nAmountCol); CString strPrice = m_Grid.GetItemText(pItem->iRow,m_nPriceCol); int nAmount = 0; double fPrice = 0; if(strAmount != ””) { nAmount = atoi(strAmount.GetBuffer(0)); } if(strPrice != "”) { fPrice = atof(strPrice.GetBuffer(0)); } double fMoney = fPrice * (double)nAmount;//金额 if(fMoney != 0) { CString strMoney; strMoney.Format("%f”,fMoney); m_Grid。SetItemText(pItem-〉iRow,m_nMoneyCol,strMoney); } //检查数量值的合理性,并重新赋值 if(nAmount > 0) { strAmount.Format(”%d",nAmount); m_Grid.SetItemText(pItem-〉iRow,m_nAmountCol,strAmount); } else m_Grid。SetItemText(pItem—>iRow,m_nAmountCol,""); //检查单价值的合理性,并重新赋值 if(fPrice 〉 0) { strPrice.Format(”%f",fPrice); m_Grid.SetItemText(pItem->iRow,m_nPriceCol,strPrice); } else m_Grid。SetItemText(pItem->iRow,m_nPriceCol,”"); m_Grid。Refresh(); } } (五) 保存单据功能 1、保存单据前,判断单据数据的合理性 包括:保证表格外的信息完整,如单据号、客户等一个都不能漏,只有附加说明可以不用填写;保证表格中每一行的数据都必须完整,除
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 行业资料 > 物流/供应链

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服