ชุมชนคนรักภาษาเบสิค - Visual Basic Community

 ลืมรหัสผ่าน
 ลงทะเบียน
ค้นหา
ดู: 5218|ตอบกลับ: 0

[VB.NET] การสร้างกราฟ หรือ Chart และส่งข้อมูลจากตารางกริดออกไปยัง Excel

[คัดลอกลิงก์]

308

กระทู้

498

โพสต์

5971

เครดิต

ผู้ดูแลระบบ

ทองก้อน ทับทิมกรอบ

Rank: 9Rank: 9Rank: 9

เครดิต
5971



บทความนี้แอดมินขอเหมารวบยอดไปเลยทีเดียวนะครับ กรณีของ การส่งข้อมูลจากตารางกริดไปยัง Excel จะใช้วิธีแบบ Line By Line ซึ่งแน่นอนว่าจะเกิดการทำงานที่ล่าช้ามาก หากกรณีที่มีข้อมูลเยอะๆ ส่วนการทำกราฟ หรือ Chart ก็จะอาศัยข้อมูลที่เกิดจากการสุ่มค่าตัวเลขแบบทศนิยมลงไปในตารางกริด โดยที่แอดมินใช้วิธีการที่ชื่นชอบก็คือ สั่งแบบ @Run Time แต่เพื่อความสะดวก แอดมินจะลาก Chart Control เข้ามาวางบนฟอร์มเอาไว้ก่อน ส่วนป้าย Legend และ Series หรือกราฟที่แสดงผลนั้น จะใช้การเขียนโค้ดเพื่อสร้างมันขึ้นมาแบบอัตโนมัติ นั่นคือเราจะเรียนรู้คุณสมบัติต่างๆของ Chart Control ด้วยโค้ดแทน และด้วยวิธีการนี้มันเกิดความยืดหยุ่นสูงในการปรับแต่งเพื่อไปใช้ในงานอื่นๆต่อไป ...


การส่งข้อมูลออกไป Excel จะทำต้อง References ตัว Microsoft Excel 14.0 Library Object เข้ามาก่อน โดยเลือกจาก COM (Component Object Model) ... (OFFICE 2010) ...




โค้ดในส่วนของการสุ่มข้อมูลเพื่อนำมาใส่ลงในตารางกริด ...
  1.     ' / --------------------------------------------------------------------------
  2.     Private Sub FillData()
  3.         Dim dt As New DataTable
  4.         dt.Columns.Add("Item")
  5.         dt.Columns.Add("Value1")
  6.         dt.Columns.Add("Value2")
  7.         dt.Columns.Add("Value3")
  8.         dt.Columns.Add("Average")
  9.         Dim RandomClass As New Random()
  10.         Dim MyMonth As String() = New String() {("ม.ค."), ("ก.พ."), ("มี.ค."), ("เม.ย."), ("พ.ค."), ("มิ.ย."), ("ก.ค."), ("ส.ค."), ("ก.ย."), ("ต.ค."), ("พ.ย."), ("ธ.ค.")}
  11.         For i As Byte = 0 To 11
  12.             Dim dr As DataRow = dt.NewRow()
  13.             dr(0) = MyMonth(i)
  14.             dr(1) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  15.             dr(2) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  16.             dr(3) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  17.             '// CDbl = Convert to Double
  18.             dr(4) = Format((CDbl(dr(1)) + CDbl(dr(2)) + CDbl(dr(3))) / 3, "#,##0.00")
  19.             dt.Rows.Add(dr)
  20.         Next
  21.         dgvData.DataSource = dt
  22.         Label1.Text = "Total : " & dt.Rows.Count.ToString("#,##") & " Records."
  23.     End Sub
คัดลอกไปที่คลิปบอร์ด

