Visual Basic .Net (VB.Net) 程式語言案例學習 (06. 題庫測驗系統)
Visual Basic .Net (VB.Net) 程式語言案例學習 (06. 題庫測驗系統)¶
6.1 問題¶
這是一個題庫練習的程式,分為循序練習及模擬(電腦亂數選題)練習,循序練習會依序將題庫中所有題目列出,讓受測者作答。而模擬練習則由電腦出題,抽出一百題讓受測者測驗。題型分為是非題跟選擇題,因此答題介面設計上就必須依照題型而有所變化。最後是成績顯示,顯示答對題數以及答錯題數,並計算出成績。成績計算之後便會顯示正確答案,受測者可以瀏覽所有的正確答案。
6.2 需求¶
表格 6-1 「題庫測驗系統」系統目的分析表
| 版本:1.0 | 要做什麼 | 不要做什麼(不要做不代表不會做) |
|---|---|---|
| 能做什麼 | (第一格:必要項目) | (第二格:次要項目) |
| 建立是非題型與選擇題型可共用的資料結構,使用MS Access 2003資料庫。 | 可提供循序練習及模擬練習。 | |
| 答題區可依照不同題型而提供適當的選擇。 | 結束練習時可瀏覽正確答案。 | |
| 可以統計答錯題數及答對題數,和最後成績。 | ||
| 不能做什麼(不能做代表不需要做) | (第三格:不必要項目) | (第四格:不需要項目) |
| 提供答案的詳解。 | 將資料庫送上SQL,開發成網路版本。 |
表格 6‑2 「題庫測驗系統」系統目標分析表
| 版本: | 重要 | 不重要 |
|---|---|---|
| 優先 | (重) | (急) |
| 建立是非題型與選擇題型可共用的資料結構,使用MS Access 2003資料庫。 | 可提供循序練習及模擬練習。 | |
| 答題區可依照不同題型而提供適當的選擇。 | ||
| 可以統計答錯題數及答對題數,和最後成績。 | ||
| 不急迫 | (輕) | (緩) |
| 結束練習時可瀏覽正確答案。 | 無。 |
表格 6‑3 「題庫測驗系統」系統規格表
| 規格項目 | 規格內容 | 備註 |
|---|---|---|
| 題型 | 是非題及選擇題。 | … |
| 練習方式 | 循序測驗及模擬練習。 | … |
| 成績計算 | 答錯題數、答對題數、最後成績 | … |
| 瀏覽答案 | 作答完畢後可瀏覽正確答案。 | … |
6.3 特色¶
特點就是麻雀雖小五臟俱全,程式碼很少,卻能夠達到功能及目的。有循序出題及亂數出題的功能,可以做為測驗的工具。
6.4 使用工具¶
| 語言 | 軟體 |
|---|---|
| Visual Basic 2005 | MS Visual Studio 2005 .NET、MS Access |
6.5 系統架構¶
圖 6‑1
綜合以上的分析,我們可以很容易得找到使用者操作流程,而測驗軟體主要的使用者也就是受測者,因此介面上儘量依照使用者方便為主,因此由上而下,使用者只須依序點選就可以順利完成測驗,先選擇測驗形式,而後測驗完畢,看成績,瀏覽答案,完畢。
在系統設計方面,我們採用陣列,將題目資料讀入的好處是效率,而不必直接對資料庫作讀取動作,而且也方便往後改版成網路版時,差別只是由SQL Server下載題目資料到陣列而以,之後的動作就與資料庫無關,這樣不但具有效率而且也比較不會有錯誤。
6.6 程式實作¶
Public Class Form1
Inherits System.Windows.Forms.Form
‘宣告題目陣列
Private strExam(0, 0) As String
‘宣告答題陣列
Private strTest(0) As String
‘宣告答案陣列
Private strAnswer(0) As String
‘宣告題目索引
Private intPoint As Integer = 0
‘宣告總題數
Private intTotalRows As Integer
‘宣告狀態字串
Private strStatus As String = “”
‘程式起始載入事件副程式
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
‘設定題目位置索引
intPoint = 0
‘設定表單顯示到最大
SetFormScreen()
‘設定超連結
LinkLabel1.Links.Add(0, 35, “”)
End Sub
‘開始測驗按鈕被點選事件副程式
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
‘隱藏開始測驗按鈕
Button1.Visible = False
‘顯示測驗時要用的按鈕
Button2.Visible = True
Button3.Visible = True
Button4.Visible = True
Button5.Visible = True
Button6.Visible = True
‘隱藏完成按鈕
Button7.Visible = False
‘顯示文字框
RichTextBox1.Visible = True
‘顯示下拉式選單
ComboBox1.Visible = True
‘將題型選擇禁能
RadioButton1.Enabled = False
RadioButton2.Enabled = False
‘顯示題號標籤
Label6.Visible = True
‘狀態設定為測驗
strStatus = “Test”
‘題號索引值設定為零
intPoint = 0
‘若選擇循序測驗
If RadioButton1.Checked = True Then
‘設定循序測驗資料庫
SetDataBase(1)
‘倘若選擇模擬測驗
ElseIf RadioButton2.Checked = True Then
‘設定模擬測驗資料庫
SetDataBase(2)
End If
‘開始測驗函式,並傳入測驗題號索引
ExamTest(intPoint)
End Sub
‘測驗函式
Private Sub ExamTest(Optional ByVal intItem As Integer = 0)
‘顯示題數
Label6.Text = “第” & (intPoint + 1).ToString & “ 題/” & intTotalRows.ToString & “ 題”
‘清除下拉式選單
ComboBox1.Items.Clear()
‘增加不作答選項
ComboBox1.Items.Add(“不作答”)
‘藉由題目陣列判斷題型
Select Case strExam(1, intItem)
Case “O”, “X”
ComboBox1.Items.Add(“O”)
ComboBox1.Items.Add(“X”)
Case “1”, “2”, “3”, “4”
ComboBox1.Items.Add(“1”)
ComboBox1.Items.Add(“2”)
ComboBox1.Items.Add(“3”)
ComboBox1.Items.Add(“4”)
End Select
‘顯示題目
RichTextBox1.Text = strExam(2, intItem)
‘設定預設選項為第一項
ComboBox1.SelectedIndex = 0
‘若有答題
If IsNothing(strTest(intItem)) = False Then
‘設定下拉式選單索引值
Select Case strTest(intItem)
Case “O” : ComboBox1.SelectedIndex = 1
Case “X” : ComboBox1.SelectedIndex = 2
Case “1” : ComboBox1.SelectedIndex = 1
Case “2” : ComboBox1.SelectedIndex = 2
Case “3” : ComboBox1.SelectedIndex = 3
Case “4” : ComboBox1.SelectedIndex = 4
End Select
End If
End Sub
‘答錯題數函式
Private Sub ExamError(Optional ByVal intItem As Integer = 0)
‘顯示題數
Label6.Text = “第” & (intPoint + 1).ToString & “ 題”
‘若為循序練習
If RadioButton1.Checked = True Then
‘清空下拉式選單
ComboBox1.Items.Clear()
‘加入正確答案項目
ComboBox1.Items.Add(strExam(1, strAnswer(intItem) – 1))
‘設定索引值
ComboBox1.SelectedIndex = 0
‘顯示題目
RichTextBox1.Text = strExam(2, strAnswer(intItem) – 1)
‘若為模擬練習
ElseIf RadioButton2.Checked = True Then
‘清空下拉式選單
ComboBox1.Items.Clear()
‘加入正確答案
ComboBox1.Items.Add(strExam(1, intItem))
‘設定索引值
ComboBox1.SelectedIndex = 0
‘顯示題目
RichTextBox1.Text = strExam(2, intItem)
End If
End Sub
‘設定表單最大化函式
Private Sub SetFormScreen()
‘宣告螢幕物件
Dim Screens As Screen
‘宣告區域物件
Dim Rect As System.Drawing.Rectangle
‘設定螢幕物件
Screens = Screen.PrimaryScreen
‘設定區域大小
Rect = Screen.GetWorkingArea(Rect)
‘設定表單位置及大小
Me.Top = Rect.Top
Me.Left = Rect.Left
Me.Height = Rect.Height
Me.Width = Rect.Width
‘以下皆是調整控制項的位置及大小
GroupBox1.Left = 10
GroupBox1.Width = Me.Width – 30
GroupBox2.Left = 10
GroupBox2.Width = Me.Width – 30
GroupBox2.Height = Me.Height – GroupBox1.Height – GroupBox3.Height – 70
GroupBox2.Top = GroupBox1.Top + GroupBox1.Height + 10
GroupBox3.Left = 10
GroupBox3.Width = Me.Width – 30
GroupBox3.Top = GroupBox2.Top + GroupBox2.Height + 10
ComboBox1.Top = Button1.Top
Button2.Top = GroupBox2.Top + GroupBox2.Height – Button2.Height – 100
Button3.Top = GroupBox2.Top + GroupBox2.Height – Button3.Height – 100
Button4.Top = GroupBox2.Top + GroupBox2.Height – Button4.Height – 100
Button5.Top = GroupBox2.Top + GroupBox2.Height – Button5.Height – 100
Button6.Top = GroupBox2.Top + GroupBox2.Height – Button6.Height – 100
RichTextBox1.Width = GroupBox2.Width – RichTextBox1.Left – 20
RichTextBox1.Height = GroupBox2.Height / 2
LinkLabel1.Top = GroupBox3.Top + GroupBox3.Height – 10
LinkLabel1.Left = GroupBox3.Left + GroupBox3.Width – LinkLabel1.Width – 10
Button7.Left = GroupBox3.Left + GroupBox3.Width – Button7.Width – 20
‘以下是設定控制項顯示與隱藏
Button2.Visible = False
Button3.Visible = False
Button4.Visible = False
Button5.Visible = False
Button6.Visible = False
Button7.Visible = False
RichTextBox1.Visible = False
ComboBox1.Visible = False
RadioButton1.Enabled = True
RadioButton2.Enabled = True
Label6.Visible = False
‘以下是初始化控制項的內容
Label6.Text = “第” & (intPoint + 1).ToString & “ 題/” & intTotalRows.ToString & “ 題”
Label4.Text = “0”
Label5.Text = “0”
Label8.Text = “0”
End Sub
‘設定題目資料庫函式
Private Sub SetDataBase(Optional ByVal intSelect As Integer = 1)
‘宣告與資料庫連結的物件
Dim objCnn As New OleDb.OleDbConnection
Dim strCnn As String
Dim objCmd As New OleDb.OleDbCommand
Dim strCmd As String
Dim objCmdCount As New OleDb.OleDbCommand
Dim strCmdCount As String
‘設定連結字串並建立連結
strCnn = “Provider=Microsoft.Jet.OLEDB.4.0;Data Source =” & Application.StartupPath & “\Exam.mdb”
objCnn.ConnectionString = strCnn
objCnn.Open()
Select Case intSelect
‘循序練習
Case 1
‘獲得總題數
strCmdCount = “Select Count(*) from 網頁設計丙級學科”
objCmdCount.Connection = objCnn
objCmdCount.CommandText = strCmdCount
intTotalRows = objCmdCount.ExecuteScalar
‘取得資料庫
strCmd = “Select * from 網頁設計丙級學科”
objCmd.Connection = objCnn
objCmd.CommandText = strCmd
‘獲得資料表內容
Dim objRead As OleDb.OleDbDataReader = objCmd.ExecuteReader
‘宣告動態陣列
ReDim strExam(objRead.FieldCount – 1, intTotalRows)
ReDim strTest(intTotalRows)
Dim intI As Integer
‘將題目載入至陣列中
For intI = 0 To intTotalRows – 1
objRead.Read()
strExam(0, intI) = objRead.Item(0)
strExam(1, intI) = objRead.Item(1)
strExam(2, intI) = objRead.Item(2)
strExam(3, intI) = objRead.Item(3)
strExam(4, intI) = objRead.Item(4)
Next
‘關閉資料庫讀取物件
objRead.Close()
‘模擬練習
Case 2
‘設定亂數種子
Randomize()
‘宣告題陣列
Dim aryRnd(100) As Integer
Dim intRnd As Integer = 0
Dim intI As Integer = 0
Dim intJ As Integer = 0
Dim blnI As Boolean = False
‘是非題
For intI = 1 To 50
Do Until blnI = True
blnI = True
intRnd = Cint(Int((500 * Rnd()) + 1))
For intJ = 1 To 50
If aryRnd(intJ) = intRnd Then
blnI = False
Exit For
End If
Next
Loop
aryRnd(intI) = intRnd
blnI = False
Next
‘選擇題
For intI = 51 To 100
Do Until blnI = True
blnI = True
intRnd = Cint(Int((500 * Rnd()) + 1)) + 500
For intJ = 51 To 100
If aryRnd(intJ) = intRnd Then
blnI = False
Exit For
End If
Next
Loop
aryRnd(intI) = intRnd
blnI = False
Next
‘利用字串將題號都串起來
Dim strID As String = “”
For intI = 1 To 100
strID = strID & aryRnd(intI) & “,”
Next
‘查詢總題數
strCmdCount = “Select Count(*) from 網頁設計丙級學科Where [識別碼] in (“ & strID & “)”
objCmdCount.Connection = objCnn
objCmdCount.CommandText = strCmdCount
intTotalRows = objCmdCount.ExecuteScalar
‘查詢題目內容
strCmd = “Select * from 網頁設計丙級學科Where [識別碼] in (“ & strID & “)”
objCmd.Connection = objCnn
objCmd.CommandText = strCmd
‘獲得題目內容
Dim objRead As OleDb.OleDbDataReader = objCmd.ExecuteReader
‘設定動態陣列
ReDim strExam(objRead.FieldCount – 1, intTotalRows)
ReDim strTest(intTotalRows)
‘將題目讀入到陣列中
For intI = 0 To intTotalRows – 1
objRead.Read()
strExam(0, intI) = objRead.Item(0)
strExam(1, intI) = objRead.Item(1)
strExam(2, intI) = objRead.Item(2)
strExam(3, intI) = objRead.Item(3)
strExam(4, intI) = objRead.Item(4)
Next
‘關閉資料庫讀取物鍵
objRead.Close()
End Select
‘關閉資料庫連結
objCnn.Close()
End Sub
‘結束測驗按鈕事件副程式
Private Sub Button6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button6.Click
‘隱藏結束測驗按鈕
Button6.Visible = False
‘顯示完全按鈕
Button7.Visible = True
‘清除狀態
strStatus = “”
Dim intI As Integer = 0
‘錯誤題數
Dim intErr As Integer = 0
‘得分
Dim intErrA As Integer = 0
‘扣分
Dim dblErrB As Double = 0
‘統計錯誤題數
For intI = 0 To intTotalRows – 1
If strExam(1, intI) <> strTest(intI) Then
intErr += 1
End If
Next
‘動態陣列宣告回答陣列
ReDim strAnswer(intErr – 1)
Dim intJ As Integer = 0
intJ = 0
‘紀錄正確答案
For intI = 0 To intTotalRows – 1
‘當答錯題目時
If strExam(1, intI) <> strTest(intI) Then
‘設定正確答案到陣列中
strAnswer(intJ) = strExam(0, intI)
intJ += 1
End If
Next
‘顯示答對題數
Label4.Text = (intTotalRows – intErr).ToString
‘顯示答錯題數
Label5.Text = intErr.ToString
‘計算成績歸零
intErrA = 0
dblErrB = 0
‘開始計算成績
For intI = 0 To intTotalRows – 1
If strExam(1, intI) <> strTest(intI) And strTest(intI) <> “不作答” Then
dblErrB = dblErrB + CDbl(strExam(4, intI))
ElseIf strTest(intI) = “不作答” Then
ElseIf strExam(1, intI) = strTest(intI) Then
intErrA = intErrA + Cint(strExam(3, intI))
End If
Next
‘顯示成績
Label8.Text = Iif((intErrA – dblErrB) <= 0, “0”, (intErrA – dblErrB).ToString)
‘重新初始化
intTotalRows = intErr
intPoint = 0
ExamError(intPoint)
End Sub
‘顯示題目文字框鍵盤事件副程式
Private Sub RichTextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RichTextBox1.KeyPress
‘禁止輸入
e.Handled = True
End Sub
‘第一題按鈕點選事件副程式
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
strTest(intPoint) = ComboBox1.Text
intPoint = 0
If strStatus = “Test” Then
ExamTest(intPoint)
ElseIf strStatus = “” Then
ExamError(intPoint)
End If
End Sub
‘上一題按鈕點選事件副程式
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
strTest(intPoint) = ComboBox1.Text
intPoint = intPoint – 1
If intPoint < 0 Then
intPoint = 0
End If
If strStatus = “Test” Then
ExamTest(intPoint)
ElseIf strStatus = “” Then
ExamError(intPoint)
End If
End Sub
‘下一題按鈕點選事件副程式
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
strTest(intPoint) = ComboBox1.Text
intPoint = intPoint + 1
If intPoint > intTotalRows – 1 Then
intPoint = intTotalRows – 1
End If
If strStatus = “Test” Then
ExamTest(intPoint)
ElseIf strStatus = “” Then
ExamError(intPoint)
End If
End Sub
‘最後一題按鈕點選式鍵程式
Private Sub Button5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button5.Click
strTest(intPoint) = ComboBox1.Text
intPoint = intTotalRows – 1
If strStatus = “Test” Then
ExamTest(intPoint)
ElseIf strStatus = “” Then
ExamError(intPoint)
End If
End Sub
‘完成按鈕事件副程式
Private Sub Button7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button7.Click
‘隱藏所有控制項
RichTextBox1.Visible = False
ComboBox1.Visible = False
Label6.Visible = False
Button1.Visible = True
RadioButton1.Enabled = True
RadioButton2.Enabled = True
Button7.Visible = False
Button2.Visible = False
Button3.Visible = False
Button4.Visible = False
Button5.Visible = False
‘初始化控制項內容
strStatus = “”
Label4.Text = “0”
Label5.Text = “0”
Label8.Text = “0”
End Sub
‘當下拉是選項有改變時
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
‘設定答題內容到陣列
strTest(intPoint) = ComboBox1.Text
End Sub
‘當超連結被點選時
Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
‘呼叫超連結網頁
System.Diagnostics.Process.Start(e.Link.LinkData.ToString())
End Sub
End Class
6.7 修改重點¶
類似測驗的軟體通常都是要收費用的,自己開發一套就免去這種支出,題型方面由於只有是非題跟選擇題,而且皆以文字模式,因此建議讀者修改為可讀圖檔,圖形檔可以代碼為標示崁入在文字題目中,而後由程式判斷應該讀取哪一張圖檔,這種做法是市面上普遍測驗軟體的方法,這樣就可以解決數學公式或是化學符號以及英文看圖問答的題型,一般而言是將文字框置換成網頁瀏覽器物件,透過測驗軟體產生的網頁檔,來做顯示文圖並茂的題目,這種做法會相當方便移植到網頁上,變成網頁版的測試程式。不過並非最佳解,由於非資訊系的教師能力有限,因此有廠商依照教師手寫的考卷文稿,以一題一元新台幣的方式替教師作建檔的服務,這種方式可以說是互惠互利的模式。對於廠商來說有利,對於教師出卷有惠,教師出卷的時候只需要勾勾選選就可以出卷了。由程式設計來看,比較好的解法應該是讓所有題目內的元素皆看成物件,無論是圖形或文字還是符號,透過編輯器安排所在的位置,並將該題型儲存成一個可識別的規格檔,例如:XML。如此程式將更具彈性。
6.8 結論¶
這是一個單機版本的測驗軟體,有利於隨時安裝測驗,而且資料庫的題目可以用Excel匯入,是小而巧的程式。但隨著應用不同,會發現功能不及的地方,倘若是應用於班級上,必須修改成網路版,但若是小班制,其實只需要修改一點,就是透過網路磁碟機的方式,將題庫資料庫放置在主機上,其餘單機只需要連結到主機,設定成網路磁碟機,而程式只需要修改連結路徑,這樣也是另類的網路版測驗軟體。倘若有好幾個班級測驗,也只需要將Access資料庫上傳至SQL Server,當然程式連結的方式就要改成SQL版本,如此一來就變成SQL版本可提供更多學生測驗。
Lai Tai-Yu (賴岱佑)