實現這個“簡單”的管理系統其實不是那麼簡單!
其中總結我所遇到的幾個大問題:
其一:對於一個界面型的管理系統,用我所熟悉的MFC實現,也不斷的碰見控件操作和數據交換問題;
其二:數據庫操作,對於MFC的CRecordset類來說,還是需要研究一下才能加入這個系統的使用中來的;
其三:生成項目報表,這就需要利用MFC來操作word,用MFC提供的庫文件來形成word文檔的報表;
下面就來一 一介紹我克服這幾個問題的過程吧!
第一個,控件操作與數據交換!
首先給大家看一下該系統所涉及的幾個界面:
登陸界面
經營部管理主界面
綜合部、生產部、總工辦管理主界面類似
用戶信息更改界面
項目信息查詢界面
用戶信息註冊界面
該系統流程大致是:經營部接到項目,填寫項目信息和項目安排,交由下一級總工辦;總工辦登陸顯示該項目信息,填寫項目安排後交由下一級生產部;生產部登陸顯示該項目信息,填寫項目安排後交由下一級綜合部;綜合部登陸顯示該項目信息,填寫項目安排後提交下一級返回經營部,此項目完成整個流程。經營部再次登陸,可填寫新項目信息和安排。每個部門都可以查看之前所有項目的信息。
之前說的關於控件的操作問題主要就是由於經營部、綜合部、生產部、總工辦的管理界面相似度很大,我不想做四個Dialog,所以就想着這四個部門共用一個對話框。還有就是不同的用戶登陸,所屬部門不同,對這個界面的操作權限就不同,如上圖所示,還有經營部可以編輯項目信息和安排,而其他3個部門的用戶就只能編輯安排那一部分,而已經發送下一級的項目,都變爲不可編輯狀態。我在資源里加入一個綜合部樣式的對話框,想到控件有可以隱藏和禁用的操作,所以這個控件的問題應該不算太難……
但是這個所謂的不太難,難度還不太小。
我用管理界面的對話框類ManagementMain 生成對話框: ManagementMain dlg; dlg.DoModal();
這樣的結果就是,我設計的對話框是怎樣,它出來就是怎樣……那要在哪裏判斷用戶後做不同的顯示呢? 那我就給ManagementMain 添加一個成員變量,int m_flg; 然後再在構造函數裏給它初始化m_flg=0; 如果是經營部登陸,那麼ManagementMain dlg; dlg.m_flg=1;//隱藏部分控件 dlg.DoModal(); 然後在構造函數裏判斷做不同的顯示:
if(m_flg==1)//爲經營部登陸,則隱藏歸檔要求那兩個控件,否則禁用項目信息的控件
{
m_CtrFileRequire.ShowWindow(false);
m_CtrFilingRequire.ShowWindow(false);
}
else
{
GetDlgItem(IDC_ProjectNum)->EnableWindow(FALSE);
GetDlgItem(IDC_ProjectName)->EnableWindow(FALSE);
GetDlgItem(IDC_ProjectAddr)->EnableWindow(FALSE);
GetDlgItem(IDC_ClientAddr)->EnableWindow(FALSE);
GetDlgItem(IDC_ClientPerson)->EnableWindow(FALSE);
GetDlgItem(IDC_ClientPhone)->EnableWindow(FALSE);
GetDlgItem(IDC_ClientRequire)->EnableWindow(FALSE);
}
這裏保存後編譯鏈接沒問題,運行執行文件登陸過後,就出現下圖的運行錯誤:
多次百度查找錯誤的原因,也沒有弄明白個究竟,只知道不能在構造函數裏對對話框控件進行操作,要初始化對話框的佈局,需要在virtual void DoDataExchange(CDataExchange* pDX);這個函數裏進行改變。而且放在構造函數裏的判斷m_flg始終未0,這是由於構造函數先於 dlg.m_flg=1;//隱藏部分控件 這一句執行,構造裏初始化爲0,所以構造裏判斷過後m_flg纔會被賦值爲1。
那麼將上面改變控件的代碼Ctrl+X,Ctrl+V到 DoDataExchange()函數中,編譯鏈接後運行登陸果然可以實現同一個對話框佈局的不同顯示了!
控件操作的問題解決了,還有一個就是數據交換了。
比如在經營部登陸後,對話框一出來,就顯示該用戶信息,項目信息的編號處顯示一個新生成的項目編號;綜合部、生產部、總工辦登陸後,對話框上就顯示用戶信息,顯示上一級發過來的項目信息。
這個問題應該可以不用再對話框上再加一個按鈕,點擊按鈕過後才更新各對話框的信息,應該有另外的方法……我百度查了一下對話框的初始化相關的消息,也翻看以前一些寫了界面的程序,偶然發現平時忽略的生成對話框的步驟 ManagementMain dlg; dlg.DoModal(); 太簡單了,百度有在這兩句話之間對類成員變量賦值的例子,效果就是DoModal()對話框可以初始顯示控件內容。於是乎,經營部DoModal()之前加上 dlg.m_projectnum=buf;爲項目編號的顯示內容,用戶信息的成員變量依次賦值;另外3個部門DoModal()之前爲用戶信息、項目信息的成員變量賦值。
至此,第一個大問題控件操作和數據交換得以解決!
第二個大問題,MFC的CRecordset類對數據庫的操作問題。
之前照着課本寫了一個簡單的QQ聊天系統,其中有涉及到數據庫的操作,記得是重寫了一個數據庫類,代碼還不少,當然是針對那個系統專寫的數據庫操作。我也沒時間再去看那裏的代碼,找出可用於這個管理系統的數據庫操作,再自己重寫了,所以我就百度搜索可以直接操作數據庫的類的使用。 找到MFC的CDataBase類和CRecordset類結合使用可以直接對數據庫進行讀寫操作。
在對數據庫進行讀寫操作之前,需要先動態註冊數據源,即告訴應用程序所需要的數據庫文件和對應的數據庫驅動:
SQLConfigDataSource(NULL, ODBC_ADD_DSN,
"Microsoft Access Driver (*.mdb)",//Access數據庫的驅動驅動程序,其他數據庫可在電腦的數據源(ODBC)裏查看哪些可用
"DSN=projectinfo\0" "DBQ=dbf\\projectinfo.mdb\0" "DEFAULTDIR=dbf\0"); //註冊本地數據庫數據源,projectinfo爲數據庫文件名稱
CoInitialize(NULL);
其中 SQLConfigDataSource()爲註冊數據源,具體參數可百度瞭解,CoInitialize(NULL)爲初始化com庫。這兩句可以放在需要使用數據庫的類的構造函數裏。先編譯鏈接運行一下,使其在用戶DSN註冊一個數據庫文件。
數據源註冊完過後,需要自定義一個數據庫記錄集的類,使該類與需要讀寫的數據庫關聯。在類嚮導裏添加一個新類,類名定義爲MyProjectSet,選擇基類時選擇CRecordset,點擊OK後彈出對話框選擇數據源,完成後就會建成一個與數據庫文件相關聯的類MyProjectSet:
long m_ID;
CString m_projectnum;
CString m_projectname;
CString m_projectaddr;
CString m_clientaddr;
CString m_clientperson;
CString m_clientphone;
CString m_clientrequire;
……………
RFX_Long(pFX, _T("[ID]"), m_ID);
RFX_Text(pFX, _T("[projectnum]"), m_projectnum);
RFX_Text(pFX, _T("[projectname]"), m_projectname);
RFX_Text(pFX, _T("[projectaddr]"), m_projectaddr);
RFX_Text(pFX, _T("[clientaddr]"), m_clientaddr);
RFX_Text(pFX, _T("[clientperson]"), m_clientperson);
RFX_Text(pFX, _T("[clientphone]"), m_clientphone);
RFX_Text(pFX, _T("[clientrequire]"), m_clientrequire);
…………
接下來,我們就可以通過MyProjectSet類來對數據庫進行讀寫操作了。我在這個管理系統中,就只用到數據庫的查詢、修改、添加3個操作。
數據庫的查詢操作如下:
CDatabase m_db;
MyProjectSet myset(&m_db);
CString strSQL1="select * from projectinfo where projectnum= '00001' ";
if(!myset.Open(CRecordset::dynaset,strSQL1))
return;
如果沒有打開失敗返回,則myset裏存放的就是數據文件中projectnum爲00001的所有記錄。可以做如下判斷:
if(myset.GetRecordCount()!=0)
{//有projectnum爲00001的記錄,定義操作
…………}
數據庫的修改操作如下:
//更新項目信息
myset.Edit();
myset.m_projectname=m_projectname;//需要修改的數據項
…………
myset.Update();
myset.Requery();
myset.Close();
數據庫添加操作如下:
//項目信息加入數據庫信息表
myset.AddNew();
myset.SetFieldNull(NULL);
myset.m_projectnum=m_projectnum;//需要添加的數據項
…………
myset.Update();
myset.Requery();
myset.Close();
至此,第二個大問題數據庫的操作也可以得到解決。
最後一個大問題就是MFC操作word生成報表。
在這之前,我所接觸的MFC操作文檔就只限於讀寫txt文件,而要讀寫word並生成表格樣式的doc文檔,就不是那麼簡單了。百度MFC讀寫word,發現網上也沒有說得非常明白的應用文檔,最終讓我找到一篇比較好的應用說明文檔http://wenku.baidu.com/view/e62b610c52d380eb62946d5a.html,其中說到在word中創建一個表格,然後爲單元格賦值,還有合併單元格等操作的使用。當然,這篇文檔裏沒有說得那麼完整,需要先使用MFC提供的wor庫文件添加幾個操作類。具體方法爲:
按下快捷鍵Ctrl+W,彈出MFC ClassWizard對話框,單擊Add Class…,選擇From a type library…,彈出Import from Type Library對話框,找到你OFFICE軟件的安裝文件夾(默認是在C盤的Program Files中),在其中找到MSWORD.OLB,單擊打開。在Confirm Classes中按下Ctrl鍵選中_Application,Documents,_Document,Cell,Cells,Paragraph,Paragraphs,Shading,Table,Tables,InlineShapes和Selection,單擊OK。之後會發現類視圖下多了之前添加的那幾個文檔操作類,在需要生成word表格的Cpp文件頭部添加幾個頭文件:
#include "MyProjectSet.h"
#include "msword.h"
#include <atlbase.h>
然後就可以創建生成word的表格了:
COleVariant bTRUE((short)TRUE);
COleVariant bFALSE((short)FALSE);
COleVariant OPTION((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
_Application WordApp;
if(!WordApp.CreateDispatch("Word.Application",NULL))
{
AfxMessageBox("CreateDispatch falied.",MB_OK|MB_SETFOREGROUND);
return;
}
Documents Docs;
_Document Doc;
Docs=WordApp.GetDocuments();
Doc=Docs.Add(OPTION,OPTION,OPTION,OPTION);
Selection Select;
Select=WordApp.GetSelection();
_Document ActiveDoc;
ActiveDoc=WordApp.GetActiveDocument();
Tables tables=ActiveDoc.GetTables();
CComVariant defaultBehavior(1);
CComVariant AutoFitBehavior(1);
tables.Add(Select.GetRange(),16,6,&defaultBehavior,&AutoFitBehavior);//添加一個7行11列的空表格
Table table=tables.Item(1);
Cell c,c1;
Cells cs;
//以上就是創建一個表格,並定義單元格對象
c=table.Cell(1,1);
c1=table.Cell(1,6);
c.Merge(c1);//合併(1,1)到(1,6)的單元格
c.Select();
cs=Select.GetCells();
cs.SetVerticalAlignment(1);
Select.TypeText("項目信息");
//這是將第一行前6個單元格合併,並設置該合併後的單元格顯示字符"項目信息"
c=table.Cell(i,j);
c.Select();
cs=Select.GetCells();
cs.SetVerticalAlignment(1);
Select.TypeText("字符");
//這裏是選定第i行第j列的單元格,並設置字符"字符"
Select.ReleaseDispatch();
c.ReleaseDispatch();//釋放文檔操作類的對象
ActiveDoc.SaveAs(COleVariant(filename),COleVariant((short)0),
bFALSE,COleVariant(""),bTRUE,COleVariant(""),
bFALSE,bFALSE,bFALSE,bFALSE,bFALSE,bFALSE,bFALSE,bFALSE,bFALSE,bFALSE);
//保存該word文檔
WordApp.Quit(OPTION,OPTION,OPTION);
以上就是對於最後一個大問題的解決方法。
至此,我的一個“簡單”的工程項目管理系統的實踐的過程說明就完成了,至於心得體會以及收穫,那就只有重複研究該系統,精益求精,才能將這個“簡單”的系統變爲一份不簡單的編程財富!