โค้ดในส่วนของการสร้างกราฟ หรือ Chart
  1.     ' / --------------------------------------------------------------------------------
  2.     Private Sub btnChart_Click(sender As System.Object, e As System.EventArgs) Handles btnChart.Click
  3.         If dgvData.RowCount <= 0 Then Return
  4.         '//
  5.         Chart1.Titles.Clear()
  6.         '// Clear Legends & Series
  7.         Chart1.Series.Clear()
  8.         Chart1.Legends.Clear()
  9.         '// Clear Points
  10.         For Each xSeries In Chart1.Series
  11.             xSeries.Points.Clear()
  12.         Next
  13.         '// Create Legends
  14.         Dim Legend1 As Legend = New Legend()
  15.         Legend1.Name = "Legend1"
  16.         Chart1.Legends.Add(Legend1)
  17.         '// Create Series
  18.         Dim Series1 As Series = New Series()
  19.         Dim Series2 As Series = New Series()
  20.         Dim Series3 As Series = New Series()
  21.         Dim Series4 As Series = New Series()
  22.         '// Add Series
  23.         With Chart1
  24.             .Series.Add(Series1)
  25.             .Series.Add(Series2)
  26.             .Series.Add(Series3)
  27.             .Series.Add(Series4)
  28.         End With
  29.         '//
  30.         Try
  31.             Dim myFont As New Font("Tahoma", 14, FontStyle.Bold)
  32.             Chart1.Titles.Add("Sample Chart")
  33.             Chart1.Titles(0).Font = myFont
  34.             '// Define Chart Type.
  35.             For Each xSeries In Chart1.Series
  36.                 Select Case cmbChartType.Text
  37.                     Case "Column"
  38.                         xSeries.ChartType = SeriesChartType.Column
  39.                     Case "Line"
  40.                         xSeries.ChartType = SeriesChartType.Line
  41.                     Case "Point"
  42.                         xSeries.ChartType = SeriesChartType.Point
  43.                 End Select
  44.                 '// Show Legend
  45.                 If chkShowLegend.Checked Then
  46.                     xSeries.IsVisibleInLegend = True
  47.                 Else
  48.                     xSeries.IsVisibleInLegend = False
  49.                 End If
  50.                 '// View the value of a chart point on mouse over.
  51.                 xSeries.ToolTip = "#VAL{0.00}"
  52.             Next
  53.             '//
  54.             With Chart1
  55.                 .Series(0).LegendText = "Value 1"
  56.                 .Series(1).LegendText = "Value 2"
  57.                 .Series(2).LegendText = "Value 3"
  58.                 .Series(3).LegendText = "Average"
  59.             End With
  60.             '// Show all Axis Label
  61.             Chart1.ChartAreas(0).AxisX.Interval = 1
  62.             '//
  63.             With Chart1.ChartAreas("ChartArea1")
  64.                 .AxisX.MajorGrid.LineWidth = 1
  65.                 .AxisY.MajorGrid.LineWidth = 1
  66.             End With

  67.             '// LOOP DISPLAY
  68.             For CountData As Integer = 0 To dgvData.Rows.Count - 1
  69.                 With Chart1
  70.                     '// 0 = Month, 1 = Value1, 2 = Value2, 3 = Value3, 4 = Average
  71.                     .Series(0).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(1, CountData).Value)
  72.                     .Series(1).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(2, CountData).Value)
  73.                     .Series(2).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(3, CountData).Value)
  74.                     .Series(3).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(4, CountData).Value)
  75.                 End With
  76.             Next
  77.         Catch ex As Exception
  78.             MessageBox.Show(ex.Message)
  79.         End Try

  80.     End Sub
คัดลอกไปที่คลิปบอร์ด

