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

หรือติดต่อเข้ามาทาง 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 5 9 1 7 2 8

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

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

การจัดเก็บข้อมูลตำแหน่ง และ ชื่อไฟล์รูปภาพไว้ในฐานข้อมูล

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 30/3/2553   เวลา: 18:11
(อ่าน : 59019) 
    ต้องขอบอกก่อนน่ะครับว่า เป็นการเก็บเฉพาะตำแหน่ง หรือ ชื่อไฟล์ภาพไว้ในฐานข้อมูลเท่านั้น ผมไม่นิยม หรือ สนับสนุนแนวคิดในการเก็บภาพจริงๆลงฐานข้อมูล การจัดเก็บข้อมูลรูปภาพไว้ในฐานข้อมูล ปกติจะมี 2 แนวทาง คือ เก็บ Path และชื่อรูปภาพตามตำแหน่งอย่างเดิมของมันไว้หมดเลย หรือ อีกวิธีคือคัดลอกภาพนั้นๆไปไว้ในตำแหน่งที่เราต้องการ เช่น ให้อยู่ภายใต้โปรเจคของเรา (App.Path & "\images") แบบแรกเป็นแบบที่ง่าย แต่จะติดปัญหาว่าหากหาไฟล์ภาพไม่เจอ (กรณีรูปภาพหาย) จะทำให้เกิด Error ขึ้นได้ แบบที่ 2 น่าจะดีกว่า เหมาะสำหรับวง LAN ด้วย แต่จะเขียนยากขึ้น (รอบหน้าจะมาว่ากันอีกที) ... บทความนี้จะใช้กรณีแรกน่ะครับ ก่อนอื่นเราต้องมานั่งคิดวิเคราะห์การออกแบบกันเสียก่อน
  • สร้างฟิลด์ข้อมูลในการเก็บตำแหน่งไฟล์ภาพขึ้นมา โดยกำหนดชนิดข้อมูลเป็นแบบ Text ความยาว 255 ตัวอักษร
  • จะสามารถ Browse เฉพาะภาพมาดูได้อย่างไร ... ก็ใช้ CommonDialog ยังไงล่ะครับ
  • การนำภาพมาแสดงผลจะแบ่งออกได้อีก 2 กรณี
    • ไม่มีข้อมูลภาพเก็บไว้เลย (ทั้งการเพิ่ม และ การแก้ไข) ดังนั้นให้หาภาพอะไรก็ได้มาแสดงแทน เพื่อบอกผู้ใช้งานว่าไม่มีภาพอยู่น่ะครับ
    • การแสดงภาพเดิมที่มีอยู่ ก็โดยการอ่านข้อมูลจากตารางข้อมูลเข้ามา นำตำแหน่ง และ ชื่อไฟล์ภาพไปแสดงใน Image Control (โดย Method LoadPicture(ตำแหน่ง และ ชื่อไฟล์)) พร้อมทั้งเก็บค่าตำแหน่งภาพ และ ชื่อไฟล์ภาพไว้ในตัวแปรแบบ String หรือ ใน TextBox ก็ได้เลือกเอา ทำไมล่ะ ? ก็เพราะตอนบันทึกข้อมูล (ไม่ว่าจะแก้ไขหรือไม่ก็ตาม) ก็จะได้นำค่านี้ไปจัดเก็บลงตารางข้อมูลด้วยยังไงล่ะครับ ... บทความนี้ใช้ตัวแปรรับค่าน่ะครับ
  • ขั้นสุดท้าย คือ การบันทึกข้อมูลก็เป็นอันจบ

    การออกแบบตารางข้อมูลในแบบฉบับของผม เหล่าขาประจำก็ไม่ต้องกล่าวถึงกันมาก แต่สำหรับสมาชิกใหม่ที่เข้ามาอ่าน ต้องกลับไปดูเรื่องของ VB6 กับ MS Access ตั้งแต่ต้นๆก่อนครับ แล้วคุณถึงจะเข้าใจ
ดาวน์โหลด
ดาวน์โหลด 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
เริ่มต้นกระบวนการทำงาน

Projects --> Component ...


การออกแบบ Design Time

เกิดเหตุการณ์ Double Click หรือ กด Enter ในแต่ละแถวของ MS FlexGrid

