注册 登录
编程论坛 VFP论坛

[分享]用VFP做一个简单的图书管理程序

东海ECS 发布于 2023-04-29 12:29, 283 次点击
这是一个简单的图书馆管理系统,用 Visual FoxPro 开发而成。它包含了会员管理、图书管理、借阅和归还图书、统计会员借阅情况等功能。欢迎借鉴或质疑

通过这个项目,你可以学习到:

如何在 Visual FoxPro 中使用界面设计器创建界面,以及如何通过代码控制控件的属性和事件。

如何使用表格控件显示和编辑数据,以及如何对表格进行分组、排序、过滤等操作。

如何使用数据库引擎和查询语言实现数据的存储和检索。

如何掌握面向对象编程的基本概念,并应用于实际开发中。

如何设计和实现简单的业务逻辑,例如借阅和归还图书、更新可借阅数等。

如何处理用户输入错误、异常情况和数据安全等问题。

这些是开发任何项目中都需要关注的问题,这是一个简单的示例,帮助你更好地理解和应用这些概念和技术。

程序代码:
* 设置界面字体和日期格式
SET FONT TO "Arial", 9
SET DATE TO DMY

* 定义程序变量和常量
LOCAL lnBookCount, lnMemberCount
LOCAL lnMaxBooksPerMember, lnFinePerDay
CONST lcLibraryName = "图书馆管理系统"

* 定义窗体和控件
DEFINE WINDOW wndMain FROM 0, 0 TO 800, 600 TITLE lcLibraryName

DEFINE LABEL lblTitle PROMPT "图书管理系统" ROW 20 COL 300 FONT "Arial,B" HEIGHT 30

DEFINE TABSHEET tbsBooks FROM 50, 70 TO 750, 570 TITLE "图书"

DEFINE LABEL lblBookId PROMPT "图书编号:" ROW 20 COL 50
DEFINE TEXTBOX txtBookId ROW 20 COL 150 WIDTH 150

DEFINE LABEL lblTitle PROMPT "标题:" ROW 50 COL 50
DEFINE TEXTBOX txtTitle ROW 50 COL 150 WIDTH 200

DEFINE LABEL lblAuthor PROMPT "作者:" ROW 80 COL 50
DEFINE TEXTBOX txtAuthor ROW 80 COL 150 WIDTH 200

DEFINE LABEL lblSubject PROMPT "主题:" ROW 110 COL 50
DEFINE TEXTBOX txtSubject ROW 110 COL 150 WIDTH 200

DEFINE LABEL lblPublisher PROMPT "出版社:" ROW 140 COL 50
DEFINE TEXTBOX txtPublisher ROW 140 COL 150 WIDTH 200

DEFINE LABEL lblPubYear PROMPT "出版年份:" ROW 170 COL 50
DEFINE TEXTBOX txtPubYear ROW 170 COL 150 WIDTH 200

DEFINE LABEL lblIsbn PROMPT "ISBN:" ROW 200 COL 50
DEFINE TEXTBOX txtIsbn ROW 200 COL 150 WIDTH 200

DEFINE BUTTON btnAddBook PROMPT "添加图书" ROW 240 COL 150 WIDTH 100
DEFINE BUTTON btnClearBook PROMPT "清空" ROW 240 COL 280 WIDTH 100

DEFINE GRID grdBooks ROW 280 COL 50 WIDTH 700 HEIGHT 200 HEADERS "图书编号,标题,作者,主题,出版社,出版年份,ISBN" FONT "Arial" ;
UNITS PIXELS COLUMNS 7

DEFINE LABEL lblBookCount PROMPT "总图书数:" ROW 490 COL 50 FONT "Arial,B" HEIGHT 25
DEFINE LABEL lblAvailableCount PROMPT "可借图书数:" ROW 490 COL 280 FONT "Arial,B" HEIGHT 25

DEFINE TABSHEET tbsMembers FROM 50, 130 TO 750, 570 TITLE "会员"

DEFINE LABEL lblMemberId PROMPT "会员编号:" ROW 20 COL 50
DEFINE TEXTBOX txtMemberId ROW 20 COL 150 WIDTH 150

DEFINE LABEL lblName PROMPT "姓名:" ROW 50 COL 50
DEFINE TEXTBOX txtName ROW 50 COL 150 WIDTH 200

DEFINE LABEL lblAddress PROMPT "地址:" ROW 80 COL 50
DEFINE TEXTBOX txtAddress ROW 80 COL 150 WIDTH 200

DEFINE LABEL lblPhone PROMPT "电话:" ROW 110 COL 50
DEFINE TEXTBOX txtPhone ROW 110 COL 150 WIDTH 200

