成语大会姚瑶微博:vb数据窗体架构的说明

来源:百度文库 编辑:中财网 时间:2024/04/30 17:51:52

vb数据窗体架构的说明

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类的话,还可以再扩充功能,比如可以增加一些常用的功能,如对列的输入数据,检查等。