โค้ดในการเตรียมแสดงผลรายละเอียดของลูกค้า - frmMainCustomer.frm

' ======================================================
' เกิดเหตุการณ์ Double Click หรือ กด Enter ในแต่ละแถวของ MS FlexGrid
' ======================================================
Private Sub fgCustomer_DblClick()
    ' กำหนดหลักที่ทำการอ่าน คือ หลัก 0 ที่เก็บค่า Primary Key ของลูกค้าไว้(CustomerPK) และเราซ่อนเอาไว้ด้วย
    fgCustomer.Col = 0
    ' ดัก Error ไว้ก่อน เผื่อในกรณีที่ไม่มีข้อมูลสักรายการใน MS FlexGrid
    If Val(fgCustomer.Text) <= 0 Or IsNull(fgCustomer.Text) Then Exit Sub
    
    ' =======================================================
    ' ตัวแปร blnNewData และ FormUpdate จะถูกประกาศแบบ Global ไว้ใน gMyDB.bas
    ' =======================================================

    ' บอกว่าเป็นการแก้ไขข้อมูล
    blnNewData = False
    ' ตั้งค่าเริ่มต้นเพื่อแจ้งกลับมาฟอร์มหลักว่าเกิดการเปลี่ยนแปลงข้อมูลหรือไม่ ?
    ' เพื่อให้เกิดการ Refresh แสดงผลใหม่ในตารางกริด
    FormUpdate = False
    frmCustomer.Show vbModal
    
    ' หาก FormUpdate ส่งค่ากลับมาเป็นจริง แสดงว่าเกิดการแก้ไขข้อมูล (Save) ก็ต้องแสดงผลข้อมูลใหม่
    If FormUpdate Then
        Call SetupFgCustomer
        Call DisplayFgCustomer
    End If
End Sub

ฟอร์มการแสดงรายละเอียดข้อมูลลูกค้า

การแสดงรายละเอียดของลูกค้า และ แสดงผลภาพด้วย

Option Explicit
' ตัวแปรรับค่า CustomerPK จากฟอร์มหลัก
Dim CusPK As Long

' ประกาศตัวแปรสำหรับรับค่าตำแหน่งไฟล์ภาพ หรือ จะใช้ TextBox ก็ได้ไม่ผิดแต่ประการใด
Dim PicturePath As String


Private Sub Form_Load()
    ' ตั้งหน้าจอ (ฟอร์ม) กึ่งกลาง (เครื่องหมาย \ คือ การหารตัดเศษ ... จะทำงานได้เร็วกว่าการหาร /)
    Me.Move (Screen.Width - Width) \ 2, (Screen.Height - Height) \ 2
    
    ' เคลียร์หน้าจอแสดงผล
    Call SetupScreen
    
    ' ไม่ให้คีย์ข้อมูลลงไปได้ ... หากต้องการแก้ไข ให้กลับไปดูในบทความที่มีอยู่ด้วยน่ะครับ
    ' จุดประสงค์ของบทความนี้เพื่อต้องการแสดงวิธีการเก็บ Path ของภาพเท่านั้น
    txtCustomerID.Locked = True
    
    ' โหลดรายชื่อจังหวัดเข้ามาสู่ ComboBox
    Call DisplayProvince
    
    ' ส่วนนี้ก็ผ่านไปเลยครับ ให้พิจารณาการแก้ไขข้อมูลอย่างเดียว
    ' If blnNewData Then ... หรือ เขียนง่ายๆแบบนี้ก็ได้
    If blnNewData = True Then
        ' รหัสลูกค้าจะให้ทำงานอัตโนมัติ
        ' เช่น RS("CustomerID") = Right$("CUS0000000" & CountRec, 10)
        txtCustomerID.Text = "[New]"
    ' พิจารณาเฉพาะการแก้ไขข้อมูล
    Else
        ' การรับค่าด้วยตัวแปรจากฟอร์มหลักที่เรียกมา โดยการอ้างอิงไปที่ MS Flex Grid
        CusPK = Val(frmMainCustomer.fgCustomer.Text)
        ' แสดงผลรายการตาม Primary Key ที่ส่งมา
        Call RecordToScreen
    End If
End Sub