DEFINE BUTTON btnAddMember PROMPT "添加会员" ROW 140 COL 150 WIDTH 100
DEFINE BUTTON btnClearMember PROMPT "清空" ROW 140 COL 280 WIDTH 100

DEFINE GRID grdMembers ROW 180 COL 50 WIDTH 700 HEIGHT 200 HEADERS "会员编号,姓名,地址,电话,借书数" FONT "Arial" ;
UNITS PIXELS COLUMNS 5

DEFINE LABEL lblMemberCount PROMPT "总会员数:" ROW 390 COL 50 FONT "Arial,B" HEIGHT 25

DEFINE TABSHEET tbsLoans FROM 50, 190 TO 750, 570 TITLE "借阅"

DEFINE LABEL lblLoanBookId PROMPT "图书编号:" ROW 20 COL 50
DEFINE TEXTBOX txtLoanBookId ROW 20 COL 150 WIDTH 150

DEFINE LABEL lblLoanMemberId PROMPT "会员编号:" ROW 50 COL 50
DEFINE TEXTBOX txtLoanMemberId ROW 50 COL 150 WIDTH 150

DEFINE LABEL lblLoanDate PROMPT "借出日期:" ROW 80 COL 50
DEFINE TEXTBOX txtLoanDate ROW 80 COL 150 WIDTH 150

DEFINE BUTTON btnIssueLoan PROMPT "借出" ROW 110 COL 150 WIDTH 100
DEFINE BUTTON btnReturnLoan PROMPT "归还" ROW 110 COL 280 WIDTH 100

DEFINE GRID grdLoans ROW 150 COL 50 WIDTH 700 HEIGHT 350 HEADERS "图书编号,会员编号,借出日期,归还日期,罚款金额"


定义程序变量和常量:

程序代码:
* 定义程序变量和常量
lnBookCount = 0
lnMemberCount = 0
lnMaxBooksPerMember = 5
lnFinePerDay = 1


在批量添加图书时,需要使用数组保存图书信息,定义一个名为 laBooks 的二维数组,每行包含图书编号、标题、作者、主题、出版社、出版年份和 ISBN:

* 定义图书数组
DIMENSION laBooks[100, 7]

在批量添加会员时,需要使用数组保存会员信息,定义一个名为 laMembers 的二维数组,每行包含会员编号、姓名、地址、电话和已借书数:

* 定义会员数组
DIMENSION laMembers[100, 5]


为添加图书按钮添加点击事件处理程序,将行输入框中的数据保存到二维数组中,然后更新图书数量和表格:

程序代码:
* 添加图书按钮点击事件处理程序
PROCEDURE AddBook
  IF EMPTY(txtBookId.Value) OR EMPTY(txtTitle.Value) OR EMPTY(txtAuthor.Value) OR EMPTY(txtSubject.Value) OR EMPTY(txtPublisher.Value) OR EMPTY(txtPubYear.Value) OR EMPTY(txtIsbn.Value)
    MESSAGEBOX("请输入完整的图书信息。", 16, lcLibraryName)
    RETURN
  ENDIF
  
  lnBookCount = lnBookCount + 1
  laBooks[lnBookCount, 1] = txtBookId.Value
  laBooks[lnBookCount, 2] = txtTitle.Value
  laBooks[lnBookCount, 3] = txtAuthor.Value
  laBooks[lnBookCount, 4] = txtSubject.Value
  laBooks[lnBookCount, 5] = txtPublisher.Value
  laBooks[lnBookCount, 6] = txtPubYear.Value
  laBooks[lnBookCount, 7] = txtIsbn.Value
  
  CLEAR(txtBookId, txtTitle, txtAuthor, txtSubject, txtPublisher, txtPubYear, txtIsbn)
  txtBookId.SetFocus()
  
  lblBookCount.Caption = "总图书数:" + ALLTRIM(STR(lnBookCount))
  lblAvailableCount.Caption = "可借图书数:" + ALLTRIM(STR(lnBookCount - GetLoanCount()))
  
  UpdateBooksGrid()
ENDPROC


为清空图书按钮添加点击事件处理程序,将行输入框中的数据清空:

程序代码:
* 清空图书按钮点击事件处理程序
PROCEDURE ClearBook
  CLEAR(txtBookId, txtTitle, txtAuthor, txtSubject, txtPublisher, txtPubYear, txtIsbn)
  txtBookId.SetFocus()
ENDPROC


在更新图书表格时,先清空原有的数据,然后使用循环将二维数组中的数据插入到表格中:

