ดาวน์โหลดโปรแกรม RSS Reader ได้ที่นี่ ...

|
|
|
Visitors - Session views |       
7 ธันวาคม พ.ศ.2549 39 Users On-Line. |
|
Visitors - Page views |        1 กุมภาพันธ์ พ.ศ.2551 |
|
|
|
 |
|
Visual Basic 6.0 กับการทำรายงานด้วย Active Report ตอนที่ 2 |
Category »
VB 6/VB.Net โดย : Webmaster เมื่อ 12/2/2551 12:00:00 | (อ่าน : 37692) | บทความสำหรับตอนนี้ ผมจะมานำเสนอแนวทาง และ กลวิธี ในการควบคุมการแสดงผลของรายงาน โดยใช้โค้ดจริงๆ ไม่ใช้ตัวประกอบ หรือ ตัวแสดงแทนแต่อย่างใด ... เอิ๊กๆๆๆๆ ... การทำรายงานที่มีรูปแบบที่คล้ายคลึงกันนั้น เราไม่จำเป็นต้องมานั่งออกแบบจาก Designer แยกเป็นไฟล์ๆไปน่ะครับ แต่เราสามารถกำหนดตามความต้องการ (ของเรา หรือ ผู้ว่าจ้าง) โดยการสั่งโปรแกรมให้ทำงานในลักษณะของ Run-Time นั่นคือ จะมองเห็นผลลัพธ์ก็ต่อเมื่อสั่งรันโปรแกรมแล้วเท่านั้น ไอ้ประเภทมาผูกคอนโทรลติดตายตัวกับฟิลด์ของฐานข้อมูลนั้น (Design Time) โปรแกรมของเราก็จะขาดความยืดหยุ่นไปเยอะเลยทีเดียว บทความนี้ผมเลยรวบยอดหลายสิ่งหลายอย่างเข้ามานำเสนอไว้ให้กับงานนี้ไปเลย แต่ประเด็นหลักๆ ก็คือ ในเรื่องของการจัดกลุ่ม (Group) เพื่อแยกรายงานออกเป็นหมวดหมู่ได้ โดยการใช้ Designer เพียงตัวเดียว อันเดียว หรือ ไฟล์เดียว ... และนอกจากแล้วนี้ พี่น้องก็จะได้ให้เห็นถึงการคำนวณหาค่าทางคณิตศาสตร์ โดยไม่ต้องมาใช้สูตร (หรือใส่ปีกกา จนหน้านิ่วคิ้วขมวด ทำให้รอยตีนกาขึ้นหน้าโดยอัตโนมัติ ... 55555) แต่อาศัยการกำหนดค่าลงในตัวแปรแทน ... แน่นอนครับที่ผมว่ามานี้ เราใช้การโค้ดตามแบบสไตล์ของ Visual Basic ล้วนๆ ... และมาถึง ณ ตรงนี้ ผมบอกได้เลยว่าคุณสามารถนำมันไปประยุกต์ใช้งานเพื่อพิมพ์ใบเสนอราคา หรือ ใบรายการซื้อขายได้อย่างไม่ยากเย็นเลยครับ ... พี่น้อง
ส่วนเพิ่มเติมในตอนนี้ คือ การนำ ComboBox มาเป็นเงื่อนไขในการเลือกงานพิมพ์
จาก Designer ให้คลิ๊กเมาส์ขวา จากนั้นก็ให้เลือก Insert Group Header เข้ามา
ปรากฏ GroupHeader และ GroupFooter เข้ามาเป็นของคู่กันเสมอ จากตอนที่ 1 พี่น้องต้องย้ายส่วนหัวของรายงานเข้ามาไว้ที่ GroupHeader ด้วย และเพิ่มลาเบล lblGroupData เข้ามา เพื่อแจ้งให้ผู้ใช้งานได้รู้ว่าเป็นรายงานแบบใดอยู่
ส่วนของ GroupFooter เพิ่ม TextBox (txtSumSalary) เพื่อที่จะทำการรวมจำนวนเงินเดือนพนักงาน
รายงานรายชื่อพนักงานทั้งหมด
แยกตามแผนก - DepartmentName
แยกตามตำแหน่ง - PositionName
ส่วนของ frmPrintEmployee
Private Sub Form_Load()
On Error GoTo ErrorHandler
Me.Move (Screen.Width - Me.Width) \ 2, (Screen.Height - Me.Height) \ 2
' เชื่อมต่อฐานข้อมูล
Call OpenDataBase
' ผมใช้ ComboBox มาเป็นเงื่อนไขในการพิมพ์รายงาน
cmbPrint.Clear
cmbPrint.AddItem " พิมพ์รายชื่อพนักงานทั้งหมด"
cmbPrint.AddItem " พิมพ์รายงานตามแผนก"
cmbPrint.AddItem " พิมพ์รายงานตามตำแหน่ง"
cmbPrint.ListIndex = 0
ExitProc:
Exit Sub
ErrorHandler:
MsgBox "Error : " & Err.Number & vbCrLf & Err.Description, vbOKOnly + vbExclamation, "รายงานความผิดพลาด"
Resume ExitProc
End Sub
Private Sub cmdPreview_Click()
Set RS = New ADODB.Recordset
' ผมยกตัวอย่างของการเชื่อมความสัมพันธ์แบบง่ายๆให้พี่น้องได้รับชมกันน่ะครับ
' อันที่จริงอย่างผลรวมของเงินเดือน เราก็สามารถใช้การทำ Group เพื่อหาค่า Sum แทนก็ได้
' ก็ลองไปสรรหาไอเดียใส่เอาเองล่ะกัน
Statement = "SELECT tblEmployee.EmployeePK, tblEmployee.EmployeeID, " & _
" tblEmployee.EmployeeName, tblEmployee.DateStart, " & _
" tblPosition.PositionName, tblDepartment.DepartmentName, " & _
" tblEmployee.Salary " & _
" FROM (tblPosition INNER JOIN tblEmployee ON tblPosition.PositionPK = " & _
" tblEmployee.PositionFK) INNER JOIN " & _
" tblDepartment ON tblEmployee.DepartmentFK = tblDepartment.DepartmentPK "
' พี่น้องครับ ... การทำกลุ่ม กับ การใช้ ORDER มันมีความสัมพันธ์กันน่ะครับ
' หลายต่อหลายคนก็มักจะพลาดอะไรง่ายๆแบบนี้ได้เสมอ ... ไม่เชื่อผมก็ลองทดสอบดูได้เลยว่า
' หากคุณทำ ORDER ไม่ตรงกับกลุ่มที่ต้องการ ผลลัพธ์จะเกิดอะไรขึ้นมาบ้าง
Select Case cmbPrint.ListIndex
' แสดงข้อมูลพนักงานทั้งหมด
Case 0
Statement = Statement & " ORDER BY EmployeeID "
' แสดงรายงานตามตำแหน่ง
Case 1
Statement = Statement & " ORDER BY DepartmentName, EmployeeID "
' แสดงรายงานตามแผนก
Case 2
Statement = Statement & " ORDER BY PositionName, EmployeeID "
End Select
RS.Open Statement, ConnDB, adOpenForwardOnly, adLockReadOnly, adCmdText
' ส่วนสำคัญในการทำรายงานด้วย Active Report
' ตั้งค่า หรือ การผูกรายงานเข้ากับ Object
Set rptPrint = New arEmployeeListGroup ' มาจากชื่อไฟล์รายงาน (Designer)
' ARViewEmployeeList ตัวนี้คือ Control ที่วางไว้อยู่บนฟอร์ม frmPrintEmployee
Set Me.ARViewEmployeeList.object = rptPrint
' ผูกฐานข้อมูล (Bound Control) แบบ Run Time เข้ากับ Object
' dcRptData ตัวนี้มันไปอยู่ที่แบบฟอร์มการแสดงผลของ ActiveReport น่ะครับ
Set rptPrint.dcRptData.Recordset = RS
End Sub
|
ส่วนของ Report Designer - arEmployeeListGroup
Option Explicit
Private bLastPage As Boolean
' ประกาศตัวแปร i ใหม่ เปลี่ยนมาเป็นแบบ Public สำหรับรายงานนี้
' หมายความว่าในทุกๆโปรแกรมย่อยของรายงานนี้เท่านั้น จะมองเห็นตัวแปรที่ผมประกาศไว้บนสุด
' รายงานอื่นน่ะมันมองไม่เห็นหรอกครับ ... พี่น้อง
Private i As Integer
Private SumSalary As Double
' เหอๆๆๆๆ งงกันล่ะซิ ฮ่วย ... ประกาศตัวแปรเป็นแบบ Private ดันมาบอกเป็น Public
' ส่วนนี้เป็นส่วนของการอ่านข้อมูลเข้ามาทีละรายการ
' นอกจากนี้ GroupHeader1.GroupValue นี่แหละ คือ การจัดกลุ่มรายงาน
Private Sub ActiveReport_FetchData(eof As Boolean)
' หากหมดข้อมูล bLastPage จะมีค่าเป็นจริง
bLastPage = dcRptData.Recordset.eof
If Not eof Then
' เพิ่มจำนวนการนับของลำดับที่
i = i + 1
Select Case frmPrintEmployee.cmbPrint.ListIndex
Case 0 ' แสดงรายการทั้งหมด
Case 1 ' แยกตามแผนก
GroupHeader1.GroupValue = dcRptData.Recordset("DepartmentName")
Case 2 ' แยกตามตำแหน่ง
GroupHeader1.GroupValue = dcRptData.Recordset("PositionName")
End Select
End If
End Sub
' ส่วนของการทำกลุ่มข้อมูล ทำการแจ้งผู้ใช้ว่าไอ้นี่มันคือรายงานอะไร ??????
Private Sub GroupHeader1_Format()
Select Case frmPrintEmployee.cmbPrint.ListIndex
Case 0 ' แสดงรายการทั้งหมด
lblGroupData.Caption = "รายงานรายชื่อพนักงานทั้งหมด:"
lblDepartment.Alignment = ddTXLeft
lblDepartment.Caption = "แผนก"
Case 1 ' แยกตามแผนก
lblGroupData.Caption = "แผนก: " & dcRptData.Recordset("DepartmentName")
' ใช้งาน Control ให้คุ้มค่า โดยการกำหนดในขณะ Run-Time
lblDepartment.Alignment = ddTXRight
lblDepartment.Caption = "เงินเดือน"
Case 2 ' แยกตามตำแหน่ง
lblGroupData.Caption = "ตำแหน่ง: " & dcRptData.Recordset("PositionName")
' ใช้งาน Control ให้คุ้มค่า โดยการกำหนดในขณะ Run-Time
lblPosition.Caption = "แผนก"
lblPosition.Alignment = ddTXLeft
lblDepartment.Caption = "เงินเดือน"
txtDepartment.Alignment = ddTXRight
End Select
End Sub
' รายละเอียดต่างๆก็จะนำมาแสดงใน Detail อยู่แล้ว
Private Sub Detail_Format()
' คราวนี้ค่า i จะเพิ่มค่าก็อยู่ที่ Group แทน
txtItem.Text = i & "."
txtEmployeeID.Text = "" & Trim(dcRptData.Recordset("EmployeeID"))
txtName.Text = "" & Trim(dcRptData.Recordset("EmployeeName"))
txtPosition.Text = "" & Trim(dcRptData.Recordset("PositionName"))
' ตรวจสอบเงื่อนไขของการพิมพ์
Select Case frmPrintEmployee.cmbPrint.ListIndex
Case 0
' พิมพ์รายงานออกปกติ
txtDepartment.Text = "" & Trim(dcRptData.Recordset("DepartmentName"))
Case 1
' เอาชื่อแผนกไปไว้ส่วนหัวรายงาน (GroupHeader) ดังนั้นผมก็เลยเอาเงินเดือน
' มายัดใส่ไว้ในรายชื่อแผนกแทน ... (ใช้งาน Control ให้คุ้มค่า)
txtDepartment.Text = Format(Trim(dcRptData.Recordset("Salary")), "#,##0.00")
txtDepartment.Alignment = ddTXRight
Case 2
' ส่วนนี้ผมก็นำชื่อแผนกมาใส่ไว้ตรงตำแหน่งซ่ะ ส่วนเงินเดือนก็ไปใส่ไว้ในแผนกแทน ... อิอิอิอิอิ
txtPosition.Text = "" & Trim(dcRptData.Recordset("DepartmentName"))
txtDepartment.Text = Format(Trim(dcRptData.Recordset("Salary")), "#,##0.00")
End Select
txtDateStart.Text = FormatDateTime(dcRptData.Recordset("DateStart"), vbShortDate)
' ผมถึงได้บอกว่านี่แหละข้อดีของ Active Report เพราะโค้ดมันเนียนๆจาก VB เด๊ะๆๆๆๆๆ
' ทำให้ไม่ไปสับสน หรือ จดจำ สิ่งอื่นใด ... เพิ่มเติม
' ไม่ต้องใช้สูตร แต่อาศัยตัวแปรในการเก็บค่าแทน
SumSalary = SumSalary + dcRptData.Recordset("Salary")
' ค่านี้จะนำไปแสดงตอนท้ายรายงาน หรือ GroupFooter ครับพี่น้อง
' สมมุติว่าแผนกนี้มีพนักงาน 10 คน รายงาน (Detail) ในส่วนนี้ก็จะ Loop ไปที่
' ActiveReport_FetchData(eof As Boolean) 10 รอบ เพื่อทำการแสดงผลรายงาน
' ซึ่งในแต่ละรอบก็จะทำการบวกจำนวนเงินเดือนของพนักงานแต่ละคนไว้ใน SumSalary
End Sub
Private Sub GroupFooter1_Format()
' กรณีที่ให้พิมพ์รายชื่อพนักงานออกมาทั้งหมด ดังนั้น ...
' ผมจะไม่แสดงจำนวนเงินเดือนออกมา ก็ง่ายๆแค่กำหนดความสูงของส่วนนี้เป็น 0
' โห ... คิดได้ไงเนี่ย 55555
If frmPrintEmployee.cmbPrint.ListIndex = 0 Then GroupFooter1.Height = 0
' กรณีเลือกการทำรายงานตามแผนก หรือ ตำแหน่ง ความสูงจะมีค่าปกติ เท่ากับตอน Design
' ผลรวมของเงินเดือนก็จะปรากฏออกมา โดย ...
' นำค่าที่ได้จากการบวก (Sum) ใน Detail มาแสดงผลตอนท้ายรายงาน (GroupFooter)
txtSumSalary.Text = "รวมจำนวนเงินเดือน: " & Format(SumSalary, "#,##0.00")
' อันนี้จะว่าไปแล้วก็ไปใช้ SQL Statement ในเรื่องของ Group แทนก็ได้เน้อ ... พี่น้อง
' กรณีที่เป็น Group
' เมื่อพิมพ์ผลลัพธ์ในแต่ละกลุ่มเรียบร้อยแล้ว ก็ทำการเคลียร์ค่าใหม่
i = 1: SumSalary = 0
End Sub
|
Conclusion: อนึ่ง ... พี่น้องทั้งหลายครับ ... ลำพังแค่เพียงแต่ได้โค้ดจริงๆของผมไปนอนกอดเล่นๆให้อบอุ่นแล้ว มันไม่ได้ช่วยทำให้พี่น้องสามารถพัฒนาทักษะได้ดีขึ้นหรอกครับ หากไม่พินิจ พิจารณาไล่เรียงการทำงาน และ ทำความเข้าใจอย่างถ่องแท้แล้ว (ใช้ Trace หรือ Step Into ด้วยการกด F8 ดูครับ) ลองคิดจินตนาการดูซิครับว่าจะลองไปปรับประยุกต์ใช้งานได้อย่างไรบ้าง เอาเป็นว่าหากคิดไม่ออก ก็ลองเอาโจทย์ไปคิดเล่นๆดูครับ ... ลองทำ Query รายการแผนก (Department) ใส่เข้าไปใน ComboBox เพื่อให้มันเลือกพิมพ์รายการแยกออกมาเป็นแต่ละแผนกดูซิครับ ... เอ้า !!! เร็วๆๆๆๆ ... ใครจะทำได้ก่อนกัน
|
|