'การแสดงผลรายละเอียดของลูกค้า
Sub RecordToScreen()
Set RS = New Recordset
Statement = "SELECT tblCustomer.*, tblProvince.* " & _
                " FROM tblCustomer INNER JOIN tblProvince ON tblCustomer.ProvinceFK = tblProvince.ProvincePK " & _
                " WHERE [CustomerPK] = " & CusPK

    ' การแสดงผลข้อมูล ให้อ่านข้อมูลแบบเดินหน้า (Forward) และ อ่านอย่างเดียว (ReadOnly) จะทำงานได้เร็ว
    RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
    
    txtCustomerID.Text = "" & RS("CustomerID")
    txtFirstname.Text = "" & RS("Firstname")
    txtLastname.Text = "" & RS("Lastname")
    txtAddress.Text = "" & RS("Address")
    txtAmphur.Text = "" & RS("Amphur")
    cmbProvince.Text = RS("ProvinceName")
    txtAmphur.Text = "" & RS("Amphur")
    txtPostCode.Text = "" & RS("PostCode")
    
    ' การโหลดตำแหน่งภาพแสดงผลใน image control
    ' ตรวจสอบว่ามีการเก็บตำแหน่งภาพหรือไม่
    ' กรณีนี้ ไม่มีข้อมูล
    If IsNull(RS("CustomerPicture")) Or Trim(RS("CustomerPicture")) = "" Then
        ' ตัวแปรเก็บตำแหน่งไฟล์ภาพจะเป็นค่าว่างเปล่า
        PicturePath = ""
        ' นำภาพอะไรก็ได้ มาแสดงให้ผู้ใช้งานเห็นว่าข้อมูลนี้ไม่มีการจัดเก็บภาพไว้
        Image1.Picture = LoadPicture(App.Path & "\NoPicture.jpg")
        cmdDeletePicture.Enabled = False
        
    ' นำตำแหน่งภาพมาทำการแสดงผล พร้อมกับระบุตำแหน่งให้กับตัวแปร PicturePath ไว้รอก่อนด้วย
    ' แต่ปัญหามันจะเกิดขึ้นในวันข้างหน้า หากหาไฟล์ภาพที่ระบุไม่เจอ ทางแก้ก็คือเขียนโค้ดดัก Error
    Else
        PicturePath = RS("CustomerPicture")
        Image1.Picture = LoadPicture(PicturePath)
        cmdDeletePicture.Enabled = True
    End If
    
    ' ปิดตาราง
    RS.Close:    Set RS = Nothing
End Sub

' Load รายการจังหวัดเข้าสู่ ComboBox
Sub DisplayProvince()
    Set DS = New ADODB.Recordset
    Statement = "SELECT * FROM tblProvince ORDER BY ProvincePK"
    Set DS = ConnDB.Execute(Statement, , adCmdText)
    cmbProvince.Clear
    Do Until DS.EOF
        ' การใส่ "" ไว้ เพื่อป้องกัน Run Time Error 94 ... นั่นคือ ProvinceName อาจเป็นค่าว่าง (Null)
        cmbProvince.AddItem "" & Trim(DS("ProvinceName"))
        DS.MoveNext
    Loop
    DS.Close:    Set DS = Nothing
End Sub


การ Browse ข้อมูลภาพตามที่เราระบุประเภท หรือ ชนิดไฟล์ภาพ

โค้ดในการ Browse ภาพออกมา

Private Sub cmdBrowse_Click()
On Error Resume Next ' ไม่สน Error ใดๆทั้งสิ้น
    With dlgOpenFile
        .FileName = ""
        .DialogTitle = " เลือกไฟล์ภาพ - Graphics File Format " ' แสดง Title Bar
        .Filter = "ไฟล์ภาพ (*.jpg;*.gif;*.bmp)|*.jpg;*.gif;*.bmp"   ' ประเภทของรูปภาพ
        .CancelError = True ' ยกเลิกทุกๆความผิดพลาด ไม่สนว่างั้นเหอะ ... พี่น้อง
        .ShowOpen ' เปิด Dialog ขึ้นมาเพื่อเลือกไฟล์
    End With
    
    ' การโหลดภาพที่ต้องการจาก Disk เข้ามา
    '  เลือกไฟล์ได้แล้วก็ให้นำไปใส่ไว้ในตัวแปรแบบ Full Path
    PicturePath = dlgOpenFile.FileName
    ' หากไม่มีการเลือกไฟล์ภาพเข้ามา ก็ให้เด้งออกจากโปรแกรมย่อยไปเลย
    If Trim(PicturePath) = "" Or Len(PicturePath) = 0 Then Exit Sub

    ' ให้ image1 แสดงผลภาพ
    Image1.Picture = LoadPicture(PicturePath)
    ' เปิดปุ่มลบภาพไว้ ... เพื่อให้เคลียร์ภาพออกได้
    cmdDeletePicture.Enabled = True

