อาจารย์ของอาจารย์สอนอาจารย์มาก็ใช้ Crystal Report พออาจารย์มาสอนเราก็ใช้ Crystal Report พอเรามาเป็นอาจารย์ก็เอาไอ้เจ้านี่แหละมาสอนลูกศิษย์ต่อไป พอลูกศิษย์จบไปสอน ก็เอาเจ้านี่แหละไปสอนต่ออีก (Forever) ... ก้ากกกก อินโทรแบบกวนๆล่ะรอบนี้ ก็ไม่ได้มีเจตนาไปท้าทายโปรแกรมไฮโซ (ยอดฮิต) ของ Crystal Report หรอกครับ เนื่องจากผมไม่ได้ไปร่ำเรียนทางด้านนี้กะใครเขามานี่นา เพียงแต่อยากจะนำเสนออีกแนวทาง หรือ อีกทางเลือกหนึ่งให้กับพี่น้องทั้งหลายได้รับรู้ และ ประจักษ์แก่สายตากัน มันแปลกด้วยเหรอที่ผมจะทำอะไรที่ไม่เหมือนชาวบ้านชาวเมืองเขา ... เอิ๊กๆๆๆๆ ...
ตอนที่เริ่มต้นใช้งาน Active Report เนี่ย "มันไม่ค่อยสะดวกครับ" ก็เพราะตัวอย่างที่มีมาให้ มันเป็น DAO ทั้งหมด และ แถมผูกติดกับไฟล์ฐานข้อมูลมาด้วย หากทำโปรเจค ADO แล้วมาผสมพันธุ์กับ DAO นี่มันช่างดูกระไรๆเสียจริงๆ ... ยากต่อการควบคุม และ การนำไปใช้งาน ทำให้ไม่มีความยืดหยุ่นมากนัก แต่พอหลังจากเก็บตัวเงียบๆ ไม่ยอมออกไปก๊งเหล้าตามคำเชิญของบรรดาเพื่อนพ้องน้องพี่ (อันนี้ไม่รู้ว่าพวกเขาจะเสียใจ หรือ ดีใจกันแน่) ก็เลยหากลวิธีที่จะพิชิต (หัวใจ) มันให้ได้ ... หลังจากลูบๆคลำๆมันอยู่หลายคืน จนในที่สุดมันก็ท้อง เอ๊ย ก็ได้คำตอบสุดท้ายออกมา ... โธ่เอ๊ย ก็เราไม่เข้าใจกลไก วิธีการทำงาน และ การควบคุมที่แท้จริงของมันเองนี่หว่า ... การค้นพบแสงสว่างในครั้งนี้ จะว่าไปแล้วทางค่าย DataDynamics ต้องมาขอบคุณผมเสียด้วยซ้ำ เหอๆๆๆๆ ... ทะลึ่งทำตัวอย่างออกมาได้ดีกว่าต้นฉบับซ่ะงั้น 55555
หลักการของ Active Report : ทำ Query ข้อมูลในฟอร์มของ Visual Basic จากนั้นผูก RecordSet เข้ากับ ADO Data Control ใน Active Report Designer (DSR) ถัดมาใน Designer ก็จะทำการผูกฟิลด์ข้อมูล (ADO) เข้ากับ TextBox Control (หรืออื่นๆ) และวนรอบค่าของ RecordSet เพื่อทำการแสดงผลจนกระทั่งหมดข้อมูล ... จบ
ข้อแนะนำ: ขอให้มอง Active Report Designer (DSR) เป็นเสมือนฟอร์มๆหนึ่งของ MS Visual Basic
 ลาก Control ARViewer เพื่อทำการแสดงผล (Preview) มาวางแปะไว้บนฟอร์ม Name : ARViewerEmployeeList
 เพิ่ม Designer เข้ามา ... กรณีที่มีไฟล์เดิมอยู่แล้วก็ให้ทำการ Add File ... เข้ามา
 สร้างความสัมพันธ์ของตารางข้อมูลเพื่อนำมาใช้ในการแสดงผล
 ฟิลด์ที่เลือกมาแสดงผล
