หากมีคำถาม ขอให้ไปโพสต์ลง เว็บบอร์ดจีทูจีเน็ตดอตคอม ตัวใหม่แทนน่ะครับ

หรือติดต่อเข้ามาทาง Inbox ที่ เฟซบุ๊ค ผมครับ

หน้าหลัก
ข่าวสาร - บทความ ทั้งหมด
VB 6/VB.Net
ASP/ASP.Net
จับฉ่ายคอมพิวเตอร์
เรียนรู้ผ่าน Flash Movie
บทความที่มีผู้ตอบล่าสุด  
 RSS Feeds
 ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...   Download โปรแกรม RSS Reader

Forum - www.g2gnet.com
Webmaster - www.g2gnet.com
Visitors - Session views
 5 2 1 6 8 8 7

7 ธันวาคม พ.ศ.2549
1436 Users On-Line.
Visitors - Page views
 8 5 3 9 7 7 5
1 กุมภาพันธ์ พ.ศ.2551

Google   
เว็บ g2gnet.com
ขนาดตัวอักษร:  

พื้นฐานในการใช้งาน MS FlexGrid ก่อนสร้างความสัมพันธ์แบบ One To Many (ภาค 2)

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 4/3/2553   เวลา: 12:54
(อ่าน : 14913) 
บทความสำหรับเรื่องนี้ ซึ่งจะมีตามมาอีกในหลายๆตอน ... ผมนำมาเสนอในแง่มุม 2 ด้าน คือ ด้านแรกสำหรับคนที่กำลังพัฒนา ฝึกฝน ในสายงานโปรแกรมมิ่งอยู่ เพื่อให้เข้าใจกระบวนการคิด และ การออกแบบ และ อีกด้าน คือ การนำเสนอแนวทาง หรือ วิธีการถ่ายทอดความรู้ที่มีอยู่ออกไป ในรูปแบบที่เป็นเอกลักษณ์เฉพาะของตัวเอง เพื่ออยากจะบ่งบอกให้รู้กันทั่วไปว่า "การเรียนรู้งานพวกนี้ มันไม่ได้ยากเกินไปตามที่หลายๆคนคิด" ... คงจะมีคนถามว่า ทำไมผมไม่สอนให้ออกแบบ หรือ ทำใบขาย กับ ลูกค้า มาก่อน ... ตอบได้เลยครับว่า กรณีนี้มันยังไม่ใช่ประเด็นหลักๆที่สำคัญ เมื่อเทียบกับ การทำใบขาย กับ รายการสินค้าก่อนหรอกครับ เพราะขั้นตอนนี้ เรายังไม่จำเป็นต้องไปออกแบบตารางข้อมูลด้วยซ้ำไป แต่โปรแกรมจะสามารถค้นหารหัสสินค้าจากตารางข้อมูลออกมาได้ พร้อมกับ การที่ผู้ใช้สามารถเข้าไปแก้ไขข้อมูลในตารางกริดโดยตรงได้ทันที ... การทำแบบนี้ เราเรียกว่า Friendly Use หรือ เป็นมิตรกับผู้ใช้งาน ... ซึ่งจะแตกต่างไปจากหลายๆโปรแกรมที่เขาทำขายกัน หรือ ตามหนังสือ ... ไม่เชื่อต้องดาวน์โหลด Source Code มาทดสอบดูน่ะครับผม
ดาวน์โหลด
ดาวน์โหลด Source Code สำหรับ MS Visual Basic 6.0 - Service Pack 6
 ดาวน์โหลด Visual Basic 6.0 SP5: Run-Time Redistribution Pack
 ดาวน์โหลด Microsoft Data Access Object (MDAC) และ Jet 4.0 Update
 ดาวน์โหลด Microsoft Visual Basic Service Pack 6
ข้อมูลเพิ่มเติม
ตารางกริด (MS Flex Grid) ธรรมดา ที่ไม่ธรรมดา ... VB 6.0
การอ่านข้อมูลแบบ Text File เข้าสู่ MS FlexGrid ด้วย MS Visual Basic 6.0
ตารางกริด (MS Flex Grid) ธรรมดา ที่ไม่ธรรมดา ... ตอนการจัดเรียงข้อมูลในการแสดงผลให้ MS FlexGrid
ตารางกริด (MS Flex Grid) ธรรมดา ที่ไม่ธรรมดา ... ตอนใช้ Wheel Mouse ใน MS FlexGrid
ตารางกริด (MS Flex Grid) ธรรมดา ที่ไม่ธรรมดา ... ตอนจับยัดข้อมูลเข้าไปใน MS FlexGrid ได้
พื้นฐานในการใช้งาน MS FlexGrid ก่อนสร้างความสัมพันธ์แบบ One To Many (ภาค 1)
เริ่มต้นกระบวนการทำงาน