End Sub

' ส่วนของการลบภาพออก
Private Sub cmdDeletePicture_Click()
    ' เมื่อลบภาพออกจาก image1
    ' ให้ Full Path เป็นค่าว่าง
    PicturePath = ""
    ' นำภาพ NoPicture.jpg มาแสดงผลแทน ... แต่ตอนเก็บข้อมูลเราไม่เก็บภาพนี้น่ะครับ เพราะ PicturePath = ""
    Image1.Picture = LoadPicture(App.Path & "\NoPicture.Jpg")
    ' ปิดปุ่มลบภาพ ... เนื่องจากไม่มีภาพมาแสดงผล
    cmdDeletePicture.Enabled = False
End Sub
โค้ดโปรแกรมย่อยในการบันทึกข้อมูล - SAVE

Sub SaveData()
Dim CountRec As Long

    Set RS = New ADODB.Recordset
    ' ตัวอย่างนี้ผมไม่ได้ทำปุ่มเพิ่มข้อมูลเอาไว้ ... ส่วนนี้ก็ผ่านไปเลยครับ ให้พิจารณาการแก้ไขข้อมูลอย่างเดียว
    If blnNewData Then
        ' หาค่า Primary Key (CustomerPK) ก่อน ... อย่าลืมต้องจัดเรียงด้วย CustomerPK
        Statement = "SELECT * FROM tblCustomer ORDER BY CustomerPK "
        RS.CursorLocation = adUseClient
        RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
        ' เงื่อนไขแรกแสดงว่ายังไม่มีข้อมูล
        If RS.BOF Or RS.EOF Then
            CountRec = 1
        Else
            RS.MoveLast
            CountRec = RS("CustomerID") + 1
        End If
        RS.Close
        
        Set RS = New ADODB.Recordset
        Statement = "SELECT tblCustomer.*, tblProvince.* " & _
                            " FROM tblCustomer INNER JOIN tblProvince ON tblCustomer.ProvinceFK = tblProvince.ProvincePK " & _
                            " ORDER BY [CustomerPK] "
        RS.Open Statement, ConnDB, adOpenKeyset, adLockOptimistic, adCmdText
        ' นี่คือการ INSERT น่ะครับ
        RS.AddNew
        RS("CustomerPK") = CountRec
        ' ส่วนนี้ไม่มีอะไรมาก ผมอยากจัดรูปแบบของ CustomerID เช่น CUS0000001
        RS("CustomerID") = "CUS" & Right$("0000000" & CountRec, 7)
    
    ' Edit/แก้ไขข้อมูล
    Else
        Statement = "SELECT tblCustomer.*, tblProvince.* " & _
                            " FROM tblCustomer INNER JOIN tblProvince ON tblCustomer.ProvinceFK = tblProvince.ProvincePK " & _
                            " WHERE [CustomerPK] = " & CusPK
        RS.Open Statement, ConnDB, adOpenKeyset, adLockOptimistic, adCmdText
    
    End If
    
    ' Save Data/บันทึกข้อมูล
    ' ผมว่าผมเขียนโค้ดแบบดั้งเดิมเนี่ย มันอ่านง่าย แก้ไข หาจุดบกพร่องได้ง่ายง่ายกว่า INSERT, UPDATE เป็นไหนๆ
    RS("Firstname") = "" & Trim(txtFirstname.Text)
    RS("Lastname") = "" & Trim(txtLastname.Text)
    RS("Address") = "" & Trim(txtAddress.Text)
    RS("Amphur") = "" & Trim(txtAmphur.Text)
    ' ส่วนนี้ต้องระวังให้ดีน่ะครับ เป็นการนำค่าใน ComboBox ไปตรวจสอบหาค่า Primary Key ของรายชื่อจังหวัด
    ' กรณีของตัวเลข ไม่ต้องมาใส่เครื่องหมาย "" ข้างหน้าน่ะครับ
    RS("ProvinceFK") = CheckProvinceName(cmbProvince.Text)
    '
    RS("PostCode") = "" & Trim(txtPostCode.Text)
    RS("Telephone") = "" & Trim(txtTelephone.Text)
    RS("Facsimile") = "" & Trim(txtFacsimile.Text)
    
    ' เก็บข้อมูลตำแหน่ง และ ชื่อไฟล์ภาพไว้จากค่าตัวแปร
    RS("CustomerPicture") = "" & PicturePath
    
    RS.Update
    
    ' บอกฟอร์มหลักว่าเกิดการเปลี่ยนแปลงข้อมูล
    FormUpdate = True
    MsgBox "บันทึกข้อมูลเรียบร้อย", vbOKOnly + vbInformation, "รายงานสถานะ"
    RS.Close:    Set RS = Nothing
    Set frmCustomer = Nothing
    Unload Me
    