ย้ำอีกครั้ง: ขอให้มอง Active Report Designer (DSR) เป็นเสมือนฟอร์มๆหนึ่งของ MS Visual Basic การออกแบบรายงาน ก็แค่นำ Control ต่างๆ มาวางแปะลงบนฟอร์มรายงาน หรือ Designer นี่แหละครับ ... พี่น้อง หากต้องการให้ Control ผูกเข้ากับฟิลด์ฐานข้อมูล ... แนะนำให้ใช้ TextBox ส่วนป้ายบอกต่างๆ ก็ไปใช้ Label เอา
 การตั้งค่า Properties แบบ Design Time
 Unbound Control
 ตัวอย่างนี้ผมตั้งค่ากระดาษรายงานแบบ A4 (210 x 297 mm.) พิมพ์ในแนวตั้ง (Portrait) ดังนั้นในเวลาออกแบบจาก Designer จะต้องลดขนาดความกว้างของกระดาษลง 1 Cm. หรือ 10 mm.รับรองครับว่าเมื่อตอนพิมพ์ออกมาบนกระดาษจริงๆ จะไม่เกินความกว้างของมันเลย ไม่ว่าคุณจะตั้งค่าขนาดของกระดาษแบบไหนก็ตามที ... เชื่อทองก้อนเหอะ
 การตั้งขนาดความกว้างของกระดาษผิด
 สั่งให้โปรแกรมทำงาน
