thongkorn โพสต์ 2017-11-16 16:55:25

[VB.NET] แจกฟรีโค้ด ActiveReports.NET การพิมพ์ใบแจ้งค่าใช้จ่าย สำหรับหอพัก ห้องเช่า อพาร์ทเมนท์ แบบกระดาษครึ่ง A4

http://www.g2gnet.com/webboard/images/vbnet/RentRoom.png
หลายวันก่อนก็แจกเป็นโปรแกรมไปเรียบร้อย (สามารถดาวน์โหลดได้ที่นี่) วันนี้มาแจกเป็นโค้ดเพื่อให้ได้นำไปศึกษาเรียนรู้กันครับผม โค้ด Visual Basic .Net ที่อ่านข้อมูลจาก Excel หรือการ Import ข้อมูลจากเวิร์คชีตของตาราง Excel เข้ามาสู่ตารางกริด จากนั้นก็นำผลไปพิมพ์เป็นใบแจ้งหนี้ หรือใบแจ้งค่าใช้จ่ายด้วย ActiveReports .Net (AR)...

สำหรับการพิมพ์รายงานแบบนี้ค่อนข้างจะแปลกประหลาดไปจากที่หลายๆคนอาจจะเคยเห็นๆมา เพราะว่าเป็นการนำเอาข้อมูลจากหลักมาพิมพ์ในแนวแถวแทน โดยพิจารณาจากภาพประกอบด้านบนซึ่งเป็น Excel เริ่มต้นจากหลักที่ 3 (Index = 2) หรือหลัก C เราเอาค่าในเซลล์ C1 มาพิมพ์ลง Detail ของ AR ในแถวแรก จากนั้นเลื่อนแถวถัดไปคือเซลล์ C2 (จำนวนเงิน) แต่กลับเอามาพิมพ์ต่อในแถวเดิม แต่เลื่อนหลักไป ... งงมั้ยครับ 5555+ ... คือต้องไปดูที่โค้ดในส่วนโปรแกรมย่อย Detail ของ AR แล้วต้องทำการ Debugger จะทำให้คุณเข้าใจได้ชัดเจนขึ้นครับ ...

หัวข้อที่เกี่ยวข้อง ...
การเรียกใช้งาน ActiveReports .NET แบบเบื้องต้น
ก้าวแรกกับการพิมพ์รายงานด้วย ActiveReports .NET
พื้นฐานการพิมพ์รายงานด้วย ActiveReports .NET ลงบนกระดาษขนาด A4

แอดมินได้อธิบายรายละเอียด ActiveReports (AR) ไล่เรียงกันมาตามหัวข้อด้านบนแล้ว ดังนั้นจึงจะไม่ขออธิบายเพิ่มเติมล่ะกันครับผม ... สำหรับบทความนี้เราจะไม่ใช้งาน Excel Object แต่เป็นการใช้ OLEDB เพื่อจัดการหรือติดต่อกับไฟล์ Excel file แทน

มาดูโค้ดในส่วนของการ Import ไฟล์ Excel ด้วยการติดต่อผ่าน ADO.NET ... นั่นคือเราจะมอง Excel เป็นเสมือนไฟล์ฐานข้อมูล
    ' / --------------------------------------------------------------------
    ' / เลือกไฟล์ Excel เข้ามา
    Private Sub btnBrowse_Click(sender As System.Object, e As System.EventArgs) Handles btnBrowse.Click
      ' ประกาศใช้งาน Open File Dialog ในแบบ Run Time
      Dim dlgOpenFile As OpenFileDialog = New OpenFileDialog()

      ' / ตั้งค่าการใช้งาน Open File Dialog
      With dlgOpenFile
            .InitialDirectory = MyPath(Application.StartupPath)
            .Title = "เลือกไฟล์ MS Excel"
            .Filter = "MS Excel Files (*.xlsx;*.xls)|*.xlsx;*xls"
            .FilterIndex = 1
            .RestoreDirectory = True
      End With
      ' / หากเลือกปุ่ม OK หลังจากการ Browse ...
      If dlgOpenFile.ShowDialog() = DialogResult.OK Then
            txtFileName.Text = dlgOpenFile.FileName
            Dim strConn As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
                dlgOpenFile.FileName & "; Extended Properties=""Excel 12.0 Xml; HDR=YES"";"
            Dim Conn As New OleDbConnection(strConn)
            Conn.Open()
            ' / มอง WorkSheet ให้เป็นตารางข้อมูล (Table)
            Dim dtSheets As DataTable = Conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, Nothing)
            Dim drSheet As DataRow

            cmbSheetName.Items.Clear()
            ' / นำรายชื่อ WorkSheet ทั้งหมด มาเก็บไว้ที่ ComboBox เพื่อรอให้ User เลือกนำไปใช้งาน
            For Each drSheet In dtSheets.Rows
                cmbSheetName.Items.Add(drSheet("TABLE_NAME").ToString())
            Next
            Conn.Close()
            '//
            dgvData.Columns.Clear()
      End If

    End Sub
