ผู้เขียน หัวข้อ: [VB.Net] โค้ดโปรแกรมการคำนวณหาเกรดเฉลี่ยและส่งออกข้อมูล DataGrid ไปยังไฟล์ Excel  (อ่าน 167 ครั้ง)

ออฟไลน์ ทองก้อน ทับทิมกรอบ

  • Administrator
  • *****
  • กระทู้: 245
  • เพศ: ชาย
  • Webmaster G2GNet
ต่อเนื่องจากตอนที่แล้ว [VB.Net] โค้ดโปรแกรมการคำนวณหาเกรดเฉลี่ย (GPA) - DataGridView Control @Run Time และ [VB.Net] เรียนรู้และใช้ DisplayMember/ValueMember ใน ComboBox Control ให้ลึกซึ้ง ... ขั้นตอนต่อไปในการฝึกคิด ฝึกทำ โดยการพยายามตั้งโจทย์ที่มันไม่มีอยู่ในหนังสือ ก็คือการส่งข้อมูลจากตารางกริดออกไปยังไฟล์ MS Excel (หรือการทำรายงานด้วย ActiveReports.Net ซึ่งท่านสามารถนำไปคิดพัฒนาล่วงหน้าเองได้เลย) ...

หลายคนคงอาจจะมีคำถามว่าทำไมแอดมินถึงนำพาให้เขียนโค้ดแบบยากจัง ทำไมไม่ลากๆมาวางแปะๆๆ กำหนดคุณสมบัติโน่นนั่นนี่ก็พอแล้วมั้ง ... ลองพิจารณาให้ดีๆนะครับ จากการเขียนโค้ดจะทำให้เราอ่านแล้วเข้าใจ โดยไม่ต้องมาจดจำ มิหนำซ้ำจากโค้ดมันจะนำพาเราให้เห็นถึงกลวิธี (Method) ต่างๆในการควบคุมบรรดา Control เหล่านี้ได้ ... เอาน่าลองดูครับ สู้ๆ


หน้าตาโปรแกรมจาก DataGridViewX ของ DotNetBar 12.8.0.20 ซึ่งใช้โค้ดเดียวกันกับ DataGridView ของไมโครซอฟท์
(ดาวน์โหลด DotNetBar จากเว็บไซต์ผู้ผลิต)


เมื่อคลิ๊กปุ่มคำสั่งในการส่งออกไปไฟล์ Excel ... ท่านสามารถนำไปคิดต่อได้อีกแหละ จะจัดรูปแบบ (Format) แต่ละเซลล์ให้สวยงามได้อย่างไร

เริ่มต้นกระบวนการ


ต้อง Add References MS Excel 12.0 Object Library (หรือ Office2007) เข้ามาก่อน

และในฟอร์มก็ต้องสั่ง Imports เข้ามาด้วย
โค๊ด: [Select]
Imports Excel = Microsoft.Office.Interop.Excel

เริ่มต้นค่าต่างๆให้กับตารางกริด (DataGridView Control) ในแบบ Run Time