程序代码:
* 更新图书表格
PROCEDURE UpdateBooksGrid
  LOCAL i
  grdBooks.Clear()
  FOR i = 1 TO lnBookCount
    grdBooks.AddRow(1)
    grdBooks.Value(grdBooks.RowCount, 1) = laBooks[i, 1]
    grdBooks.Value(grdBooks.RowCount, 2) = laBooks[i, 2]
    grdBooks.Value(grdBooks.RowCount, 3) = laBooks[i, 3]
    grdBooks.Value(grdBooks.RowCount, 4) = laBooks[i, 4]
    grdBooks.Value(grdBooks.RowCount, 5) = laBooks[i, 5]
    grdBooks.Value(grdBooks.RowCount, 6) = laBooks[i, 6]
    grdBooks.Value(grdBooks.RowCount, 7) = laBooks[i, 7]
  ENDFOR
ENDPROC


在更新会员表格时,先清空原有的数据,然后使用循环将二维数组中的数据插入到表格中,注意根据已借书数量判断是否可以再次借阅:

程序代码:
* 更新会员表格
PROCEDURE UpdateMembersGrid
  LOCAL i
  grdMembers.Clear()
  FOR i = 1 TO lnMemberCount
    grdMembers.AddRow(1)
    grdMembers.Value(grdMembers.RowCount, 1) = laMembers[i, 1]
    grdMembers.Value(grdMembers.RowCount, 2) = laMembers[i, 2]
    grdMembers.Value(grdMembers.RowCount, 3) = laMembers[i, 3]
    grdMembers.Value(grdMembers.RowCount, 4) = laMembers[i, 4]
    grdMembers.Value(grdMembers.RowCount, 5) = ALLTRIM(STR(laMembers[i, 5]))


为添加会员按钮添加点击事件处理程序,将行输入框中的数据保存到二维数组中,然后更新会员数量和表格:

程序代码:
* 添加会员按钮点击事件处理程序
PROCEDURE AddMember
  IF EMPTY(txtMemberId.Value) OR EMPTY(txtName.Value) OR EMPTY(txtAddress.Value) OR EMPTY(txtPhone.Value)
    MESSAGEBOX("请输入完整的会员信息。", 16, lcLibraryName)
    RETURN
  ENDIF
  
  lnMemberCount = lnMemberCount + 1
  laMembers[lnMemberCount, 1] = txtMemberId.Value
  laMembers[lnMemberCount, 2] = txtName.Value
  laMembers[lnMemberCount, 3] = txtAddress.Value
  laMembers[lnMemberCount, 4] = txtPhone.Value
  laMembers[lnMemberCount, 5] = 0
  
  CLEAR(txtMemberId, txtName, txtAddress, txtPhone)
  txtMemberId.SetFocus()
  
  lblMemberCount.Caption = "总会员数:" + ALLTRIM(STR(lnMemberCount))
  
  UpdateMembersGrid()
ENDPROC


为清空会员按钮添加点击事件处理程序,将行输入框中的数据清空:

程序代码:
* 清空会员按钮点击事件处理程序
PROCEDURE ClearMember
  CLEAR(txtMemberId, txtName, txtAddress, txtPhone)
  txtMemberId.SetFocus()
ENDPROC


为借阅图书按钮添加点击事件处理程序,根据选择的行和会员编号判断是否可以借阅,如果可以,则在该会员的已借书列表中添加该图书的编号,并更新表格和可借阅数:

程序代码:
* 借阅图书按钮点击事件处理程序
PROCEDURE LoanBook
  LOCAL lnSelectedRow, lcMemberId, lcBookId, lnLoanCount
  lnSelectedRow = grdBooks.SelectedRow()
  IF lnSelectedRow = 0
    MESSAGEBOX("请先选择一本图书。", 16, lcLibraryName)
    RETURN
  ENDIF
  
  lcMemberId = txtLoanMemberId.Value
  lcBookId = grdBooks.Value(lnSelectedRow, 1)
  
  lnLoanCount = GetLoanCount(lcMemberId)
  IF lnLoanCount >= lnMaxBooksPerMember
    MESSAGEBOX("该会员已达到最大借阅量。", 16, lcLibraryName)
    RETURN
  ENDIF
  
  IF LoanBookToMember(lcBookId, lcMemberId)
    MESSAGEBOX("借阅成功。", 64, lcLibraryName)
   
    lblAvailableCount.Caption = "可借图书数:" + ALLTRIM(STR(lnBookCount - GetLoanCount()))
    UpdateBooksGrid()
    UpdateMembersGrid()
  ELSE
    MESSAGEBOX("该图书已被借阅。", 16, lcLibraryName)
  ENDIF
ENDPROC


在判断会员是否已借阅一本特定的图书时,使用 laMembers 数组中的已借书列表进行判断。在添加一本新的已借书时,首先要找到该会员的位置,然后在已借书列表中查找这本图书,如果没有查找到,则将该图书编号添加到列表末尾,并将该会员的已借书数加 1:

