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

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

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

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

Visual Basic 6.0 กับการทำรายงานด้วย Active Report ตอนที่ 2

Category »  VB 6/VB.Net
โดย : Webmaster เมื่อ 12/2/2551 12:00:00
(อ่าน : 35109) 
บทความสำหรับตอนนี้ ผมจะมานำเสนอแนวทาง และ กลวิธี ในการควบคุมการแสดงผลของรายงาน โดยใช้โค้ดจริงๆ ไม่ใช้ตัวประกอบ หรือ ตัวแสดงแทนแต่อย่างใด ... เอิ๊กๆๆๆๆ ... การทำรายงานที่มีรูปแบบที่คล้ายคลึงกันนั้น เราไม่จำเป็นต้องมานั่งออกแบบจาก 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

ดาวน์โหลด 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

ส่วนของ 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 เพื่อให้มันเลือกพิมพ์รายการแยกออกมาเป็นแต่ละแผนกดูซิครับ ... เอ้า !!! เร็วๆๆๆๆ ... ใครจะทำได้ก่อนกัน
จี ทู จี เน็ต ดอต คอม - g2gNet Dot Com
เลขทะเบียนพาณิชย์อิเล็กทรอนิกส์ 0407314800231
CopyLeft © 2004 - 2099 g2gNet.Com All rights reserved.
Email: [email protected] หรือ โทร. 08-6862-6560