vb数据窗体架构的说明

来源:百度文库 编辑:神马文学网 时间:2024/04/28 08:53:08
1.架构的介绍
提供一个简单的,可以扩充的客户端架构。主要完成对数据库数据到UI层(窗口控件)的读写。例如:
‘************************************
‘函数名:   ReadForm
‘参数 :     tempId:单证号
‘返回值:
‘说明 :    读取数据库字段
‘************************************
Private SubReadForm(tempId As String)
Dim sql As String
Dim rs AsADODB.Recordset
sql = "selectleadid,declaretime,tocorpname from insrcmain where tempid=‘" & tempId& "‘"
Set rs =getRecordset(sql)
Set mydForm =myDataForm.getForm("leadid")
mydForm.dataSource = rs
Set mydForm =myDataForm.getForm("declaretime")
mydForm.dataSource = rs
Set mydForm =myDataForm.getForm("tocorpname")
mydForm.dataSource = rs
If Not rs Is Nothing Orrs.RecordCount > 0 Then
myDataForm.ReadData
CloseRecordset rs
End If
End Sub
以上代码即完成了由查询语句到数据库查询结果填充到文本框,日历控件的读的功能。
2.架构的功能
从功能来分:有从数据库读和写的功能
从面向的对象来分:有面向网格控件:spread和面向VB常用控件的TEXTBOX,CALANDER等。
各个模块的说明
类DataColumn:提供spread控件数据列的绑定功能。是类mydataspread实现的基础。
这个类主要参考了.NET框架结构中的DATAGRID控件。使得在读取数据库数据时不用通过复杂的循环,一个一个的填充数据到spread控件中,而是使用了类似配置文件的写法,通过调用myDataSpread的fill方法,自动填充数据到spread控件中。下面是一个不使用类DataColumn和使用类DataColumn的例子。
不使用类DataColumn:
Private SubcmdQuery_Click()
Dimsql As String
Dim whereClause As String
Dim i As Integer
whereClause = " where approve=‘1‘ andcancel=‘0‘ and bonded=‘0‘ "
。。。。。。。。。
sql = "select * fromoriginalsource" & whereClause
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
On Error GoTo errorpos
rst.Open sql, cn, adOpenKeyset, adLockOptimistic
If rst.RecordCount <= 0 Then
spdOriSrc.maxRows = 0
GoTo EXITPOS
End If
With spdOriSrc
.maxRows = rst.RecordCount
rst.MoveFirst
For i = 1 To .maxRows
.Row = i
.Col = LNG_SPDSRC_HSCODE
.Text =rst.Fields("hscode").value
.Col = LNG_SPDSRC_CHNNAME
.Text =rst.Fields("chinesename").value
.Col = LNG_SPDSRC_ENGNAME
.Text =rst.Fields("englishname").value
.Col = LNG_SPDSRC_PARTNO
.Text =rst.Fields("sourcepartno").value
.Col = LNG_SPDSRC_SPEC
.Text =rst.Fields("spec").value
.Col = LNG_SPDSRC_TYPE
.Text =rst.Fields("type").value
.Col = LNG_SPDSRC_UNIT
.Text =rst.Fields("unit").value
.Col = LNG_SPDSRC_PRICE
.Text =CStr(rst.Fields("price").value)
.Col = LNG_SPDSRC_CURRENCY
.Text =rst.Fields("currency").value
.Col = LNG_SPDSRC_COUNTRY
.Text =rst.Fields("country").value
.Col = LNG_SPDSRC_NET
.Text =CStr(rst.Fields("net").value)
.Col = LNG_SPDSRC_GROSS
.Text =CStr(rst.Fields("gross").value)
.Col = LNG_SPDSRC_SRCID
.Text =rst.Fields("orisourceid").value
rst.MoveNext
Next i
End With
EXITPOS:
If rst.State = adStateOpen Then
rst.Close
End If
Set rst = Nothing
Exit Sub
errorpos:
MsgBox "打开数据库时发生错误,请稍后重试!", vbOKOnly + vbInformation,"注意"
Resume EXITPOS
End Sub
可以看见,除了写对数据库查询的SQL语句外,还要对每一个列作多次的循环和填写,同时还要对数据类型进行转换。
.Col = LNG_SPDSRC_GROSS
.Text =CStr(rst.Fields("gross").value)
这样做的结果使得代码的修改和维护非常困难,而且如果要增加或删减数据库里的某一个列的化,需要对上面的代码做非常大的改动。
下面是使用了使用类DataColumn的例子:
‘填充记录Selected
Private Sub FillSelected(tempIdAs String)
Dim sql As String ‘查询语句
Dim rs AsADODB.Recordset
sql = "select hscode," ‘税号
sql = sql + "chinesename, " ‘中文品名
sql = sql + "englishname," ‘英文品名
sql = sql + "sourcepartno," ‘备件号
sql = sql + "spec," ‘规格
sql = sql + "type," ‘型号
sql = sql + "unit," ‘单位
sql = sql + "currency," ‘币制
sql = sql + "country," ‘原产国家
sql = sql + "orisourceid," ‘原始料件号
sql = sql + "price," ‘价格
sql = sql + "net," ‘净重
sql = sql + "gross," ‘毛重
sql = sql + "quantity" ‘出库数量
sql = sql + " from insrcdetail wheretempid=‘" & tempId & "‘"
On Error GoTo errorpos
Set rs = getRecordset(sql) ‘得到数据库记录
If rs.RecordCount > 0 Then ‘如果记录数不为0
mySpreadSelected.fill rs ‘填充
Else
GoTo errorpos
End If
CloseRecordset rs ‘关闭记录集
Exit Sub
errorpos:
ShowErrMessage
CloseRecordset rs
End Sub
可以看到,上面的代码非常简介,除了标准的SQL语句外,只有一句mySpreadSelected.fillrs就完成了数据到控件的过程。为什么会变得如此简单呢?原因在于使用了类DataColumn将数据列和spread的列进行了绑定。请看下面:
‘初始化Spread
Private SubInitSpreadSelected()
Dim dc As DataColumn
Dim dcs As NewCollection
Set mySpreadSelected =New myDataSpread
Set dc = New DataColumn ‘税号
dc.Col = LNG_SPDSEL_HSCODE
dc.DataField = "hscode"
dcs.add dc
Set dc = New DataColumn ‘中文品名
dc.Col = LNG_SPDSEL_CHNNAME
dc.DataField = "chinesename"
dcs.add dc
Set dc = New DataColumn ‘英文品名
dc.Col = LNG_SPDSEL_ENGNAME
dc.DataField = "englishname"
dcs.add dc
Set dc = New DataColumn ‘备件号
dc.Col = LNG_SPDSEL_PARTNO
dc.DataField = "sourcepartno"
dcs.add dc
Set dc = New DataColumn ‘规格
dc.Col = LNG_SPDSEL_SPEC
dc.DataField = "spec"
dcs.add dc
Set dc = New DataColumn ‘型号
dc.Col = LNG_SPDSEL_TYPE
dc.DataField = "type"
dcs.add dc
Set dc = New DataColumn ‘单位
dc.Col = LNG_SPDSEL_UNIT
dc.DataField = "unit"
dcs.add dc
Set dc = New DataColumn ‘原产国家
dc.Col = LNG_SPDSEL_COUNTRY
dc.DataField = "country"
dcs.add dc
Set dc = New DataColumn ‘币制
dc.Col = LNG_SPDSEL_CURRENCY
dc.DataField = "currency"
dcs.add dc
Set dc = New DataColumn ‘原始料件号
dc.Col = LNG_SPDSEL_SRCID
dc.DataField = "orisourceid"
dcs.add dc
Set dc = New DataColumn ‘净重
dc.Col = LNG_SPDSEL_NET
dc.DataField = "net"
dcs.add dc
Set dc = New DataColumn ‘价格
dc.Col = LNG_SPDSEL_PRICE
dc.DataField = "price"
dcs.add dc
Set dc = New DataColumn ‘毛重
dc.Col = LNG_SPDSEL_GROSS
dc.DataField = "gross"
dcs.add dc
Set dc = New DataColumn ‘出库数量
dc.Col = LNG_SPDSEL_NUMBER
dc.DataField = "quantity"
dcs.add dc
mySpreadSelected.create Me.spdSelected, dcs
End Sub
代码InitSpreadSelected就像配置文件一样,把数据库中的字段和spread控件里的字段结合起来了。如:dc.DataField= "gross"。其中属性DataField就是改列对应的数据字段名称。
a.类myDataSpreat是实现上述功能的类。主要提供了对数据的读和写。
首先是对数据库的填充:
‘************************************
‘函数名:    fill
‘参数  :   rs:Recordset(可选)
‘返回值:
‘说明  :    填充spread控件
‘************************************
Public Sub fill(Optionalrs As ADODB.Recordset)
If fpSpread.maxRows > 0 Then
fpSpread.maxRows = 0
End If
If Not IsMissing(rs) Then
Set fpSpread.dataSource = rs
End If
End Sub
Fill方法要求提供一个recordset做为参数,其中recordset就是对应数据库的数据。这里使用了控件spread的数据绑定功能:Set fpSpread.dataSource = rs。注意:recordset参数可选,如果没有传入,则清空spread网格数据。
对数据库的保存:
‘************************************
‘函数名:    save
‘参数1:    adoSave:Recordset
‘参数2:    rows:需要保存到数据库的行(可选)
‘返回值:
‘说明  :    保存控件spread中的值到数据库
‘************************************
Public Sub save(ByRefadoSave As ADODB.Recordset, Optional rows As Variant)
Dim i As Long
Dim j As Long
Dim maxRows As Long
Dim myRows() As Long
j = 0
With fpSpread
If .maxRows = 0 Then
Exit Sub
End If
If IsMissing(rows) Then ‘表示所有的行都需要保存
ReDim myRows(.maxRows)
For i = 1 To .maxRows
myRows(i) = i
Next
Else
‘根据传过来的参数有选择的保存
ReDim myRows(UBound(rows))
For i = 1 To UBound(rows)
myRows(i) = rows(i)
Next i
End If
maxRows = UBound(myRows)
For i = 1 To maxRows
adoSave.AddNew
For Each Column In DataColumnCollection
If Column.DataField <>vbNullString Then
If Column.Col = -1 Then
adoSave(Column.DataField) =Column.Text ‘预先设定的值
Else
.Row = myRows(i)
.Col = Column.Col
adoSave(Column.DataField) =.Text ‘表格中的值
End If
End If
Next
adoSave.Update
Next i
End With
End Sub
参数adoSave是一个recordset,代表要保存到数据库的recordset,其实就是提供了要保存到数据库里的字段。
参数rows(可选),因为有些行不需要保存,所以设置了rows参数,提供了哪些行需要保存到数据库。
方法fill和save进行操作的基础都是由datacolumn中的属性提供。其中比较重要的是datafield属性,col属性,text属性。Datafield属性上面已经说过,是表示该列在数据库里代表的字段名称。Col属性则表示这个列在控件里实际的列的索引。当col=-1也就是等于默认值的时候,表示这个列不在界面上显示,而是写到数据库里。可以看以下代码:
IfColumn.Col = -1 Then
adoSave(Column.DataField) =Column.Text ‘预先设定的值
Else
.Row = myRows(i)
.Col = Column.Col
adoSave(Column.DataField) =.Text ‘表格中的值
End If
当Column.Col = -1,数据库里实际保存的值是由text属性的值。
DataForm模块
先看以下代码:
‘************************************
‘函数名:    ReadForm
‘参数  :    tempId:单证号
‘返回值:
‘说明  :    读取数据库字段
‘************************************
Private Sub ReadForm(tempIdAs String)
Dim sql As String
Dim rs AsADODB.Recordset
sql = "selectleadid,declaretime,tocorpname from insrcmain where tempid=‘" & tempId& "‘"
Set rs =getRecordset(sql)
Set mydForm =myDataForm.getForm("leadid")
mydForm.dataSource = rs
Set mydForm =myDataForm.getForm("declaretime")
mydForm.dataSource = rs
Set mydForm =myDataForm.getForm("tocorpname")
mydForm.dataSource = rs
If Not rs Is Nothing Orrs.RecordCount > 0 Then
myDataForm.ReadData
CloseRecordset rs
End If
End Sub
和myDataSpread一样,也是使用传入的参数recordset,然后自动调用readdata方法,把数据读入到控件中。
可以看到上面代码中有这样一段:
If Not rs Is Nothing Orrs.RecordCount > 0 Then
myDataForm.ReadData
CloseRecordset rs
End If
其实myDataForm使用了接口来完成对每一个控件类数据的装入。
dForm类:dForm类是一个接口,主要是实现对数据的读和写的接口.
‘************************************
‘函数名:    dRead
‘参数  :
‘返回值:
‘说明  :    对数据库字段进行读取
‘************************************
Public Function dRead()
End Function
‘************************************
‘函数名:    dWrite
‘参数  :    adoSave:ADODB.Recordset
‘返回值:
‘说明  :    对数据库字段进行读取
‘************************************
Public FunctiondWrite(ByRef adoSave As ADODB.Recordset)
End Function
dRead和dWrite方法并没有实际的代码,具体的实现都是由实现了dForm接口类来实现。
‘************************************
‘函数名:    dTextForm
‘说明  :    对接口dForm的实现
‘************************************
Implements dForm
Private WithEventsmyControl As TextBox ‘TextBox控件
Private mydataField AsString ‘数据库字段
Private mydataValue AsVariant ‘数据值
Private mydataSource AsADODB.Recordset ‘数据源
如:类dTextForm即对接口dForm实现。
‘************************************
‘函数名:    dRead
‘参数  :
‘返回值:    Variant
‘说明  :    对数据库字段进行读取
‘************************************
Private FunctiondForm_dRead() As Variant
If mydataSource Is Nothing OrmydataSource.RecordCount = 0 Then
myControl.Text = ""
Else
myControl.Text =mydataSource(mydataField)
End If
End Function
‘************************************
‘函数名:    dWrite
‘参数  :    adoSave:ADODB.Recordset
‘返回值:
‘说明  :    对数据库字段进行读取
‘************************************
Private FunctiondForm_dWrite(ByRef adoSave As ADODB.Recordset) As Variant
adoSave(mydataField) = Trim(myControl.Text)
End Function
在dTextForm中还有一个重要的属性:Control
Private WithEvents myControl As TextBox ‘TextBox控件
注意myControl的申明前由关键字WithEvents,表示它将接管传入的textbox的事件。
‘************************************
‘函数名:    myControl_KeyPress
‘参数  :   KeyAscii:键盘ascii码
‘返回值:
‘说明  :    键盘按下时间,屏蔽非法字符["][%][‘][?]
‘************************************
Private SubmyControl_KeyPress(KeyAscii As Integer)
‘34 代表["],37代表[%],39 代表[‘],63 代表[?]
If KeyAscii = 37 OrKeyAscii = 34 Or KeyAscii = 39 Or KeyAscii = 63 Then
KeyAscii = 0
ShowErrMessage "你输入了非法字符"
End If
End Sub
函数myControl_KeyPress即表示对非法字符的屏蔽。
最后,是集合类DataForm。
‘************************************
‘函数名:    DataForm
‘说明  :    接口dForm的集合类
‘************************************
Dim dFormCollection AsCollection ‘接口dForm的集合类
Dim dFormInstance AsdForm ‘dForm实例
从它的私有字段可以看到,类DataForm中最主要的就是一个字段dFormCollection被申明为集合。
在DataForm实现了集合中的公共方法read和write。也就是接口dForm里定义的。
‘************************************
‘函数名:    ReadData
‘参数  :
‘返回值:
‘说明  :    调用接口的读方法从数据库里读数据到控件
‘************************************
Public FunctionReadData()
For Each dFormInstance In dFormCollection
dFormInstance.dRead
Next
End Function
‘************************************
‘函数名:    WriteData
‘参数  :    rsSave:ADODB.Recordset
‘返回值:
‘说明  :    调用接口的写方法把控件的值写入到数据库
‘************************************
Public FunctionWriteData(ByRef rsSave As ADODB.Recordset)
rsSave.AddNew
For Each dFormInstance In dFormCollection
dFormInstance.dWrite rsSave
Next
rsSave.Update
End Function
出于可能需要后绑定的需要,所以提供了对集合类中的单个类可以读取
‘************************************
‘函数名:    add
‘参数  :   newForm:dForm实例
‘参数  :   id:键
‘返回值:
‘说明  :    增加一个dForm实例
‘************************************
Public Sub add(ByRefnewForm As dForm, ID As String)
dFormCollection.add newForm, ID
End Sub
‘************************************
‘函数名:    getForm
‘参数  :   id:键
‘返回值:   dForm实例
‘说明  :    返回一个dForm实例
‘************************************
Public FunctiongetForm(ID As String) As dForm
Set getForm = dFormCollection(ID)
End Function
Add是添加一个实现了dForm的类,而getForm方法则可以通过关键字,可以在add方法中增加,取回一个实现了dForm的类。
不足之处:
1. 在写列的绑定时候,显得过于繁琐。可以做的更简洁一些。比如:
Set dc = New DataColumn ‘英文品名
dc.Col = LNG_SPDSEL_ENGNAME
dc.DataField = "englishname"
dcs.add dc
可以写成:
myDataSpread.bindColumn("englishname",LNG_SPDSEL_ENGNAME, ("englishname")
2. 可以在配置列属性的时候,把sql语句一起写入。直到具体要填充的时候,只要写fill方法就可以了。这样就不用每次到写查询语句,然后在填充了。
3. 对于spread类的话,还可以再扩充功能,比如可以增加一些常用的功能,如对列的输入数据,检查等。