程序代码:
* 借一本图书给会员
FUNCTION LoanBookToMember(lcBookId, lcMemberId)
  LOCAL i, j
  
  FOR i = 1 TO lnMemberCount
    IF laMembers[i, 1] = lcMemberId
      FOR j = 1 TO lnMaxBooksPerMember
        IF EMPTY(laMembers[i, 5, j])
          laMembers[i, 5, j] = lcBookId
          laMembers[i, 5] = laMembers[i, 5] + 1
          RETURN .T.
        ENDIF
      ENDFOR
    ENDIF
  ENDFOR
  
  RETURN .F.
ENDFUNC


在获取一个会员已借书数时,查找 laMembers 数组中对应会员的已借书列表,然后返回不为空的数量:

程序代码:
* 获取一个会员已借书数
FUNCTION GetLoanCount(lcMemberId)
  LOCAL i, lnCount
  
  FOR i = 1 TO lnMemberCount
    IF laMembers[i, 1] = lcMemberId
      lnCount = 0
      DO WHILE NOT EMPTY(laMembers[i, 5, lnCount + 1])
        lnCount = lnCount + 1
      ENDDO
      RETURN lnCount
    ENDIF
  ENDFOR


接下来,为归还图书按钮添加点击事件处理程序,根据选择的行、会员编号和图书编号判断是否可以归还,如果可以,则在该会员的已借书列表中删除该图书的编号,并更新表格和可借阅数:

程序代码:
* 归还图书按钮点击事件处理程序
PROCEDURE ReturnBook
  LOCAL lnSelectedRow, lcMemberId, lcBookId, lnLoanCount
  lnSelectedRow = grdLoans.SelectedRow()
  IF lnSelectedRow = 0
    MESSAGEBOX("请先选择一条借阅记录。", 16, lcLibraryName)
    RETURN
  ENDIF
  
  lcMemberId = txtReturnMemberId.Value
  lcBookId = grdLoans.Value(lnSelectedRow, 2)
  
  IF ReturnBookFromMember(lcBookId, lcMemberId)
    MESSAGEBOX("归还成功。", 64, lcLibraryName)
   
    lblAvailableCount.Caption = "可借图书数:" + ALLTRIM(STR(lnBookCount - GetLoanCount()))
    UpdateBooksGrid()
    UpdateMembersGrid()
  ELSE
    MESSAGEBOX("该图书已被归还。", 16, lcLibraryName)
  ENDIF
ENDPROC

在查找会员的已借书列表并删除一个图书时,首先要找到该会员的位置,然后在已借书列表中查找这本图书,如果找到了,则将该图书删除,并将该会员的已借书数减 1:

程序代码:
* 从会员那里归还一本图书
FUNCTION ReturnBookFromMember(lcBookId, lcMemberId)
  LOCAL i, j
  
  FOR i = 1 TO lnMemberCount
    IF laMembers[i, 1] = lcMemberId
      FOR j = 1 TO lnMaxBooksPerMember
        IF laMembers[i, 5, j] = lcBookId
          laMembers[i, 5, j] = ""
          laMembers[i, 5] = laMembers[i, 5] - 1
          RETURN .T.
        ENDIF
      ENDFOR
    ENDIF
  ENDFOR
  
  RETURN .F.
ENDFUNC


最后,为统计按钮添加点击事件处理程序,统计所有会员的借阅情况,并将统计结果输出到消息框中:

程序代码:
* 统计按钮点击事件处理程序
PROCEDURE ShowStatistics
  LOCAL i, j, lcOutput
  
  lcOutput = "会员编号,姓名,已借书数\n"
  
  FOR i = 1 TO lnMemberCount
    IF laMembers[i, 5] > 0
      lcOutput = lcOutput + ALLTRIM(laMembers[i, 1]) + "," + ALLTRIM(laMembers[i, 2]) + "," + ALLTRIM(STR(laMembers[i, 5])) + "\n"
    ENDIF
  ENDFOR
  
  MESSAGEBOX(lcOutput, 64, lcLibraryName)
ENDPROC


至此,我们完成了图书馆管理系统的开发。

[此贴子已经被作者于2023-4-29 12:31编辑过]

5 回复
#2
sdta2023-04-29 13:48
SET FONT TO "Arial", 9
这是什么版本的VFP命令
#3
csyx2023-04-29 14:33
人工智能强大之处!根据已有的 vfp SET 命令格式杜撰一条 vfp 命令
#4
sam_jiang2023-04-30 09:45
鍟ユ儏鍐碉紵
#5
星光闪闪5132023-05-05 23:03
啥东西啊看不到啊
#6
星光闪闪5132023-05-05 23:04
楼主再分享一下
1