โค้ดในส่วนของการส่งข้อมูลออกไป Excel
  1.     ' / --------------------------------------------------------------------------------
  2.     '// Export data to Excel.
  3.     Private Sub btnExportExcel_Click(sender As System.Object, e As System.EventArgs) Handles btnExportExcel.Click
  4.         '// ไม่มีข้อมูลในตารางกริด ก็สั่งให้เด้งหนีออกไป
  5.         If dgvData.Rows.Count <= 0 Then Exit Sub
  6.         '// พิจารณาการเลือกใช้ชนิดข้อมูล (Data Type) ให้เหมาะสม
  7.         Dim MaxRow As Integer, MaxCol As Short
  8.         Dim nRow As Integer, nCol As Short
  9.         Dim xlsApp As New Excel.Application
  10.         Dim xlsWorkBook As Excel.Workbook = xlsApp.Workbooks.Add
  11.         Dim xlsWorkSheet As Excel.Worksheet = CType(xlsWorkBook.Worksheets(1), Excel.Worksheet)
  12.         '// S T A R T
  13.         Try
  14.             xlsApp.Visible = True
  15.             '// หาค่าจำนวนแถว
  16.             MaxRow = dgvData.RowCount
  17.             '// หาค่าจำนวนหลัก
  18.             MaxCol = dgvData.Columns.Count - 1
  19.             With xlsWorkSheet
  20.                 .Cells.Select()
  21.                 .Cells.Delete()
  22.                 '// Header
  23.                 For nCol = 0 To MaxCol
  24.                     .Cells(1, nCol + 1).Value = dgvData.Columns(nCol).HeaderText
  25.                 Next nCol
  26.                 '// ไล่ตามจำนวนแถว
  27.                 For nRow = 0 To MaxRow - 1
  28.                     For nCol = 0 To MaxCol
  29.                         .Cells(nRow + 2, nCol + 1).value = dgvData.Rows(nRow).Cells(nCol).Value
  30.                     Next nCol   '// Nested Loop
  31.                     '// หากชุดคำสั่งที่อยู่ใน Nested Loop
  32.                     '// การให้ตัวแปรต่อท้าย Next จะช่วยให้เรารู้ว่ามันอยู่ใน Loop ไหน
  33.                 Next nRow

  34.                 '// กำหนดรูปแบบใน WorkSheet
  35.                 .Rows("1:1").Font.FontStyle = "Bold"
  36.                 .Rows("1:1").Font.Size = 10
  37.                 '//
  38.                 .Cells.Columns.AutoFit()
  39.                 .Cells.Select()
  40.                 .Cells.EntireColumn.AutoFit()
  41.                 .Cells(1, 1).Select()
  42.             End With
  43.         Catch ex As Exception
  44.             MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
  45.         End Try
  46.         xlsApp = Nothing
  47.         '// Release memory.
  48.         ReleaseObject(xlsApp)
  49.         ReleaseObject(xlsWorkBook)
  50.         ReleaseObject(xlsWorkSheet)
  51.     End Sub
คัดลอกไปที่คลิปบอร์ด