Projects --> References ...


Projects --> Component ...


การออกแบบ Design Time
modDataBase.bas โมดูลหากิน (มันมาอีกแล้ว) ... 55555+

Option Explicit

Global ConnDB As New ADODB.Connection
Global RS As New ADODB.Recordset
Global DS As New ADODB.Recordset
Global Statement As String
Global SQLStmt As String
'
' กำหนดว่าเป็นการเพิ่ม หรือ แก้ไขข้อมูล
Global blnNewData As Boolean
' ให้เกิดการ Update ในฟอร์มที่มีการเปลี่ยนแปลง
Global FormUpdate As Boolean

' เชื่อมเข้าสู่ไฟล์ฐานข้อมูล MS Access
Public Sub OpenDataBase()
On Error GoTo Err_Handler
Dim DB_File As String
    DB_File = App.Path
    If Right$(DB_File, 1) <> "\" Then DB_File = DB_File & "\"
    DB_File = DB_File & "ProductDB.MDB"
    ' Open a connection.
    Set ConnDB = New ADODB.Connection
    ConnDB.ConnectionString = _
        "Provider=Microsoft.Jet.OLEDB.4.0;" & _
        "Data Source=" & DB_File & ";" & _
        "Persist Security Info=False"
    ConnDB.Open
    Exit Sub
    
Err_Handler:
    MsgBox "Error : " & Err.Number & " " & Err.Description
    End
End Sub

Public Sub CloseDataBase()
    ' ตรวจสอบว่ามีการเชื่อมโยง - Connect ข้อมูลหรือไม่
    If ConnDB.State = adStateOpen Then
        ConnDB.Close
        Set ConnDB = Nothing
    End If
End Sub


Query - การเชื่อมความสัมพันธ์ของตารางสินค้า (tblProduct) กับ ตารางหน่วยนับ (tblUnit) ... งานจริงๆเลยน่ะครับ

จากนั้นไปเลือกมุมมอง SQL แล้วตัด Query Statement มาแปะลงใน Visual Basic 6 ได้เลย ... หมูอู๊ดๆเลย
SELECT tblProduct.ProductPK, tblProduct.ProductCode, tblProduct.Description, tblUnit.UnitName, tblProduct.PriceUnit
FROM tblProduct INNER JOIN tblUnit ON tblProduct.UnitFK = tblUnit.UnitPK



- อย่างที่บอกกันมาตลอดครับ หลักแรก (0) ต้องนำเอาค่า Primary ไปซ่อนไม่ให้ User เห็น
- Primary Key ต้องไม่ใช่รหัสสินค้า (ProductCode) ด้วยครับ

โค้ดในการค้นหารหัสสินค้าจากตารางข้อมูล tblProduct ... แสดงเฉพาะส่วนสำคัญน่ะครับ

' ======================================================
' การตั้งค่าคุณสมบัติของ MS FlexGrid ในลักษณะของ Run Time
' ======================================================
Sub SetupGrid()
    With fgData
        .FixedRows = 1
        .FixedCols = 0
        ' กำหนด 7 หลัก
        .Cols = 7
        ' กำหนด 1 แถว (เฉพาะ Column Header)
        .Rows = 1
        .ColWidth(0) = 0
        .ColWidth(1) = .Width \ 6 - 100
        .ColWidth(2) = .Width \ 6 + 250
        .ColWidth(3) = .Width \ 6 - 200
        .ColWidth(4) = .Width \ 6 - 100
        .ColWidth(5) = .Width \ 6 - 200
        .ColWidth(6) = .Width \ 6
        
        .TextMatrix(0, 0) = "PK"
        .TextMatrix(0, 1) = "รหัสสินค้า"
        .TextMatrix(0, 2) = "ชื่อสินค้า"
        .TextMatrix(0, 3) = "หน่วยนับ"
        .TextMatrix(0, 4) = "ราคาสินค้า"
        .TextMatrix(0, 5) = "จำนวน" ' ป้อนข้อมูลได้ในหลักนี้
        .TextMatrix(0, 6) = "รวมจำนวนเงิน"
    End With
    
End Sub

' ======================================================
' การเกิดเหตุการณ์ค้นหาข้อมูลรหัสสินค้า โดยการกดปุ่ม Enter
' ======================================================
Private Sub txtSearch_KeyPress(KeyAscii As Integer)
    If KeyAscii = vbKeyReturn Then
        Call CheckDataRow
    End If