โค๊ด: [Select]
    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        InitializeGrid()
        '// ข้อมูลตัวอย่าง
        FillDataSample()
        '// ปรับปรุงข้อมูล
        UpdateRow()
    End Sub

    Private Sub InitializeGrid()
        '// Declare columns type.
        '// TextBox
        Dim Column1 As New DataGridViewTextBoxColumn()
        Dim Column2 As New DataGridViewTextBoxColumn()
        '// ComboBox
        Dim Column3 As New DataGridViewComboBoxColumn()
        Dim Column4 As New DataGridViewComboBoxColumn()
        '//
        Dim Column5 As New DataGridViewTextBoxColumn()
        '// Add new Columns
        dgvData.Columns.AddRange(New DataGridViewColumn() { _
                Column1, Column2, Column3, Column4, Column5 _
                })
        '// Or use this style
        'With dgvData
        '.Columns.Add(Column1)
        '.Columns.Add(Column2)
        '.Columns.Add(Column3)
        '.Columns.Add(Column4)
        '.Columns.Add(Column5)
        'End With

        '// Startup
        With Column1
            '// ประกาศชื่อ (Name) เอาไว้สำหรับการอ้างอิงถึง (แทนการใช้ Index หากขี้เกียจนับค่าหลัก)
            .Name = "SubjectID"
            .HeaderText = "รหัสวิชา"
            .Width = dgvData.Width \ 5 - 30
        End With
        With Column2
            .Name = "SubjectName"
            .HeaderText = "ชื่อรายวิชา"
            .Width = dgvData.Width \ 5 + 20
        End With
        With Column3
            .Name = "Credit"
            .HeaderText = "หน่วยกิต"
            '// กำหนดจำนวนหน่วยกิต
            .Items.AddRange(New Object() {"1", "2", "3", "4", "5", "6"})
            .Width = dgvData.Width \ 5 - 40
            .HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight
            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
        End With
        With Column4
            .Name = "Grade"
            .HeaderText = "เกรด"
            '// กำหนดค่าเกรด (5 เกรด)
            .Items.AddRange(New Object() {"A", "B+", "B", "C+", "C", "D+", "D", "F"})
            '// Alignment
            .HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight
            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
            .Width = 60
        End With
        With Column5
            .Name = "Point"
            .HeaderText = "หน่วยกิต x เกรด"
            .HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter
            .DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter
            .DefaultCellStyle.Format = "n2"
            .Width = dgvData.Width \ 5 + 35
            .ReadOnly = True
        End With

        '// Sample coding with Run-Time
        With dgvData
            '.RowHeadersVisible = False
            .AllowUserToAddRows = True
            .AllowUserToDeleteRows = True
            .AllowUserToResizeColumns = True
            .AllowUserToResizeRows = True
            .SelectionMode = DataGridViewSelectionMode.FullRowSelect
            .MultiSelect = False
            '// Data rows
            .Font = New Font("Tahoma", 8.5)
            .RowTemplate.MinimumHeight = 20
            .RowTemplate.Height = 26
            '// Column Header
            .ColumnHeadersHeight = 30
            .ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing
            '// Header Own Styles
            With .ColumnHeadersDefaultCellStyle
                .BackColor = Color.Navy
                .ForeColor = Color.Black
                .Font = New Font("Tahoma", 8.5, FontStyle.Bold)
            End With
        End With
    End Sub

ตัวอย่างข้อมูลที่ใช้ในการทดสอบ (จะได้ไม่ต้องมานั่งคลิ๊กหรือป้อนค่าให้เมื่อยมือ)

โค๊ด: [Select]
    '// Sample Data
    Private Sub FillDataSample()
        Dim row As String() = New String() {"123-456", "ไมโครโปรเซสเซอร์", "3", "A", ""}
        dgvData.Rows.Add(row)
        row = New String() {"456-123", "Basic Progamming", "3", "B+", ""}
        dgvData.Rows.Add(row)
        row = New String() {"001-100", "การพัฒนาเว็บไซต์", "3", "C+", ""}
        dgvData.Rows.Add(row)
        row = New String() {"000-000", "ระบบเครือข่าย", "3", "D", ""}
        dgvData.Rows.Add(row)
        row = New String() {"999-999", "การพัฒนาภาษาคน", "3", "F", ""}
        dgvData.Rows.Add(row)
    End Sub

เหตุการณ์คลิ๊กเลือกรายการจาก ComboBox Control

โค๊ด: [Select]
    Private Sub dgvData_CellValueChanged( _
                                        sender As Object, _
                                        e As System.Windows.Forms.DataGridViewCellEventArgs _
                                        ) Handles dgvData.CellValueChanged
        If e.RowIndex < 0 Then Exit Sub
        '// Update each rows but only column 2-3
        Select Case e.ColumnIndex
            Case 2, 3
                UpdateRow()
        End Select
        '// ---------------------
    End Sub

การอัพเดตข้อมูลที่มีการเปลี่ยนแปลงในตารางกริด