โค้ดในการติดต่อกับ WorkSheet ... เรามองเวิร์คชีตเป็นเหมือนตารางข้อมูล (Table)
    ' / --------------------------------------------------------------------
    ' / เลือก WorkSheet เพื่อนำข้อมูลมาแสดงผลในตารางกริด
    Private Sub cmbSheetName_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles cmbSheetName.SelectedIndexChanged
      Dim Conn As OleDbConnection
      Dim Cmd As OleDbCommand
      Dim DAP As OleDbDataAdapter
      Dim DS As DataSet

      Dim strConn As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & _
            txtFileName.Text & "; Extended Properties=""Excel 12.0 Xml; HDR=YES"";"
      Try
            Conn = New OleDbConnection
            Conn.ConnectionString = strConn
            Cmd = New OleDbCommand
            '// เสมือน WorkSheet เป็น Table ในฐานข้อมูล
            Cmd.CommandText = "Select * FROM [" & cmbSheetName.Text & "]"
            Cmd.Connection = Conn
            DAP = New OleDbDataAdapter(Cmd)
            DS = New DataSet
            Conn.Open()
            DAP.Fill(DS, "MySheet")
            '// ผูกข้อมูล (Bound Data)
            dgvData.DataSource = DS.Tables("MySheet")
            Call InitGrid()
      Catch ex As Exception
            MessageBox.Show(ex.Message)
      Finally
            Conn = Nothing
            Cmd = Nothing
            DAP = Nothing
            DS = Nothing
      End Try
    End Sub
โค้ดในส่วนของการผูก ActiveReports Designer เข้ากับ ARViewer
    ' / --------------------------------------------------------------------
    Private Sub dgvData_DoubleClick(sender As Object, e As System.EventArgs) Handles dgvData.DoubleClick
      If dgvData.Rows.Count <= 0 Then Exit Sub
      ' Instance name ARDesigner มันจะชี้ไปที่ไฟล์ arRentRoomBill.vb
      Dim rpt As New arRentRoomBill
      ' โหลดรายงาน document (arRentRoomBill) เข้าสู่ ActiveReports Viewer
      '// Zoom 95%
      Me.Viewer1.ReportViewer.Zoom = 0.95
      Me.Viewer1.Document = rpt.Document
      ' Run Report
      rpt.Run()
    End Sub