End Sub

' ======================================================
' การตรวจสอบค่าใน MS FlexGrid ก่อนที่จะแสดงผลรายการใหม่
' ======================================================
Private Sub CheckDataRow()
    Dim CurrentRow As Integer

    ' ตรวจสอบว่าเป็นค่าว่างหรือไม่ หากใช่ก็ออกจากโปรแกรมย่อย (User ไม่มีการคีย์ข้อมูลใดๆ)
    If Trim(txtSearch.Text) = "" Or Len(Trim(txtSearch.Text)) = 0 Then
        txtSearch.SetFocus
        Exit Sub
    End If

    ' ค้นหาข้อมูลรหัสสินค้าในตารางสินค้า (tblProduct)
    ' บางคนอาจจะไม่เข้าใจในส่วนนี้ ขอให้กลับไปอ่านบทความเรื่อง VB6 กับ Access
    ' ตั้งแต่แรกก่อนน่ะครับ เพราะนี่ไม่ได้มาจากหนังสือ แต่มาจากประสบการณ์ล้วนๆของผม
Set RS = New Recordset Statement = "SELECT tblProduct.ProductPK, tblProduct.ProductCode, " & _ " tblProduct.Description, tblUnit.UnitName, tblProduct.PriceUnit " & _ " FROM tblProduct INNER JOIN tblUnit ON tblProduct.UnitFK = tblUnit.UnitPK " & _ " WHERE ProductCode = " & "'" & Trim$(txtSearch.Text) & "'" ' เคลียร์ค่าไว้รอเลย txtSearch.Text = "" RS.CursorLocation = adUseClient ' การค้นหาข้อมูลต้องใช้การอ่านเดินหน้าอย่างเดียว จะทำให้การเข้าถึงข้อมูลได้เร็วขึ้น ... อย่าลืม RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText ' ไม่พบข้อมูล ให้ออกจากโปรแกรมย่อยไปได้เลย If RS.RecordCount = 0 Then RS.Close: Set RS = Nothing Exit Sub End If ' เริ่มต้นการค้นหาข้อมูลในตารางกริด For CurrentRow = 1 To fgData.Rows - 1 ' ค้นหารหัสสินค้าที่อยู่ในหลักที่ 1 If fgData.TextMatrix(CurrentRow, 1) = RS("ProductCode") Then ' หากพบรายการสินค้าเดิมใส่จำนวนสินค้าเพิ่มเข้าไปอีก 1 ทันที ในแถวที่อยู่ ณ ปัจจุบัน fgData.TextMatrix(CurrentRow, 5) = Val(fgData.TextMatrix(CurrentRow, 5)) + 1 ' คูณราคาสินค้า กับจำนวนสินค้าเข้าไปใหม่ fgData.TextMatrix(CurrentRow, 6) = Format(Val(fgData.TextMatrix(CurrentRow, 4)) * _ Val(fgData.TextMatrix(CurrentRow, 5)), "0.00") RS.Close: Set RS = Nothing ' ไปโปรแกรมย่อยเพื่อคำนวณจำนวนเงินทั้งหมด Call CalTotalAmount ' จบจากการวนรอบ FOR และ ออกจากโปรแกรมย่อยไปเลยครับ Exit Sub End If Next ' ================================================= ' การนำรายละเอียดของสินค้าเข้าสู่ตารางกริดนั่นเอง ' ================================================= ' เพิ่มจำนวนแถวใน MS FlexGrid อีก 1 แถว fgData.Rows = fgData.Rows + 1 ' ให้แถวปัจจุบันลดลง 1 (เพื่อไม่ให้นับ Column Header) CurrentRow = fgData.Rows - 1 ' แถวใหม่ที่เพิ่มเข้ามา ทำการอ่านข้อมูลจาก RecordSet เข้ามา ' ปกติหลักแรก (หลัก 0) ต้องนำเอาค่า Primary Key ไปซ่อนเอาไว้น่ะครับ ... อย่าลืม fgData.TextMatrix(CurrentRow, 0) = RS("ProductPK") ' แสดงรหัสสินค้า fgData.TextMatrix(CurrentRow, 1) = "" & RS("ProductCode") ' แสดงชื่อสินค้า fgData.TextMatrix(CurrentRow, 2) = "" & RS("Description") ' แสดงหน่วยนับสินค้า fgData.TextMatrix(CurrentRow, 3) = "" & RS("UnitName") ' แสดงราคาสินค้า fgData.TextMatrix(CurrentRow, 4) = Format(RS("PriceUnit"), "0.00") ' ใส่จำนวนสินค้าครั้งละ 1 fgData.TextMatrix(CurrentRow, 5) = 1 ' คำนวณราคาขาย กับ จำนวน fgData.TextMatrix(CurrentRow, 6) = Format(fgData.TextMatrix(CurrentRow, 4) * _ fgData.TextMatrix(CurrentRow, 5), "0.00") RS.Close: Set RS = Nothing ' ไปโปรแกรมย่อยเพื่อคำนวณจำนวนเงินทั้งหมด Call CalTotalAmount End Sub ' ============================================= ' คำนวณหาผลรวมของราคาสินค้าทั้งหมด ' ============================================= Sub CalTotalAmount() ' หากไม่มีสักรายการก็ให้ออกจากโปรแกรมย่อยไปเลย If fgData.Rows = 1 Then Exit Sub Dim i As Integer Dim TotalAmount As Double ' นับไปตามจำนวนแถวที่มีอยู่ปัจจุบันของตารางกริด จนกว่าจะหมด ' แล้วรวมค่าในหลักที่ 6 ไว้ในตัวแปรเวียนแทียน TotalAmount ... 55555+ For i = 1 To fgData.Rows - 1 TotalAmount = TotalAmount + Val(fgData.TextMatrix(i, 6)) Next lblTotalAmount.Caption = Format(TotalAmount, "#,##0.00") End Sub
ลองย้อนกลับไปที่ภาค 1 ดูเลยครับ ... มันยังคงหลักการ วิธีคิดเช่นเดิม แต่สิ่งหลักๆที่เพิ่มเข้ามาแทน (ตามที่เคยบอกไว้ล่วงหน้าแล้ว) ก็คือ การสร้าง RecordSet เพื่อทำการค้นหารหัสสินค้าจริงๆ ที่อยู่ในตารางข้อมูล เพื่อนำมาเปรียบเทียบค่า (เครื่องหมาย = น่ะครับ) เพราะในกรณีนี้เราจะใช้ LIKE ไม่ได้ (รอบหน้าก็จะมีบอกอีกแหละครับ ... พี่น้อง) ... ไหนๆก็ไหนแล้ว แบบนี้มันยังไม่เท่ กิ๊บเก๋พอ เราต้องเสกให้ตารางกริดมันสามารถ ป้อนข้อมูลลงไปในหลัก และ แถวที่เราต้องการได้ด้วยจะดีกว่า ... ก็เอามาจากบทความที่ผมเคยเขียนไปแล้วนั่นแหละครับ ... อิอิอิอิอิ