End Sub

' ส่งค่าชื่อตาราง กับ ชื่อของ Combo Box
' การตรวจสอบชื่อจังหวัดจาก ComboBox เพื่อค้นหาค่า ProvincePK แล้วส่งค่าคืนกลับไป
Function CheckProvinceName(ComboText As String) As Integer
        Set DS = New ADODB.Recordset
        ' เปรียบเทียบค่า Text ใน ComboBox ... แต่ต้องการผลที่ได้เป็น ProvincePK เพื่อนำไปบันทึกข้อมูล
        Statement = "SELECT * FROM tblProvince " & "  WHERE [ProvinceName] = " & "'" & ComboText & "'"
        DS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
        If DS.BOF And DS.EOF Then
            ' หากไม่พบให้ Return ค่ากลับเป็น 0
            ' จากตารางข้อมูลค่า ProvincePK = 0 คือ ไม่ระบุ น่ะครับ ... พี่น้อง
            ' ดังนั้นในตารางข้อมูลคุณต้องกำหนดค่าเป็น 0 ไว้รอไว้ด้วย
            CheckProvinceName = 0
        Else
            ' ส่งค่า ProvincePK กลับไปเก็บลงฐานข้อมูล
            CheckProvinceName = DS("ProvincePK")
        End If
        DS.Close: Set DS = Nothing
End Function
Conclusion:
โจทย์ข้อนี้มันไม่ได้เป็นเรื่องยากหรอกครับ เราต้องทำความเข้าใจในหลักการของมันให้ดีเสียก่อน จากนั้นก็เรียงตามขั้นตอนของมันไปเลย เพียงแต่ว่ามันต้องมีความเกี่ยวข้องกับอีกหลายๆเรื่อง ซึ่งเห็นเวลาน้องๆนักศึกษาไปโพสต์ถามตามเว็บไซต์ต่างๆ มันก็ยากที่จะหาคนมาตอบให้ได้ นั่นมันหมายถึงต้องเอาโค้ดจริงๆมาให้ดูกันเลยทีเดียว ... ไม่ต่างอะไรไปจากการที่บางคนติดต่อเข้ามาให้ผมเขียนโปรแกรม แล้วเอารูปแบบการพิมพ์ใบเสร็จสั้นๆ กระจิ๊ดริ๊ด มาให้ผมดูเป็นตัวอย่างว่าอยากได้แบบนี้น่ะ พอผมบอกราคาไป กลับหาว่าแพง เขาบอกว่าไปถามนักศึกษาปี 4 เด็กมันรับเขียนแค่ 4 พันบาท ไอ้เราก็ถามกลับไปทันที แล้วทำไมคุณไม่จ้างเขาล่ะ จะมาจ้างผมทำไม 55555+ จบเลยแบบนี้ ... เพราะสิ่งที่เห็นน่ะ เวลาออกแบบ และ ลงโค้ดมันไม่ได้ง่ายๆแบบนั้น (นี่หว่า) มันต้องไปเกี่ยวพันกับตารางข้อมูลอื่นๆอีก เอ้อ หากให้พิมพ์ใบเสร็จออกมาได้ แล้วไม่เก็บข้อมูลเลย จะรับทำให้สักพันก็พอ (ถือเป็นค่าเหล้า) ... เอิ๊กๆๆๆๆ

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