การใช้งาน Active Report มันแบ่งการทำงานออกเป็น 2 ส่วน
ส่วนแรกเป็นส่วนควบคุม ที่ปรากฏอยู่บนฟอร์มของ MS Visual Basic
ส่วนที่สอง จะเป็นการนำข้อมูลมาแสดงผล จะอยู่ที่ Designer ... และมันจะถูกส่งออกมา Preview ยัง ARViewer
โค้ดจากฟอร์ม frmPrintEmployee ใน MS Visual Basic
Option Explicit
' ประกาศตัวแปรแบบ Object เพื่อรับงานไปพิมพ์
Dim rptPrint As Object
' ตัวแปรที่ใช้ในระบุการค้นหา หรือ กำหนดช่วงการพิมพ์หรือไม่
Dim blnSearch As Boolean
Private Sub Form_Load()
On Error GoTo ErrorHandler
Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
' เชื่อมต่อฐานข้อมูล
Call OpenDataBase
With ARViewEmployeeList
.Zoom = 100 ' ค่า % การแสดงผล
' และอื่นๆอีก ... เอาไว้ตอนหน้าล่ะกัน
End With
' ตั้งค่าเป็นเท็จเพื่อบ่งบอกว่าไม่ใช่การค้นหาข้อมูล
blnSearch = False
' อันที่จริงก่อนทำการ Preview ผมจะทำเป็นฟังค์ชั่นแทนเอา เช่น PreviewReport(False)
' เวลาประกาศในฟังค์ชั่น ก็จะประกาศแบบนี้ ... Function PreviewReport(blnSearch As Boolean)
' เพราะสั่งแบบนี้มันง่าย และ สะดวกกว่าเยอะครับ
ExitProc:
Exit Sub
ErrorHandler:
MsgBox "Error : " & Err.Number & vbCrLf & Err.Description, vbOKOnly + vbExclamation, "รายงานความผิดพลาด"
Resume ExitProc
End Sub
|
' เกิดเหตุการณ์กดปุ่ม Preview หรือ cmdPreview_Click
Private Sub cmdPreview_Click()
Set RS = New ADODB.Recordset
' ให้แสดงผลทั้งหมดน่ะมันนาน ... จริงๆแล้วต้องเลือกเฉพาะรายการที่ต้องการมากกว่า
' การค้นหา หรือ กำหนดช่วงข้อมูล
' อันนี้พี่น้องต้องลองไปใส่ไอเดียของตัวเองเข้าไปด้วยล่ะกันครับ
If blnSearch Then
Statement = "SELECT tblEmployee.EmployeePK, tblEmployee.EmployeeID, tblEmployee.EmployeeName, " & _
" tblEmployee.DateStart, tblPosition.PositionName, tblDepartment.DepartmentName " & _
" FROM (tblPosition INNER JOIN tblEmployee ON tblPosition.PositionPK = " & _
" tblEmployee.PositionFK) INNER JOIN " & _
" tblDepartment ON tblEmployee.DepartmentFK = tblDepartment.DepartmentPK " '& _
" [EmployeeID] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
" [EmployeeName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
" [PositionName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & " OR " & _
" [DepartmentName] " & " Like '%" & Trim(txtSearch.Text) & "%'" & _
" ORDER BY EmployeeID "
' หรือ BETWEEN ...
' ให้แสดงผลออกมาทั้งหมด
Else
Statement = "SELECT tblEmployee.EmployeePK, tblEmployee.EmployeeID, tblEmployee.EmployeeName, " & _
" tblEmployee.DateStart, tblPosition.PositionName, tblDepartment.DepartmentName " & _
" FROM (tblPosition INNER JOIN tblEmployee ON tblPosition.PositionPK = " & _
" tblEmployee.PositionFK) INNER JOIN " & _
" tblDepartment ON tblEmployee.DepartmentFK = tblDepartment.DepartmentPK " & _
" ORDER BY EmployeeID "
End If
'
RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
' =====================================================
' ส่วนสำคัญในการทำรายงานด้วย Active Report
' ตั้งค่า หรือ การผูกรายงานเข้ากับ Object
Set rptPrint = New arEmployeeList ' มาจากชื่อไฟล์รายงาน (Designer)
' ARViewEmployeeList ตัวนี้คือ ARViewer Control ที่วางไว้อยู่บนฟอร์ม frmPrintEmployee
Set Me.ARViewEmployeeList.object = rptPrint
' ผูกฐานข้อมูล (Bound Control) แบบ Run Time เข้ากับ Object
' dcRptData ตัวนี้มันไปอยู่ที่แบบฟอร์มรายงานของ ActiveReport (Designer) น่ะครับ
Set rptPrint.dcRptData.Recordset = RS
' RecordSet ตัวนี้นี่แหละที่ถูกส่งออกไปยัง Designer โดย dcRptData จะเป็นตัวรับค่า
' =====================================================
End Sub
|
โค้ดจาก Designer ของ Active Report
' เมื่อผูกค่าต่างๆเข้าหากันแล้ว ... ต่อไปก็จะกระโดดไปทำงานยัง Designer ที่เราออกแบบเอาไว้
' เริ่มต้นการตั้งค่าต่างๆที่นี่ ... เหมือนกับ Form_Load ใน MS Visual Basic ครับ
Private Sub ActiveReport_Initialize()
' การควบคุมการทำงานแบบ Run Time จะมีประสิทธิภาพที่ดีกว่า Design Time
' ขนาดของกระดาษ
PageSettings.PaperSize = 9 ' A4
' ตั้งค่าในแนวตั้ง
PageSettings.Orientation = ddOPortrait
' หรือแนวนอน
' PageSettings.Orientation = ddOLandscape
' หน่วย Twip น่ะครับ นั่นคือ 1440 Twip = 1 นิ้ว หรือ 2.54 Cm.
' อยากได้หน่วยวัดแบบไหนก็ทำบัญญัติไตรยางค์หาค่าเอาเองครับ
PageSettings.LeftMargin = 300
PageSettings.RightMargin = 300
PageSettings.BottomMargin = 300
PageSettings.TopMargin = 300
' เคลียร์ค่าก่อนทำการแสดงผล
txtItem.Text = ""
txtEmployeeID.Text = ""
txtName.Text = ""
txtPosition.Text = ""
txtDepartment.Text = ""
txtDateStart.Text = ""
txtDayWork.Text = ""
lblContinued.Caption = ""
End Sub
' รายละเอียดต่างๆก็จะนำมาแสดงใน Detail อยู่แล้ว
Private Sub Detail_Format()
' อยากให้พี่น้องลองทดสอบเอาเองครับ ว่าหากเราไม่ใช้ตัวแปร i เป็น Static แล้วผลที่ได้มันจะเป็นยังไง
'Dim i As Long
' เก็บค่าของตัวแปร i เอาไว้ตลอด ... นานๆครั้งที่ได้ใช้ตัวแปรแบบนี้
Static i As Long
i = i + 1
txtItem.Text = i & "."
' dcRptData ก็คือ ADO Control ที่เรานำมาวางไว้บนรายงานนั่นแหละ
' เพียงแต่เราผูกฐานข้อมูลเข้า (Bound Control) ตอนสั่ง Run Time โดยวิธีที่สุดแสนจะง่ายดาย
' rptPrint.dcRptData.Recordset = RS ในฟอร์มพิมพ์งาน (frmPrintEmployee)
' จากนั้นแต่ละฟิลด์ (จาก Query ที่อยู่ในฟอร์ม frmPrintEmployee) เราก็นำมาผูกเข้ากับ TextBox Control
' ดังนั้น ... อย่าลืมต้องสร้างความสัมพันธ์ให้มันตรง หรือ สอดคล้องกันด้วยน่ะขอรับ
txtEmployeeID.Text = "" & Trim(dcRptData.Recordset("EmployeeID"))
txtName.Text = "" & Trim(dcRptData.Recordset("EmployeeName"))
txtPosition.Text = "" & Trim(dcRptData.Recordset("PositionName"))
txtDepartment.Text = "" & Trim(dcRptData.Recordset("DepartmentName"))
txtDateStart.Text = FormatDateTime(dcRptData.Recordset("DateStart"), vbShortDate)
' เรียกใช้งาน Public Function CalcDate(วันที่เริ่มงาน, วันที่ปัจจุบัน) ... ส่งค่ากลับมาเป็น String
txtDayWork.Text = "(อายุงาน: " & CalcDate(txtDateStart.Text, Now) & ")"
' กลไกของมันต่อไป คือ การวนรอบอีก จนกว่าข้อมูลใน dcRptData จะหมดลงนั่นเอง
' ======================================================================
' มองให้ชัดๆ นั่นก็คือ คุณสามารถทำการคำนวณ หรือ ตั้งค่าสูตรต่างๆได้ด้วยตัวคุณเอง
' โดยค่าต่างๆที่เราใช้คำนวณ มันจะถูกนำมาแสดงผลลง TextBox หรือ Label Control ได้อย่างง่ายมาก
' และที่สำคัญ ... มันทำงานแบบ Real Time ครับพี่น้อง
' มาถึงตรงนี้ ... คุณคิดว่าถึงเวลาที่จะสลัดรักเจ้า Crystal Report ได้แล้วหรือยัง ... 55555
' ======================================================================
End Sub
|
 เลือกใช้งานการ Export รายงานให้อยู่ในรูปแบบอื่นๆ ... ตามใจชอบของพี่น้องเลยครับ
 ส่งรายงานออกเป็น MS Excel ... เหนือคำบรรยายจริงๆเลย