โค้ดในการตั้งค่าการพิมพ์ให้กับ ActiveReports Designer ...
    ' / --------------------------------------------------------------------
    ' / ก่อนเริ่มการพิมพ์มาตั้งค่าให้ Report ก่อน
    Private Sub arRentRoomBill_ReportStart(sender As Object, e As System.EventArgs) Handles Me.ReportStart
      '/ การตั้งค่าหน้ากระดาษ
      With PageSettings
            ' หน่วยวัดเป็นนิ้ว
            .Margins.Left = CmToInch(1) ' แปลงค่า 1.0 ซม. เป็นนิ้ว
            .Margins.Right = 0.1
            .Margins.Top = 0.5
            .Margins.Bottom = 0.2
            ' ตั้งค่ากระดาษแนวตั้ง
            .Orientation = PageOrientation.Portrait
            ' กระดาษขนาด A4
            '.PaperKind = Drawing.Printing.PaperKind.A4
            ' กรณีที่กำหนดขนาดกระดาษเอง
            .PaperKind = Drawing.Printing.PaperKind.Custom
            .PaperWidth = CmToInch(21) ' 21 ซม.
            .PaperHeight = CmToInch(14.8)
      End With
      '/ ปกติต้องเคลียร์ค่าต่างๆของ TextBox ก่อนการพิมพ์
      txtItem.Text = ""
      txtDesc.Text = ""
      txtHeader.Text = ""
      txtUnitPrice.Text = ""
      txtQTY.Text = ""
      txtAmount.Text = ""
      txtGrandTotal.Text = ""
      '// แสดงกิจการและที่อยู่ โดยการอ่านค่าจาก INI (Initialized File)
      Dim strFileINI As String = MyPath(Application.StartupPath) & "Config.ini"
      If My.Computer.FileSystem.FileExists(strFileINI) Then
            txtOwner.Text = ReadIni(strFileINI, "Config", "Owner", "")
            txtAddress.Text = ReadIni(strFileINI, "Config", "Address", "")
            txtHeader.Text = ReadIni(strFileINI, "Config", "Header", "")
            lblRemark1.Text = ReadIni(strFileINI, "Config", "Remark1", "")
            lblRemark2.Text = ReadIni(strFileINI, "Config", "Remark2", "")
            '// กรณีไม่เจอ ให้เริ่มต้นค่าใหม่
      Else
            txtOwner.Text = "ทองก้อน ฮาเร็ม อพาร์ทเมนท์"
            txtAddress.Text = "123/456 ถ.กลางเมือง ต.เมืองเก่า อ.เมือง จ.ขอนแก่น โทร.043-XXX-XXX"
            txtHeader.Text = "- ใบแจ้งค่าใช้จ่าย -"
            lblRemark1.Text = " กรุณาชำระเงินภายในวันที่ 32 ของทุกเดือน"
            lblRemark2.Text = " การเงินมีปัญหา ใส่ชุดนักศึกษามาหาป๋าทองก้อนได้ตลอด 24 ชั่วโมง"
      End If
      txtDate.Text = FormatDateTime(Now(), DateFormat.GeneralDate)
      '// อ่านค่าชื่อ WorkSheet มาพิมพ์ประจำเดือน (ตัวอย่าง "สิงหาคม 2560")
      Dim strMonth As String = frmMainBill.cmbSheetName.Text
      '// ตัดคำที่ไม่ต้องการคือ $
      strMonth = strMonth.Replace("'", "").Replace("[      DISCUZ_CODE_3      ]quot;, "")
      txtDateReciept.Text = strMonth

      '// รับค่า "แถว" ที่ถูกเลือกในตารางกริด
      sRow = frmMainBill.dgvData.CurrentRow.Index
      '// หลักแรกกับหลักที่ 2
      txtCname.Text = frmMainBill.dgvData.Rows(sRow).Cells(0).Value
      txtRoomNo.Text = frmMainBill.dgvData.Rows(sRow).Cells(1).Value
    End Sub
โค้ดในส่วนของการพิมพ์รายละเอียด ... ขอให้สังเกตว่า ข้อมูลการพิมพ์มันจัดเรียงต่อกันในแนวนอน แต่จริงๆเราจะต้องเอาทีละหลักมาพิมพ์
    ' / --------------------------------------------------------------------
    Private Sub Detail1_Format(sender As Object, e As System.EventArgs) Handles Detail1.Format
      '// ItemNo หรือลำดับที่ โดยจะเริ่มจาก 1
      txtItem.Text = ItemNo
      With frmMainBill
            '// อ่านค่าเริ่มจากหลัก 2 ดังนั้น ItemNo จึงต้อง +1 เพื่ออ่านค่าจาก Header มาแสดงผล
            '// โดยเรียงตามลำดับ --> ค่าเช่าห้อง(หลักที่ 2), ค่าไฟฟ้า(3), ค่าน้ำ(4), ค่าอินเทอร์เน็ต(5), ค่าเคเบิ้ลทีวี(6) และค่าเก็บขยะ(7)
            txtDesc.Text = .dgvData.Columns(ItemNo + 1).HeaderText
            txtQTY.Text = "1"
            '// อ่านค่าข้อมูลจากแถวที่เลือกมา (sRow) และข้อมูลอยู่ในหลัก 2 (และเลื่อนหลักถัดๆไป)
            txtUnitPrice.Text = Format(Val(.dgvData.Rows(sRow).Cells(ItemNo + 1).Value), "#,##0.00")
            txtAmount.Text = txtUnitPrice.Text
      End With
      ' รวมจำนวนเงินผ่านทางตัวแปร
      GrandTotal = GrandTotal + CDbl(txtUnitPrice.Text)
      txtGrandTotal.Text = "รวมเงิน: " & Format(GrandTotal, "#,##0.00") & " บาท."
    End Subส่วนสำคัญ ... ต้องใจเย็นๆช้าๆในการไล่แกะและทำความเข้าใจกับโค้ดครับ เพราะเป็นการอ่านค่าจากแถวใดแถวหนึ่ง (sRow) ที่เลือกขึ้นมา แต่ข้อมูลที่จะพิมพ์จะไล่ไปทีละหลัก คืออ่านค่าข้อมูลในแนวนอนตั้งแต่หลักที่ 2 (ค่า Index) แต่เอาข้อมูลในหลักนั้นมาพิมพ์ทีละแถวเรียงลงไปแทน ...

โค้ดในส่วนของการตรวจสอบว่าหมดข้อมูล (จำนวนหลัก) ที่จะพิมพ์แล้วหรือยัง ...
    ' ตัวแปรนี้ต้องประกาศเป็นแบบ Public (เฉพาะ arRoomReciept) เพื่อให้ส่วนของ Detail1_Format และ FetchData มองเห็นด้วย
    Private ItemNo As Integer
    Private GrandTotal As Double
    '// เลือกจากแถวในตารางกริด
    Private sRow As Integer

    ' / --------------------------------------------------------------------
    ' / จะเกิดการนับตามจำนวนหลักคือ 6 หลัก ข้อมูลการพิมพ์ก็จะหมด eArgs.EOF = True
    Private Sub arRentRoomBill_FetchData(sender As Object, eArgs As DataDynamics.ActiveReports.ActiveReport.FetchEventArgs) Handles Me.FetchData
      ItemNo = ItemNo + 1
      '/ ตรวจสอบจำนวนการพิมพ์ทั้งหมด ซึ่งจะมีทั้งหมด 6 หลัก
      '/ 2 หลักแรกคือ ชื่อผู้เช่า (0) และ หมายเลขห้อง (1) เราพิมพ์ที่ PageHeader ไปแล้ว ก็ให้ข้ามไป
      '/ หลักที่ต้องนำมาพิมพ์ตามแถวเรียงตามลำดับ --> ค่าเช่าห้อง(หลักที่ 2), ค่าไฟฟ้า(3), ค่าน้ำ(4), ค่าอินเทอร์เน็ต(5), ค่าเคเบิ้ลทีวี(6) และค่าเก็บขยะ(7)
      If ItemNo > 6 Then
            '/ หากหมดแล้วก็จบการพิมพ์
            eArgs.EOF = True
            Exit Sub
            '/ ยังไม่หมดข้อมูล
      Else
            eArgs.EOF = False
      End If
    End Subกรณีที่จำนวนหลักในไฟล์ Excel เปลี่ยนแปลงไปไม่ตรงกับตัวอย่าง ... แอดมินวางยาเอาไว้แถวๆนี้แหละ หากเข้าใจในตัวโค้ดก็จะแก้ปัญหาได้ครับ อิอิอิอิ

สำหรับโค้ดเรื่องของ Initialize File หรือ INI แอดมินขอแยกมาอยู่อีกหัวข้อหนึ่งล่ะกันครับ การประยุกต์ใช้งานไฟล์ INI (Initialize File) มาทำการเก็บข้อมูลขนาดเล็ก   

ดาวน์โหลดโค้ดต้นฉบับแบบเต็ม VB.NET (2010) ได้ที่นี่

MrDen โพสต์ 2017-11-17 17:22:09

ขอบคุณครับ

paper20 โพสต์ 2019-6-21 23:47:36

ขอบคุณครับ

komenservice โพสต์ 2020-2-20 10:24:12

ขอบคุณครับ

hot2 โพสต์ 2020-6-25 20:00:20

เริ่ม VB.Net อีกครั้ง(ไม่รู้ครั้งที่เท่าไหร่ครับเฮีย 55555)
หน้า: [1]
ดูในรูปแบบกติ: [VB.NET] แจกฟรีโค้ด ActiveReports.NET การพิมพ์ใบแจ้งค่าใช้จ่าย สำหรับหอพัก ห้องเช่า อพาร์ทเมนท์ แบบกระดาษครึ่ง A4