Visual Basic 6.0 (VB6) 程式語言案例學習 (06. 中藥店管理系統)
Visual Basic 6.0 (VB6) 程式語言案例學習 (06. 中藥店管理系統)¶
6.1 問題¶
這是一家歷史悠久的中藥店,由於新一代接手,想採用電腦化管理,因此提出需求。我們有許多老顧客,常常跟我們訂藥,由於有些是長期的藥單,我們希望能夠很簡單的調出顧客資料和配藥的藥單,不要很麻煩去設定一堆東西,只要越簡單越好,中藥材有很多,要可以新增、刪除、修改藥材或者是藥單,藥材分類最好是用看的懂的方式來做,可以由筆劃或者是注音來選擇。顧客的資料都要能夠留下來,可以以後查詢。配藥的藥方要顯示適應症,可供參考。未來可能要做網路版本,讓分店也可以下載到最新藥單或顧客資料。
6.2 需求¶
表格 6‑1 「中藥店管理系統」系統目的分析表
| 版本:1.0 | 要做什麼 | 不要做什麼(不要做不代表不會做) |
|---|---|---|
| 能做什麼 | (第一格:必要項目) | (第二格:次要項目) |
| 顧客資料管理要能很簡單的新增、刪除、修改、查詢。 | 保留網路版的功能,預留藥單或顧客資料下載更新。 | |
| 顧客的購買紀錄必須要能保留下來,方便以後查詢。 | 自動分析藥材的注音順序,藥材自動分類。 | |
| 藥材以注音的方式分類,要能夠新增、刪除、修改。 | 自動分析藥單的筆劃順序,藥單自動分類。 | |
| 藥單要能夠記錄所有的藥材,也要能夠新增、刪除、修改。 | 統計週、月、半年、年報表。 | |
| 藥單以筆劃的方式做分類。 | ||
| 購買清單要可以列印給客戶。 | ||
| 不能做什麼(不能做代表不需要做) | (第三格:不必要項目) | (第四格:不需要項目) |
| 建立多國語系的程式。 | 以資料探勘預測顧客購買需求。 | |
| 統計顧客購買藥材數量,以匯總成報表。 |
表格 6‑2 「中藥店管理系統」系統目標分析表
| 版本: | 重要 | 不重要 |
|---|---|---|
| 優先 | (重) | (急) |
| 顧客資料管理要能很簡單的新增、刪除、修改、查詢。 | 藥材以注音的方式分類,要能夠新增、刪除、修改。 | |
| 顧客的購買紀錄必須要能保留下來,方便以後查詢。 | 藥單要能夠記錄所有的藥材,也要能夠新增、刪除、修改。 | |
| 藥單以筆劃的方式做分類。 | ||
| 不急迫 | (輕) | (緩) |
| 購買清單要可以列印給客戶。 | 建立多國語系的程式。 | |
| 保留網路版的功能,預留藥單或顧客資料下載更新。 |
表格 6‑3 「中藥店管理系統」系統規格表
| 規格項目 | 規格內容 | 備註 |
|---|---|---|
| 藥名分類 | 以注音分類方式,可以新增、刪除、修改。 | … |
| 以拖曳的方式加入藥單。 | ||
| 方劑分類 | 以筆劃分類方式,可以新增、刪除、修改。 | … |
| 以拖曳的方式加入藥單。 | ||
| 點選方劑可以帶出適應症資料。 | ||
| 顧客資料 | 可以帶出顧客基本資料。 | … |
| 可以新增、刪除、修改顧客資料。 | ||
| 顧客清單 | 可以新增、刪除、修改顧客清單。 | … |
| 可以用電話、地址、姓名查詢。 | ||
| 當點選顧客清單項目時,可以關聯到顧客資料、購買紀錄、購買清單。 | ||
| 購買紀錄 | 可以依照顧客項目搜尋購買紀錄。 | … |
| 可以依照日期區間搜尋購買紀錄。 | ||
| 可以輸入備註內容。 | ||
| 購買清單 | 藥單可以新增、修改、刪除、列印。 | … |
| 並且能夠接受藥名和方劑拖曳過來的項目。 | ||
| 線上更新 | 預留線上更新按鈕。 | … |
| 多國語言 | 預留多國語言載入功能。 | … |
6.3 特色¶
以樹狀目錄管理藥材,並且可以自訂獨家藥方,透過拖曳的方式,替客戶打包藥材,並且有客戶管理及訂單管理。介面會隨著視窗大小自動調整,也就是說可以隨時調整視窗大小,而視窗內的控制項也會依照比例去做縮放的動作。
6.4 使用工具¶
| 語言 | 軟體 |
|---|---|
| MS Visual Basic 6.0 | MS Visual Basic 6.0、MS Access |
6.5 系統架構¶
筆者在分析的時候,就在思考一個問題,要如何將操作變得簡單易懂呢?最後採取的方式就是拖曳,這個由來已久的操作模式,是廣大使用者最熟悉的方式,因此筆者將想法融入藥材管理程式中。無論是藥材或者是方劑,我們都必須讓使用者能夠以拖曳的方式,加項目加入藥單中,這是最熟悉的操作模式。因為在Windows的檔案總管管理檔案的方式,幾乎是使用拖曳來完成的。其他資料庫管理的部分,就只是基本的資料庫管理工作而已,並不太難。
6.6 程式實作¶
Step 1:如圖 6-1 所示,我們在左邊安排藥名樹狀清單,而右邊安排方劑樹狀清單,中間則是顧客資料項目,一開始我們以英文命名,這是為了製作多國語系而設計的,也許將來可能有簡體中文版或是其他語文版本。而最底下則是顯示適應症的文字框。
圖 6‑1
Step 2:請參考以下程式碼,由於程式碼很多,因此只列出重點部分,以及副程式或函式的功用說明。原始程式碼放置在教材檔案中,請讀者參考。
'要求變數宣告才能使用 Option Explicit '記錄表單的寬度 Public frmMM_PrevResizeX As Long '記錄表單的高度 Public frmMM_PrevResizeY As Long '客戶資料模式 Public strCICD_Mode As String '採購清單模式 Public strCISL_Mode As String '採購紀錄模式 Public strCIBH_Mode As String '藥名模式 Public strItem_Mode As String '方劑模式 Public strClass_Mode As String '程式初始 Private Sub Form_Initialize() ‘... End Sub
'視窗起始載入
Private Sub Form_Load()
'設定日期範圍
dtpBH_SD.Value = Date
dtpBH_ED.Value = Date
'載入藥名框顯示模式
Call load_fraItem_Mode("")
'載入藥名下拉式選單
Call load_cboItem_Class
'載入方劑框顯示模式
Call load_fraClass_Mode("")
'載入方劑下拉式選單
Call load_cboClass_Class
'載入語言
Call load_Language(strDefineLanguage)
'載入客戶
Call load_lvwCAB
'載入預設客戶的個人資料
Call load_CD
'載入預設客戶的採購紀錄
Call load_BH
'載入預設客戶的採購清單
Call load_SL
'載入客戶詳細資料框,設定樣式
Call load_fraCICD("")
'設定頁籤簽換至採購清單
tspCI.Tabs(4).Selected = True
Me.Show
'載入藥名
Call load_fraItem
'載入方名
Call load_fraClass
'呼叫調整大小函式
frmMM_ResizeAll frmMM
Me.Show
End Sub
'釋放程式事件副程式
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
End
End Sub
‘結束程式事件副程式
Private Sub Form_Terminate()
End
End Sub
'視窗大小更動時
Private Sub Form_Resize()
'當表單最小化時不處理
If frmMM.WindowState = 1 Then
Exit Sub
End If
'限制了表單的最小高度及寬度
If frmMM.Width < 12120 Then
frmMM.Width = 12120
End If
If frmMM.Height < 9405 Then
frmMM.Height = 9405
End If
'呼叫調整大小函式
frmMM_ResizeAll frmMM
End Sub
'調整視窗大小
Public Function frmMM_ResizeAll(tmpForm As Form)
'錯誤處理
'當控制項無法改變大小或長寬時,就略過不處理
On Error Resume Next
'宣告區
Dim tmpControl As Control
'紀錄表單原來大小
If frmMM_PrevResizeX = 0 Then
'如果 frmMM_PrevResizeX = 0 表示第一次執行這個 Function
'就先給定 frmMM_PrevResizeX 及 frmMM_PrevResizeY 的初值,
'記錄表單原來的大小,然後結束這個 Function
frmMM_PrevResizeX = tmpForm.ScaleWidth
frmMM_PrevResizeY = tmpForm.ScaleHeight
Exit Function
End If
'設定表單修改大小
For Each tmpControl In tmpForm
'逐一處理這個表單中的所有控制項
If TypeOf tmpControl Is Line Then
'檢查控制項的物件類別, 如果是 Line , 就改變 X1, X2, Y1, Y2 的值
tmpControl.X1 = tmpControl.X1 / frmMM_PrevResizeX * tmpForm.ScaleWidth
tmpControl.X2 = tmpControl.X2 / frmMM_PrevResizeX * tmpForm.ScaleWidth
tmpControl.Y1 = tmpControl.Y1 / frmMM_PrevResizeY * tmpForm.ScaleHeight
tmpControl.Y2 = tmpControl.Y2 / frmMM_PrevResizeY * tmpForm.ScaleHeight
'上面這四行會自動根據控制項和表單的相對比例
'自動調整控制項的位置及大小
ElseIf TypeOf tmpControl Is ComboBox Then
'如果是其他的物件類別, 則改變控制項的 left, top, Width, and height
tmpControl.Left = tmpControl.Left / frmMM_PrevResizeX * tmpForm.ScaleWidth
tmpControl.Top = tmpControl.Top / frmMM_PrevResizeY * tmpForm.ScaleHeight
tmpControl.Width = tmpControl.Width / frmMM_PrevResizeX * tmpForm.ScaleWidth
tmpControl.Height = tmpControl.Height / frmMM_PrevResizeY * tmpForm.ScaleHeight
Else
tmpControl.Move (tmpControl.Left / frmMM_PrevResizeX * tmpForm.ScaleWidth), _
(tmpControl.Top / frmMM_PrevResizeY * tmpForm.ScaleHeight), _
(tmpControl.Width / frmMM_PrevResizeX * tmpForm.ScaleWidth), _
(tmpControl.Height / frmMM_PrevResizeY * tmpForm.ScaleHeight)
'上面這四行會自動根據控制項和表單的相對比例
'自動調整控制項的位置及大小
End If
Next tmpControl
'紀錄修改後大小
'重新給定 frmMM_PrevResizeX 及 frmMM_PrevResizeY 的值
frmMM_PrevResizeX = tmpForm.ScaleWidth
frmMM_PrevResizeY = tmpForm.ScaleHeight
End Function
'載入顯示語系 Private Sub load_Language(Optional strSS As String) ‘... End Sub '載入藥名 Private Sub load_fraItem() ‘... End Sub '載入方名 Private Sub load_fraClass() ‘... End Sub '點選採購紀錄 Private Sub lvwBH_ItemClick(ByVal Item As MSComctlLib.ListItem) '載入預設客戶的採購清單 Call load_SL '載入備註 txtBH_Note.Text = Trim(Item.SubItems(1) & "") End Sub '點選客戶 Private Sub lvwCAB_ItemClick(ByVal Item As MSComctlLib.ListItem) '載入預設客戶的個人資料 Call load_CD '載入預設客戶的採購紀錄 Call load_BH '載入預設客戶的採購清單 Call load_SL End Sub '刪除採購單上的項目 Private Sub lvwSL_KeyDown(KeyCode As Integer, Shift As Integer) ‘... End Sub '設定採購單上項目的數量 Private Sub lvwSL_KeyPress(KeyAscii As Integer) ‘... End Sub '工具按鈕 Private Sub tbrMM_ButtonClick(ByVal Button As MSComctlLib.Button) ‘... End Sub '工具按鈕 Private Sub tbrMM_ButtonMenuClick(ByVal ButtonMenu As MSComctlLib.ButtonMenu) ‘... End Sub '切換頁籤 Private Sub tspCI_Click() ‘... End Sub ' 載入客戶資料 Private Sub load_lvwCAB() ‘... End Sub '點選方劑帶出適應症 Private Sub tvwClass_NodeClick(ByVal Node As MSComctlLib.Node) ‘... End Sub '禁止地址輸入 Private Sub txtCAddr_KeyDown(KeyCode As Integer, Shift As Integer) KeyCode = 0 End Sub '禁止地址輸入 Private Sub txtCAddr_KeyPress(KeyAscii As Integer) KeyAscii = 0 End Sub '客戶資料操作模式 Private Sub load_fraCICD(strMode As String) ‘... End Sub '按下新增客戶 Private Sub cmdCD_Add_Click() ‘... End Sub '按下修改客戶 Private Sub cmdCD_Edit_Click() ‘... End Sub '按下刪除客戶 Private Sub cmdCD_Delete_Click() ‘... End Sub '在客戶模式按下確定 Private Sub cmdCD_Yes_Click() ‘... End Sub '在客戶模式按下取消 Private Sub cmdCD_No_Click() ‘... End Sub '新增客戶 Private Function fCICD_Add() As String ‘... End Function '修改客戶 Private Function fCICD_Edit() As String ‘... End Function '刪除客戶 Private Function fCICD_Delete() As String ‘... End Function '點選藥名樹狀目錄中的藥名 Private Sub tvwItem_NodeClick(ByVal Node As MSComctlLib.Node) ‘... End Sub '由藥名樹狀目錄中拖曳至採購清單 Private Sub tvwItem_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long) Data.SetData tvwItem.SelectedItem.Key, 1 End Sub '由方劑樹狀目錄中拖曳至採購清單 Private Sub tvwClass_OLEStartDrag(Data As MSComctlLib.DataObject, AllowedEffects As Long) Data.SetData tvwClass.SelectedItem.Key, 1 End Sub '採購單載入拖曳的藥名 Private Sub lvwSL_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single) ‘... End Sub '採購資料操作模式 Private Sub load_fraCISL(strMode As String) ‘... End Sub '按下新增採購 Private Sub cmdSL_Add_Click() strCISL_Mode = "add" Call load_fraCISL(strCISL_Mode) End Sub '按下修改採購 Private Sub cmdSL_Edit_Click() strCISL_Mode = "edit" Call load_fraCISL(strCISL_Mode) End Sub '按下刪除採購 Private Sub cmdSL_Delete_Click() strCISL_Mode = "delete" Call load_fraCISL(strCISL_Mode) End Sub '按下列印採購 Private Sub cmdSL_Print_Click() frmPM.Show 1 End Sub '在採購模式按下確定 Private Sub cmdSL_Yes_Click() ‘... End Sub '在採購模式按下取消 Private Sub cmdSL_No_Click() ‘... End Sub '新增採購 Private Function fCISL_Add() As String ‘... End Function '修改採購 Private Function fCISL_Edit() As String ‘... End Function '刪除採購 Private Function fCISL_Delete() As String ‘... End Function '禁止適應症文字框輸入 Private Sub txtSD_KeyDown(KeyCode As Integer, Shift As Integer) KeyCode = 0 End Sub '禁止適應症文字框輸入 Private Sub txtSD_KeyPress(KeyAscii As Integer) KeyAscii = 0 End Sub '採購單備忘 Private Sub txtBH_Note_KeyPress(KeyAscii As Integer) ‘... End Sub '載入藥名類別 Public Sub load_cboItem_Class() ‘... End Sub '載入方劑類別 Public Sub load_cboClass_Class() ‘... End Sub '載入預設客戶的個人資料 Public Sub load_CD() ‘... End Sub '載入預設客戶的採購紀錄 Public Sub load_BH() ‘... End Sub '載入預設客戶的採購清單 Public Sub load_SL() ‘... End Sub '當啟始日期被改變 Private Sub dtpBH_SD_Change() '載入預設客戶的採購紀錄 Call load_BH '載入預設客戶的採購清單 Call load_SL End Sub '當結束日期被改變 Private Sub dtpBH_ED_Change() '載入預設客戶的採購紀錄 Call load_BH '載入預設客戶的採購清單 Call load_SL End Sub '查詢客戶資料 Private Sub cmdFind_Click() ‘... End Sub '查詢文字框 Private Sub txtCAB_KeyPress(KeyAscii As Integer) ‘... End Sub '購買紀錄依照客戶過濾 Private Sub chkBH_Custom_Click() '載入依照過濾的採購紀錄 Call load_BH End Sub '採購紀錄操作模式 Private Sub load_fraCIBH(strMode As String) ‘... End Sub '按下編輯備註 Private Sub cmdBH_EditNote_Click() ‘... End Sub '在採購紀錄按下確定 Private Sub cmdBH_Yes_Click() ‘... End Sub '在採購紀錄按下取消 Private Sub cmdBH_No_Click() ‘... End Sub '編輯備註 Private Function fCIBH_EditNote() As String ‘... End Function '設定藥名框顯示模式 Sub load_fraItem_Mode(strMode As String) ‘... End Sub '按下藥名框新增按鈕 Private Sub cmdItem_Add_Click() ‘... End Sub '按下藥名框修改按鈕 Private Sub cmdItem_Edit_Click() ‘... End Sub '按下藥名框刪除按鈕 Private Sub cmdItem_Delete_Click() ‘... End Sub '按下藥名框確定按鈕 Private Sub cmdItem_Yes_Click() ‘... End Sub '按下藥名框取消按鈕 Private Sub cmdItem_No_Click() ‘... End Sub '新增藥名 Private Function fcmdItem_add() As String ‘... End Function '修改藥名 Private Function fcmdItem_edit() As String ‘... End Function '刪除藥名 Private Function fcmdItem_delete() As String ‘... End Function '設定藥名類別索引 Private Sub cboItem_Class_Click() ‘... End Sub '設定藥名類別索引 Private Sub cboItem_Class_KeyPress(KeyAscii As Integer) ‘... End Sub '設定方劑框顯示模式 Sub load_fraClass_Mode(strMode As String) ‘... End Sub '按下方劑框新增按鈕 Private Sub cmdClass_Add_Click() ‘... End Sub '按下方劑框修改按鈕 Private Sub cmdClass_Edit_Click() ‘... End Sub '按下方劑框刪除按鈕 Private Sub cmdClass_Delete_Click() ‘... End Sub '按下方劑框確定按鈕 Private Sub cmdClass_Yes_Click() ‘... End Sub '按下方劑框取消按鈕 Private Sub cmdClass_No_Click() ‘... End Sub '新增方劑 Private Function fcmdClass_add() As String ‘... End Function '修改方劑 Private Function fcmdClass_edit() As String ‘... End Function '刪除方劑 Private Function fcmdClass_delete() As String ‘... End Function '設定方劑類別索引 Private Sub cboClass_Class_KeyPress(KeyAscii As Integer) ‘... End Sub '將藥名樹狀目錄中的藥名移入方劑藥名清單中 Private Sub lvwClass_List_OLEDragDrop(Data As MSComctlLib.DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single) ‘... End Sub '刪除方劑藥名清單上的項目 Private Sub lvwClass_List_KeyDown(KeyCode As Integer, Shift As Integer) ‘... End Sub
Step 3:請看程式執行結果,如圖 6-2。
圖 6‑2 中藥店管理程式執行結果
6.7 修改重點¶
由於線上更新的部分,必須牽涉到虛擬主機空間,這對於讀者來說太不方便了,因此筆者把這一段拿掉了。若讀者想要修改為網路版本,就要先有網路空間,筆者不認為使用點對點(P2P)的方式比較好,因為你必須先以電話連絡,兩台電腦要開機進入程式,這才能運作。而透過24小時運作的網路空間,就不會有這樣的問題,將更新過後的檔案,上傳到虛擬主機上,供其他分店的程式下載,解壓縮更新資料庫。這樣會是比較好的做法。
除此之外,報表的部分因為客戶需求不大,因此只有單純的列印藥單而已,若讀者有需求分析報表,修改這個部分,增加報表功能,會使得這系統更加完整。
最後,使用資料探勘的方式,就可以預測顧客的需求,而這個演算法已經是非常普及的,能夠預測顧客需求,將有助於備料、庫存、CRM管理,而系統也進入更高一層次。
6.8 結論¶
這個案主的需求非常的簡單,只是資料庫管理的功能,筆者認為最主要的關鍵就是在於介面設計,一個符合使用者需求的介面,才是本程式成功的關鍵,有時候分析系統的時候,必須要能夠從不同的角度做切入,是著變換你所扮演的角色,以便找出接近使用著需求的項目,再以系統分析的角色來進行分析,這樣將有助於拉近需求與系統的距離。
Lai Tai-Yu (賴岱佑)