ตัวอย่างของการ Export ไปยัง MS Excel
' ส่งออกเป็นไฟล์ MS Excel ก็สุดแสนจะง่ายดาย (ซ่ะไม่มีล่ะ)
Private Sub cmdExportExcel_Click()
' ====================================================================
' ก่อนใช้งานอย่าลืมไปเลือก Project --> References ... --> ActiveReports Excel Export Filter
' ====================================================================
Dim oEXL As ActiveReportsExcelExport.ARExportExcel
Set oEXL = New ActiveReportsExcelExport.ARExportExcel
' ส่งออกไปที่ไฟล์ MS Excel
' หากต้องการให้ผู้ใช้งาน ตั้งชื่อไฟล์เอาเอง ก็นำ Common Dialog Control มาใช้งาน
' ในเว็บไซต์แห่งนี้มีให้พี่น้องอยู่แล้ว ... โปรดเลือกเอามาใช้งานเองเถิด
oEXL.FileName = App.Path & "\EXCELTest.xls"
oEXL.Export rptPrint.Pages
End Sub
|
Conclusion: เห็นหรือยังครับ ... พี่น้อง หากเอาเข้าจริงๆแล้ว มันไม่ได้ยากเย็นแสนเข็ญเลย สำหรับการทำรายงานออกมาสักตัวนึง หากเรามีแหล่งข้อมูล (ที่ถูกต้อง และ น่าเชื่อถือได้) เพื่อจะนำสิ่งต่างๆเหล่านี้ มาเผยแพร่ไปยังผู้ที่กำลังจะเรียนรู้ หรือ ต้องการพัฒนาทักษะในการเขียนโปรแกรม ... ซอฟท์แวร์ไทยไม่ต้องไปนอกหรอกครับ เอาแค่พัฒนา หรือ สร้างโปรแกรมเมอร์รุ่นใหม่ๆ ให้พร้อม และ เป็นระบบมากกว่าที่เป็นอยู่ ... ไม่ดีกว่าเรอะ ... รอบหน้าจะว่ากันเรื่องของการทำกลุ่ม หรือ Group ด้วย Designer ตัวเดียวครับ ... พี่น้อง
|