โค้ดฉบับเต็มทั้งหมด ...
  1. ' / --------------------------------------------------------------------------
  2. ' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
  3. ' / eMail : thongkorn@hotmail.com
  4. ' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
  5. ' / Facebook: https://www.facebook.com/g2gnet (For Thailand)
  6. ' / Facebook: https://www.facebook.com/commonindy (Worldwide)
  7. ' / Purpose: Create data into DataGridView for make the Chart and Export data to Excel @Run Time.
  8. ' / Microsoft Visual Basic .NET (2010) + MS Excel 14.0
  9. ' /
  10. ' / This is open source code under @CopyLeft by Thongkorn Tubtimkrob.
  11. ' / You can modify and/or distribute without to inform the developer.
  12. ' / --------------------------------------------------------------------------
  13. Imports System.Windows.Forms.DataVisualization.Charting
  14. Imports Excel = Microsoft.Office.Interop.Excel

  15. Public Class frmChartExportExcel

  16.     Private Sub frmPlotGraph_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
  17.         Label1.Text = ""
  18.         '// Chart Type
  19.         '// https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.datavisualization.charting.seriescharttype?view=netframework-4.7.2
  20.         cmbChartType.Items.Add("Column")
  21.         cmbChartType.Items.Add("Line")
  22.         cmbChartType.Items.Add("Point")
  23.         cmbChartType.SelectedIndex = 0

  24.         '// Setup DataGridView
  25.         Call InitializeGrid()
  26.         '// Generate Data
  27.         Call btnGenData_Click(sender, e)
  28.         '//
  29.     End Sub

  30.     Private Sub btnGenData_Click(sender As System.Object, e As System.EventArgs) Handles btnGenData.Click
  31.         Call FillData()
  32.     End Sub

  33.     ' / --------------------------------------------------------------------------
  34.     Private Sub FillData()
  35.         Dim dt As New DataTable
  36.         dt.Columns.Add("Item")
  37.         dt.Columns.Add("Value1")
  38.         dt.Columns.Add("Value2")
  39.         dt.Columns.Add("Value3")
  40.         dt.Columns.Add("Average")
  41.         Dim RandomClass As New Random()
  42.         Dim MyMonth As String() = New String() {("ม.ค."), ("ก.พ."), ("มี.ค."), ("เม.ย."), ("พ.ค."), ("มิ.ย."), ("ก.ค."), ("ส.ค."), ("ก.ย."), ("ต.ค."), ("พ.ย."), ("ธ.ค.")}
  43.         For i As Byte = 0 To 11
  44.             Dim dr As DataRow = dt.NewRow()
  45.             dr(0) = MyMonth(i)
  46.             dr(1) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  47.             dr(2) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  48.             dr(3) = FormatNumber(RandomClass.Next(100, 1000) + RandomClass.NextDouble(), 2)
  49.             '// CDbl = Convert to Double
  50.             dr(4) = Format((CDbl(dr(1)) + CDbl(dr(2)) + CDbl(dr(3))) / 3, "#,##0.00")
  51.             dt.Rows.Add(dr)
  52.         Next
  53.         dgvData.DataSource = dt
  54.         Label1.Text = "Total : " & dt.Rows.Count.ToString("#,##") & " Records."
  55.     End Sub

  56.     ' / --------------------------------------------------------------------------------
  57.     '// การตั้งค่าเริ่มต้นให้กับตารางกริดในแบบ @Run Time
  58.     Private Sub InitializeGrid()
  59.         With dgvData
  60.             .RowHeadersVisible = False
  61.             .AllowUserToAddRows = False
  62.             .AllowUserToDeleteRows = False
  63.             .AllowUserToResizeRows = False
  64.             .MultiSelect = False
  65.             .SelectionMode = DataGridViewSelectionMode.FullRowSelect
  66.             .ReadOnly = True
  67.             .Font = New Font("Tahoma", 9)
  68.             ' จัดความกว้างของแต่ละหลัก
  69.             .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
  70.             .AutoResizeColumns()
  71.             ' Adjust Header Styles
  72.             With .ColumnHeadersDefaultCellStyle
  73.                 .BackColor = Color.Navy
  74.                 .ForeColor = Color.White
  75.                 .Font = New Font("Tahoma", 9, FontStyle.Bold)
  76.             End With
  77.         End With
  78.     End Sub

  79.     ' / --------------------------------------------------------------------------------
  80.     Private Sub btnChart_Click(sender As System.Object, e As System.EventArgs) Handles btnChart.Click
  81.         If dgvData.RowCount <= 0 Then Return
  82.         '//
  83.         Chart1.Titles.Clear()
  84.         '// Clear Legends & Series
  85.         Chart1.Series.Clear()
  86.         Chart1.Legends.Clear()
  87.         '// Clear Points
  88.         For Each xSeries In Chart1.Series
  89.             xSeries.Points.Clear()
  90.         Next
  91.         '// Create Legends
  92.         Dim Legend1 As Legend = New Legend()
  93.         Legend1.Name = "Legend1"
  94.         Chart1.Legends.Add(Legend1)
  95.         '// Create Series
  96.         Dim Series1 As Series = New Series()
  97.         Dim Series2 As Series = New Series()
  98.         Dim Series3 As Series = New Series()
  99.         Dim Series4 As Series = New Series()
  100.         '// Add Series
  101.         With Chart1
  102.             .Series.Add(Series1)
  103.             .Series.Add(Series2)
  104.             .Series.Add(Series3)
  105.             .Series.Add(Series4)
  106.         End With
  107.         '//
  108.         Try
  109.             Dim myFont As New Font("Tahoma", 14, FontStyle.Bold)
  110.             Chart1.Titles.Add("Sample Chart")
  111.             Chart1.Titles(0).Font = myFont
  112.             '// Define Chart Type.
  113.             For Each xSeries In Chart1.Series
  114.                 Select Case cmbChartType.Text
  115.                     Case "Column"
  116.                         xSeries.ChartType = SeriesChartType.Column
  117.                     Case "Line"
  118.                         xSeries.ChartType = SeriesChartType.Line
  119.                     Case "Point"
  120.                         xSeries.ChartType = SeriesChartType.Point
  121.                 End Select
  122.                 '// Show Legend
  123.                 If chkShowLegend.Checked Then
  124.                     xSeries.IsVisibleInLegend = True
  125.                 Else
  126.                     xSeries.IsVisibleInLegend = False
  127.                 End If
  128.                 '// View the value of a chart point on mouse over.
  129.                 xSeries.ToolTip = "#VAL{0.00}"
  130.             Next
  131.             '//
  132.             With Chart1
  133.                 .Series(0).LegendText = "Value 1"
  134.                 .Series(1).LegendText = "Value 2"
  135.                 .Series(2).LegendText = "Value 3"
  136.                 .Series(3).LegendText = "Average"
  137.             End With
  138.             '// Show all Axis Label
  139.             Chart1.ChartAreas(0).AxisX.Interval = 1
  140.             '//
  141.             With Chart1.ChartAreas("ChartArea1")
  142.                 .AxisX.MajorGrid.LineWidth = 1
  143.                 .AxisY.MajorGrid.LineWidth = 1
  144.             End With

  145.             '// LOOP DISPLAY
  146.             For CountData As Integer = 0 To dgvData.Rows.Count - 1
  147.                 With Chart1
  148.                     '// 0 = Month, 1 = Value1, 2 = Value2, 3 = Value3, 4 = Average
  149.                     .Series(0).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(1, CountData).Value)
  150.                     .Series(1).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(2, CountData).Value)
  151.                     .Series(2).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(3, CountData).Value)
  152.                     .Series(3).Points.AddXY(dgvData.Item(0, CountData).Value, dgvData.Item(4, CountData).Value)
  153.                 End With
  154.             Next
  155.         Catch ex As Exception
  156.             MessageBox.Show(ex.Message)
  157.         End Try

  158.     End Sub

  159.     ' / --------------------------------------------------------------------------------
  160.     '// Export data to Excel.
  161.     Private Sub btnExportExcel_Click(sender As System.Object, e As System.EventArgs) Handles btnExportExcel.Click
  162.         '// ไม่มีข้อมูลในตารางกริด ก็สั่งให้เด้งหนีออกไป
  163.         If dgvData.Rows.Count <= 0 Then Exit Sub
  164.         '// พิจารณาการเลือกใช้ชนิดข้อมูล (Data Type) ให้เหมาะสม
  165.         Dim MaxRow As Integer, MaxCol As Short
  166.         Dim nRow As Integer, nCol As Short
  167.         Dim xlsApp As New Excel.Application
  168.         Dim xlsWorkBook As Excel.Workbook = xlsApp.Workbooks.Add
  169.         Dim xlsWorkSheet As Excel.Worksheet = CType(xlsWorkBook.Worksheets(1), Excel.Worksheet)
  170.         '// S T A R T
  171.         Try
  172.             xlsApp.Visible = True
  173.             '// หาค่าจำนวนแถว
  174.             MaxRow = dgvData.RowCount
  175.             '// หาค่าจำนวนหลัก
  176.             MaxCol = dgvData.Columns.Count - 1
  177.             With xlsWorkSheet
  178.                 .Cells.Select()
  179.                 .Cells.Delete()
  180.                 '// Header
  181.                 For nCol = 0 To MaxCol
  182.                     .Cells(1, nCol + 1).Value = dgvData.Columns(nCol).HeaderText
  183.                 Next nCol
  184.                 '// ไล่ตามจำนวนแถว
  185.                 For nRow = 0 To MaxRow - 1
  186.                     For nCol = 0 To MaxCol
  187.                         .Cells(nRow + 2, nCol + 1).value = dgvData.Rows(nRow).Cells(nCol).Value
  188.                     Next nCol   '// Nested Loop
  189.                     '// หากชุดคำสั่งที่อยู่ใน Nested Loop
  190.                     '// การให้ตัวแปรต่อท้าย Next จะช่วยให้เรารู้ว่ามันอยู่ใน Loop ไหน
  191.                 Next nRow

  192.                 '// กำหนดรูปแบบใน WorkSheet
  193.                 .Rows("1:1").Font.FontStyle = "Bold"
  194.                 .Rows("1:1").Font.Size = 10
  195.                 '//
  196.                 .Cells.Columns.AutoFit()
  197.                 .Cells.Select()
  198.                 .Cells.EntireColumn.AutoFit()
  199.                 .Cells(1, 1).Select()
  200.             End With
  201.         Catch ex As Exception
  202.             MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
  203.         End Try
  204.         xlsApp = Nothing
  205.         '// Release memory.
  206.         ReleaseObject(xlsApp)
  207.         ReleaseObject(xlsWorkBook)
  208.         ReleaseObject(xlsWorkSheet)
  209.     End Sub

  210.     Private Sub frmPlotGraph_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
  211.         Me.Dispose()
  212.         Application.Exit()
  213.     End Sub

  214.     Private Sub btnClose_Click(sender As System.Object, e As System.EventArgs) Handles btnClose.Click
  215.         Me.Close()
  216.     End Sub

  217.     '// เวลากด Enter ในแถวของตารางกริด จะไม่เกิดการเลื่อนตำแหน่ง
  218.     Private Sub dgvData_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles dgvData.KeyDown
  219.         If e.KeyCode = Keys.Enter Then e.SuppressKeyPress = True
  220.     End Sub

  221.     ' / ------------------------------------------------------------------
  222.     '// คืนหน่วยความจำกลับคืนสู่ระบบ
  223.     Public Sub ReleaseObject(ByVal obj As Object)
  224.         Try
  225.             System.Runtime.InteropServices.Marshal.ReleaseComObject(obj)
  226.             obj = Nothing
  227.         Catch ex As Exception
  228.             obj = Nothing
  229.         Finally
  230.             '// GC = Garbage Collection
  231.             GC.Collect()
  232.         End Try
  233.     End Sub

  234. End Class
คัดลอกไปที่คลิปบอร์ด

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

ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง

คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน

x
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด
ขออภัย! คุณไม่ได้รับสิทธิ์ในการดำเนินการในส่วนนี้ กรุณาเลือกอย่างใดอย่างหนึ่ง ลงชื่อเข้าใช้ | ลงทะเบียน

รายละเอียดเครดิต

ข้อความล้วน|อุปกรณ์พกพา|ประวัติการแบน|G2GNet.com  

GMT+7, 2024-3-29 04:24 , Processed in 0.197937 second(s), 4 queries , File On.

Powered by Discuz! X3.4, Rev.62

Copyright © 2001-2020 Tencent Cloud.

ตอบกระทู้ ขึ้นไปด้านบน ไปที่หน้ารายการกระทู้