โค้ดในการเสกเด็กเข้าท้อง เอ้ย ทำให้ตารางกริดธรรมดาๆ สามารถป้อนข้อมูลลงไปได้
อ่านแนวทางของการออกแบบ และ จินตนาการให้ตารางกริดสามารถป้อนข้อมูลได้ ... ที่นี่

' =============================================
' พิจารณาจากเหตุการณ์ (Event) ในการ Focus ตรงตำแหน่งใน Cell
' =============================================
Sub fgData_EnterCell()
Select Case fgData.Col ' เลือก Column ที่ต้องการ
    Case 0, 1, 2, 3, 4, 6: ' เราไม่ได้ป้อนข้อมูลในหลักที่ระบุ
        txtData.Visible = False ' จึงต้องสั่งให้ปิดการมองเห็น txtData

        
    Case 5: ' โอเค ถูกต้อง Cell ที่กำลัง Focus มาอยู่หลักที่ 5 ก็เริ่มต้นกระบวนการทำงานได้
        txtData.Visible = True ' เปิดให้ txtData มองเห็นได้
        txtData.Text = fgData.Text ' ค่าเดิมที่อยู่ใน Cell จะถูกส่งต่อไปให้ txtData เพื่อทำการแก้ไขต่อไป

        ' ขั้นตอนนี้คือการเลื่อนตำแหน่งของ txtData ให้ไปทับอยู่บนตำแหน่งของ Cell (หลักที่กำหนด) ตามที่เราต้องการ
        ' การเคลื่อนที่ โดย fgData.Move ตำแหน่งทางซ้าย, ตำแหน่งบน, ความกว้างของเซลล์, ความสูงของเซลล์
        txtData.Move fgData.CellLeft + 60, fgData.Top + fgData.CellTop, fgData.CellWidth, fgData.CellHeight

        ' เมื่อ txtData เคลื่อนที่ไปทับตำแหน่ง Cell ที่เราต้องการแล้ว ให้ Focus ไปที่ txtData เพื่อที่จะสามารถแก้ไขข้อมูลลงใน TextBox ได้
        txtData.SetFocus
End Select

End Sub