โค๊ด: [Select]
    ' / ------------------------------------------------------------------
    '// หากมีการเปลี่ยนแปลงค่าในแต่ละเซลล์ก็ทำการปรับปรุงข้อมูลใหม่
    Private Sub UpdateRow()
        Dim nRow As Integer
        '// นำค่าหน่วยกิต ไปคูณกับค่าเกรด โดยที่ค่าเกรด (A-F) จะถูกแปลงไปเป็นค่าตัวเลขก่อน (4-0) ฟังค์ชั่น GradeToPoint
        For nRow = 0 To dgvData.Rows.Count - 1
            dgvData.Rows(nRow).Cells(4).Value = dgvData.Rows(nRow).Cells(2).Value * _
                GradeToPoint(dgvData.Rows(nRow).Cells(3).Value)
        Next
        '//
        Dim SumCredit As Integer
        Dim SumPoint As Double
        '// หาผลรวมทั้งหมดของจำนวนหน่วยกิต
        For nRow = 0 To dgvData.RowCount - 1
            '// หลักที่ 3 เมื่อ Index = 2
            SumCredit = SumCredit + dgvData.Rows(nRow).Cells(2).Value
        Next
        txtSumCredit.Text = SumCredit
        '// หาผลรวมทุกๆแถวของหน่วยกิต x เกรด
        For nRow = 0 To dgvData.RowCount - 1
            '// หลักที่ 5 เมื่อ Index = 4
            If IsNumeric(dgvData.Rows(nRow).Cells(4).Value) Then
                SumPoint = SumPoint + dgvData.Rows(nRow).Cells(4).Value
            End If
        Next
        txtSumPoint.Text = SumPoint.ToString("#,##0.00")
        '// Final
        txtGPA.Text = (SumPoint / SumCredit).ToString("#,##0.00")
    End Sub

ฟังค์ชั่นที่ใช้ในการแปลงค่าตัวอักขระ หรือเกรด A - F ให้กลายเป็นตัวเลข เพื่อนำไปใช้ในการคำนวณ

โค๊ด: [Select]
    ' / --------------------------------------------------------------------------------
    '// รับค่าเกรด A - F เข้ามาแล้วแปลงเป็นตัวเลข
    '// ส่งค่ากลับเป็น Double
    Private Function GradeToPoint(ByVal Grade As String) As Double
        GradeToPoint = 0
        Select Case Grade
            Case "A"
                GradeToPoint = 4
            Case "B+"
                GradeToPoint = 3.5
            Case "B"
                GradeToPoint = 3
            Case "C+"
                GradeToPoint = 2.5
            Case "C"
                GradeToPoint = 2
            Case "D+"
                GradeToPoint = 1.5
            Case "D"
                GradeToPoint = 1
            Case "F"
                GradeToPoint = 0
        End Select
    End Function

เหตุการณ์กดปุ่มเพื่อนำค่าในเซลล์ต่างๆของตารางกริด ส่งไปยังไฟล์ Excel และทำการบันทึกด้วย

โค๊ด: [Select]
    ' / ------------------------------------------------------------------
    '// Export to Excel File
    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        Dim xlsApp As New Excel.Application

        ' Declare Save File Dialog Control @Run Time
        Dim dlgExcelFile As SaveFileDialog = New SaveFileDialog

        Dim strPath As String = MyPath(Application.StartupPath)
        ' / Initialize Open File Dialog
        With dlgExcelFile
            .InitialDirectory = strPath
            .Title = "Save as Excel File"
            .Filter = "Save Excel (2003)|*.xls|Save Excel (2007)|*.xlsx"
            .FilterIndex = 2
            .RestoreDirectory = True
        End With

        ' Select OK
        If dlgExcelFile.ShowDialog() = DialogResult.OK Then

            xlsApp.SheetsInNewWorkbook = 1

            Dim xlsWorkBook As Excel.Workbook = xlsApp.Workbooks.Add
            Dim xlsWorkSheet As Excel.Worksheet = xlsWorkBook.Worksheets.Item(1)
            xlsWorkSheet.Name = "SampleExport"

            '// Export Header Names Start
            Dim ColCount As Integer = dgvData.Columns.Count
            For Each column In dgvData.Columns
                xlsWorkSheet.Cells(1, column.Index + 1).Value = column.Name
            Next
            '// Export Each Row Start
            Dim nRow As Integer
            For nRow = 0 To dgvData.Rows.Count - 1
                Dim columnIndex As Integer = 0
                Do Until columnIndex = ColCount
                    xlsWorkSheet.Cells(nRow + 2, columnIndex + 1).Value = dgvData.Item(columnIndex, nRow).Value
                    columnIndex += 1
                Loop
            Next
            '// Summary GPA calculation.
            nRow = dgvData.Rows.Count + 3
            xlsWorkSheet.Cells(nRow, 5).value = txtSumPoint.Text
            xlsWorkSheet.Cells(nRow + 1, 5).value = txtSumCredit.Text
            xlsWorkSheet.Cells(nRow + 2, 5).value = txtGPA.Text
            '// Don't Alert something
            xlsApp.DisplayAlerts = False
            '// Save Excel File and see Workbook.SaveAs Method at link below ...
            '// https://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.workbook.saveas.aspx?f=255&MSPPError=-2147217396
            'Sub SaveAs (
            '   Filename As Object,
            '   FileFormat As Object,
            '   Password As Object,
            '   WriteResPassword As Object,
            '   ReadOnlyRecommended As Object,
            '   CreateBackup As Object,
            '   AccessMode As XlSaveAsAccessMode,
            '   ConflictResolution As Object,
            '   AddToMru As Object,
            '   TextCodepage As Object,
            '   TextVisualLayout As Object,
            '   Local As Object
            ')
            xlsWorkBook.SaveAs( _
                dlgExcelFile.FileName, _
                Excel.XlFileFormat.xlWorkbookDefault, _
                Type.Missing, _
                Type.Missing, _
                Type.Missing, _
                Type.Missing, _
                Excel.XlSaveAsAccessMode.xlNoChange, _
                Excel.XlSaveConflictResolution.xlLocalSessionChanges _
                )
            xlsWorkBook.Close()
            xlsApp.Quit()

            '// Open Excel File
            OpenFileExcel(dlgExcelFile.FileName)

            '// Release memory.
            ReleaseObject(xlsApp)
            ReleaseObject(xlsWorkBook)
            ReleaseObject(xlsWorkSheet)
        End If
    End Sub

โปรแกรมย่อยในการคืนค่าหน่วยความจำ

โค๊ด: [Select]
    ' / ------------------------------------------------------------------
    '// คืนหน่วยความจำกลับคืนสู่ระบบ
    Private Sub ReleaseObject(ByVal obj As Object)
        Try
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
            obj = Nothing
        Catch ex As Exception
            obj = Nothing
        Finally
            '// GC = Garbage Collection
            GC.Collect()
        End Try
    End Sub

โปรแกรมย่อยที่สั่งให้เปิดไฟล์ MS Excel

โค๊ด: [Select]
    ' / ------------------------------------------------------------------
    Private Sub OpenFileExcel(ByVal FilePath As String)
        Dim p As New Process
        '// Call Start Program
        p.StartInfo.FileName = "Excel.exe"
        If Not FilePath.StartsWith(Chr(34)) Then _
            FilePath = Chr(34) & FilePath & Chr(34)
        '// Arguments
        p.StartInfo.Arguments = FilePath
        p.Start()
    End Sub

โปรแกรมย่อย (หากิน) ในการกำหนดตำแหน่ง Path ในการเก็บไฟล์

โค๊ด: [Select]
    ' / ------------------------------------------------------------------
    ' / Get my project path
    ' / AppPath = C:\My Project\bin\debug
    ' / Replace "\bin\debug" with "\"
    ' / Return : C:\My Project\
    Function MyPath(AppPath As String) As String
        AppPath = AppPath.ToLower()
        MyPath = AppPath.Replace("\bin\debug", "\")
    End Function

Conclusion: จากโจทย์แบบพื้นๆ หากพิจารณาให้ดีๆ เรายังสามารถนำไปต่อ-ยอดสร้างโจทย์ไหลต่อไปได้อีกครับ ก็ขอให้ไปลองคิดเอาเองล่ะกัน ... นี่คือขั้นตอนของกระบวนการฝึกคิด ฝึกทำในการพัฒนาโปรแกรม

ดาวน์โหลดโค้ดฉบับ Visual Basic .Net (2010) ได้ที่นี่

บันทึกการเข้า
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด

ออฟไลน์ โจ้

  • Newbie
  • *
  • กระทู้: 21

บันทึกการเข้า

ออฟไลน์ Mr.Den

  • Jr. Member
  • **
  • กระทู้: 73
  • เพศ: ชาย
ขอบคุณมากครับ

แข็งแรงแข็งแรง

ไม่เจ็บไม่จนตลอดไป...ครับอาจารย์

บันทึกการเข้า