' เมื่อค่าใน TextBox เปลี่ยน ค่าใน Cell ที่ TextBox ทับเอาไว้ ก็ต้องเปลี่ยนตาม
Private Sub txtData_Change()
    Dim sRow As Integer
    ' หาค่าตำแหน่งของแถว
    sRow = fgData.Row
    
    ' เมื่อ txtData เกิดการเปลี่ยนแปลง ก็จะส่งค่าให้กับ Cell ที่เราต้องการด้วย
    ' แต่ ณ ขณะนี้เรายังมองไม่เห็นหรอกครับ เพราะ txtData มันทับ Cell ไว้อยู่ -- สำมะคัญน่ะตัวนี้
    ' ค่าใน TextBox จะต้องไม่เป็นค่าว่าง หรือ 0 ... หากเป็นใส่ 1 ให้มันซ่ะ
    If Trim(txtData.Text) = "" Or Len(Trim(txtData.Text)) = 0 Or txtData.Text = "0" Then txtData.Text = "1"
    
    fgData.TextMatrix(sRow, 5) = txtData.Text
    ' คำนวณราคา และ จำนวนสินค้า
    fgData.TextMatrix(sRow, 6) = Format(fgData.TextMatrix(sRow, 4) * fgData.TextMatrix(sRow, 5), "0.00")

    ' ไปโปรแกรมย่อยเพื่อคำนวณจำนวนเงินทั้งหมด
    Call CalTotalAmount

End Sub

Private Sub txtData_GotFocus()
    ' โปรแกรมย่อยในการทำ High Light ใน TextBox
    Call HLText(txtData)
End Sub

' การดักคีย์ที่กดลงบน TextBox
Private Sub txtData_KeyDown(KeyCode As Integer, Shift As Integer)
    Select Case KeyCode
        Case vbKeyDown
            SendKeys "{DOWN}"
            Call txtData_KeyPress(vbKeyReturn)
        Case vbKeyUp
            SendKeys "{UP}"
            Call txtData_KeyPress(vbKeyReturn)
        Case vbKeyEscape
            Call txtData_KeyPress(vbKeyReturn)
    End Select
End Sub

Private Sub txtData_KeyPress(KeyAscii As Integer)
    If KeyAscii = vbKeyReturn Then
        txtData.Visible = False
        KeyAscii = 0
    Else
        ' ตรวจสอบการกดคีย์ตัวเลขได้เท่านั้น
        KeyAscii = CheckDigitOnly(KeyAscii)
    End If

End Sub

' ==========================================================
' พวกฟังค์ชั่นเหล่านี้เราต้องใช้งานบ่อยๆ ควรนำไปเก็บไว้ใน Module จะดีกว่าน่ะครับ
' ==========================================================
' ตรวจสอบการป้อนค่าได้เฉพาะตัวเลข
Function CheckDigitOnly(Index As Integer) As Integer
    Select Case Index
        Case 48 To 57 ' 0 - 9
        Case 8            ' Back Space
        Case 13         ' Enter
        Case Else
            Index = 0
    End Select
    CheckDigitOnly = Index
End Function

' โปรแกรมย่อยในการทำ High Light ใน TextBox ... ใช้ร่วมกับ GotFocus
Public Sub HLText(ByRef sText)
    On Error Resume Next
    With sText
        .SelStart = 0
        .SelLength = Len(sText.Text)
    End With
End Sub
Conclusion:
หากพี่น้องท่านใด เคยพบเห็นวิธีการสอนแบบนี้ ขอให้รับรู้ไว้เลยว่า คนผู้นั้นต้องฟันฝ่าปัญหา อุปสรรค สำหรับการพัฒนาฝึกฝนตนเอง ในงานเขียนโปรแกรมต่างๆ มาอย่างทรหด อดทนเอามากๆ ... คิกๆๆๆๆ ... เอ้า ไม่ได้ล้อเล่นน่ะครับ เพราะสิ่งเหล่านี้มันไม่เคยปรากฏอยู่ตามหนังสือ ตามตำราเลยสักเล่ม หรือเว็บไซต์ใดๆ ... แต่ผมก็หวังไว้บ้างว่า คงจะแรงบันดาลใจ ให้กับพี่น้องหลายๆท่าน (ที่คิดว่าการเขียนโปรแกรมมันเป็นเรื่องยากเย็นเอาซ่ะเหลือเกิน) จงมีความพยายาม ฟันฝ่าอุปสรรค ขวากหนามทั้งหลาย เหมือนที่ผมเคยสัมผัสมาแล้ว

จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
Email: [email protected] หรือ โทร. 08-6862-6560