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

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

[VB.NET] การสร้างหน้าจอ GUI ของการขายสินค้า แบบกราฟิค หรือโหมดทัชสกรีน

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

311

กระทู้

502

โพสต์

6050

เครดิต

ผู้ดูแลระบบ

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

Rank: 9Rank: 9Rank: 9

เครดิต
6050



การสร้างหน้าจอ GUI ของการขายสินค้า แบบกราฟิค หรือโหมดทัชสกรีน ... โค้ดชุดนี้ถือว่าอยู่ในขั้นตอนของการออกแบบ จึงไม่มีการติดต่อเข้ากับระบบฐานข้อมูลใดๆ แต่อาศัยการใช้ข้อมูลสมมุติ หรือจำลอง ผ่านทาง DataTable ซึ่งจะมีการแบ่งกลุ่มหรือประเภทสินค้าเอาไว้ให้ 4 กลุ่ม และสามารถแสดงผลรายการสินค้าทั้งหมดออกมาได้ ...

ในการสร้าง Control ในลักษณะไดนามิค แบบนี้ (คือไม่รู้จำนวนรายการสินค้า หรือจำนวนกลุ่มที่แน่นอน) ก็ไม่ได้ยากเย็นมากนัก เริ่มจากการหาจำนวนกลุ่มสินค้าออกมาก่อน (ตัวอย่างมี 4 กลุ่ม + กลุ่มรวมทั้งหมด จะได้ 5 กลุ่ม) จากนั้นก็สร้าง TabPage และ Panel Control (เพื่อตีกรอบ Button Control ไม่ให้ล้น) มารองรับในแต่ละกลุ่ม เมื่อได้ Panel Control มาแล้ว ก็นำเอาจำนวนสินค้าที่อยู่ในแต่ละกลุ่มมาทำการแสดงผล โดยที่มีการคำนวณหาระยะของ Button อยู่ 2 ค่า คือ ...

1. หาค่าตำแหน่ง Left จะมาจากการหารเอาเศษ (MOD)
ตัวอย่างกำหนดเอาไว้ให้แสดงผลปุ่มคำสั่ง (Button) 3 หลัก
หาตำแหน่งซ้าย (Left) ... ด้วยการหารเอาเศษ (Mod) ด้วย 3 จะได้คำตอบ 0, 1, 2 ตลอด เพื่อใช้จัดวางตำแหน่งหลัก Button ได้ทีละ 3 หลัก
การหารเอาเศษจะได้ค่าสูงสุด คือ ค่าตัวหาร (Mod) ลบออก 1 เช่น X Mod 3 จะได้ค่า 0, 1, 2 (หรือ 3 - 1 = 2)
เริ่มนับจาก 0 ไปเรื่อยๆจนกว่าจะหมด (นับไปตามจำนวนรายการสินค้า)
0 Mod 3 = 0, 1 Mod 3 = 1, 2 Mod 3 = 2 ... รอบที่ 1
3 Mod 3 = 0, 4 Mod 3 = 1, 5 Mod 3 = 2 ... รอบที่ 2
6 Mod 3 = 0, 7 Mod 3 = 1, 8 Mod 3 = 2 ... รอบที่ 3 ... ทำไปเรื่อยๆ
มีคำตอบแค่ 0, 1, 2 เราก็เลยหาจำนวนหลักได้ตามที่กำหนด คือ 3 หลัก
เอาค่าที่ได้แต่ละหลักมาคูณความกว้างของปุ่มคำสั่ง
เป็นการเลื่อนตำแหน่งไปทางซ้าย ด้วยการคูณด้วย 0, 1 และ 2 เป็นจำนวนเท่าของความกว้างของ Button
B.Left = (iCount Mod ColCount) * B.Width

2. หาตำแหน่งบน (Top) ... ด้วยการหารตัดเศษ \ ... การหารปกติ 3 / 2 = 1.5, การหารตัดเศษ 3 \ 2 = 1
เริ่มนับจาก 0 ไปเรื่อยๆจนกว่าจะหมด (นับไปตามจำนวนรายการสินค้า)
0 \ 3 = 0, 1 \ 3 = 0, 2 \ 3 = 0 ... รอบที่ 1 (คำตอบคือ 0 เหมือนกัน)
3 \ 3 = 1, 4 \ 3 = 1, 5 \ 3 = 1 ... รอบที่ 2 (คำตอบคือ 1 เหมือนกัน)
6 \ 3 = 2, 7 \ 3 = 2, 8 \ 3 = 2 ... รอบที่ 3 (คำตอบคือ 2 เหมือนกัน) ... ทำไปเรื่อยๆ (คือการเพิ่มตัวคูณเข้าไปทีละ 1)
จะเห็นว่าหลักทั้ง 3 หรือ 3 ปุ่ม (Button) ในแต่ละแถว จะมีค่าคงที่ตลอด ไม่มีการเปลี่ยนค่าเลย จึงทำให้ตำแหน่ง Top ในแต่ละแถวเท่ากันเสมอ
เอาค่าที่ได้จากการหารตัดเศษในแต่ละแถว X (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล)
แถว 1 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 0 ดังนั้น Top = 0
แถว 2 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 1 ดังนั้น Top = (ความสูงของ Button+ความสูงของ Label) X 1
แถว 3 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 2 ดังนั้น Top = (ความสูงของ Button+ความสูงของ Label) X 2
B.Top = (iCount \ ColCount) * (B.Height + LB.Height)

มาดูโค้ดฉบับเต็มกันเถอะ ...
  1. Public Class frmFoodDrinkMain

  2.     '/ กำหนดตำแหน่งการเก็บไฟล์ภาพ ... โฟลเดอร์เก็บ Execute File\Images\
  3.     Dim strImagePath As String = MyPath(Application.StartupPath & "Images")

  4.     ' / --------------------------------------------------------------------------------
  5.     '/ ฟังค์ชั่นในการกำหนดพาธให้กับโปรแกรม
  6.     Private Function MyPath(ByVal AppPath As String) As String
  7.         MyPath = AppPath.ToLower.Replace("\bin\debug", "").Replace("\bin\release", "").Replace("\bin\x86\debug", "")
  8.         '/ ASCII Code (92) = \ (Backslash)
  9.         If Microsoft.VisualBasic.Right(MyPath, 1) <> Chr(92) Then MyPath = MyPath & Chr(92)
  10.     End Function

  11.     ' / --------------------------------------------------------------------------------
  12.     '/ Don't forget to set Form has KeyPreview = True
  13.     '/ เวลาทำการ Debugger ให้ปิด Handle ที่เหตุการณ์นี้
  14.     Private Sub frmFoodDrinkMain_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
  15.         Select Case e.KeyCode
  16.             Case Keys.F8
  17.                 '/ Remove Row
  18.                 Call DeleteRow("btnDelRow")
  19.         End Select
  20.     End Sub

  21.     ' / --------------------------------------------------------------------------------
  22.     '// START HERE
  23.     Private Sub frmFoodDrinkMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  24.         Me.KeyPreview = True  '/ สามารถกดปุ่มฟังค์ชั่นคีย์ลงในฟอร์มได้
  25.         Call InitializeGrid()
  26.         '// สร้าง TabPage แล้วตามด้วยสร้าง Panel จากนั้นให้สร้างปุ่มคำสั่ง (Button) ตามจำนวนรายการสินค้าที่อยู่ในแต่ละกลุ่ม/ประเภท
  27.         Call AddTabPage()
  28.         '//
  29.         txtSumTotal.ReadOnly = True
  30.         txtSumTotal.Text = "0.00"
  31.         lblLastPrice.Text = ""
  32.     End Sub

  33.     ' / --------------------------------------------------------------------------------
  34.     '// เพิ่มแท็บเพจ (TabPage) คอนโทรลแบบไดนามิคลงไปใน TabControl1
  35.     ' / --------------------------------------------------------------------------------
  36.     Private Sub AddTabPage()
  37.         Dim CatDataTable As New DataTable
  38.         '/ Remove First TabPage
  39.         Me.TabControl1.TabPages.Remove(TabPage1)
  40.         '// รับข้อมูลสมมุติมาจากตารางข้อมูล (DataTable) ในการจัดกลุ่ม/ประเภท (Category)
  41.         CatDataTable = GetCatDataTable()
  42.         '/ สร้าง Panel ตามจำนวนของกลุ่ม/ประเภท (Category) ในตัวอย่างมี 4 กลุ่ม และกลุ่มรวม (ALL) รวมเป็น 5 กลุ่ม
  43.         Dim pn(CatDataTable.Rows.Count)
  44.         Dim iCat As Byte = 0
  45.         ' Loop and display the keys.
  46.         For Each CatRow As DataRow In CatDataTable.Rows
  47.             ' / Create a tabpage
  48.             Dim tabPg As New TabPage
  49.             ' / Set the tabpage to be your desired tab.
  50.             tabPg.Name = "Tab" & CStr(iCat)
  51.             '// แสดงชื่อกลุ่ม Category ใน TabPage
  52.             tabPg.Text = CatRow(1).ToString
  53.             '// เพิ่ม TabPage ลงใน TabControl1
  54.             Me.TabControl1.Controls.Add(tabPg)
  55.             '// เพิ่ม Panel
  56.             pn(iCat) = New Panel
  57.             pn(iCat).Name = "pn" & iCat
  58.             '/ สลับสีพื้นหลังของ Panel
  59.             With pn(iCat)
  60.                 If (iCat Mod 2) = 0 Then
  61.                     '/ เลขคู่แสดงสีนี้
  62.                     .BackColor = Color.Beige
  63.                 Else
  64.                     '/ เลขคี่แสดงสีนี้
  65.                     .BackColor = Color.PaleTurquoise
  66.                 End If
  67.                 '/ ปรับคุณสมบัติของ Panel แบบ Run-Time
  68.                 .Dock = DockStyle.Fill
  69.                 .Location = New System.Drawing.Point(1, 1)
  70.                 .Size = New System.Drawing.Size(TabControl1.Width - 10, TabControl1.Height - 30)
  71.                 .BackColor = Color.Moccasin
  72.                 .AutoScroll = True
  73.                 .Anchor = AnchorStyles.Bottom + AnchorStyles.Top
  74.             End With
  75.             '/ Add the panel into the TabControl
  76.             tabPg.Controls.Add(pn(iCat))
  77.             '/
  78.             Dim dt As New DataTable
  79.             dt = GetDataTable(CatRow(0).ToString)
  80.             ' / --------------------------------------------------------------------------------
  81.             '/ ไปที่โปรแกรมย่อยการเพิ่มปุ่มคำสั่ง (Button)
  82.             '/ รอบแรกจะแสดงผลรายการสินค้าทั้งหมด เพราะส่งค่า 0 ออกไป ไม่ตรงกับค่ากลุ่มใดๆ
  83.             '/ กำหนด 3 หลัก, นับจำนวนรายการเพื่อทำปุ่ม, Panel(กลุ่ม/ประเภทสินค้า), DataTable
  84.             Call AddButton(3, dt.Rows.Count, pn(iCat), dt)
  85.             ' / --------------------------------------------------------------------------------
  86.             iCat += 1
  87.             dt.Dispose()
  88.         Next
  89.         '/ ตั้งค่าที่แท็บเพจตัวแรก (ALL)
  90.         TabControl1.SelectedIndex = 0
  91.         CatDataTable.Dispose()
  92.     End Sub

  93.     ' / --------------------------------------------------------------------------------
  94.     '// เพิ่มปุ่มคำสั่งแบบไดนามิค ตามจำนวนในแต่ละกลุ่ม/ประเภทสินค้า
  95.     ' / --------------------------------------------------------------------------------
  96.     Private Sub AddButton(ByVal ColCount As Byte, ByVal btnCount As Byte, ByRef pn As Panel, ByRef dt As DataTable)
  97.         Dim iCount As Byte = 0
  98.         '/ วนรอบไปจนกว่าจำนวนปุ่ม (Button) มันเกินค่าที่มีอยู่
  99.         While btnCount <> iCount
  100.             Dim B As New Button
  101.             B.Height = 140
  102.             B.Width = 140
  103.             Dim LB As New Label
  104.             With LB
  105.                 .Height = 40
  106.                 .Width = 140
  107.                 '// สลับสีของป้ายลาเบล
  108.                 If iCount Mod 2 = 0 Then
  109.                     '// เลขคู่
  110.                     .BackColor = Color.Orange
  111.                 Else
  112.                     '// เลขคี่
  113.                     .BackColor = Color.Crimson
  114.                 End If
  115.             End With
  116.             pn.Controls.Add(B)  '/ Add Button
  117.             pn.Controls.Add(LB) '/ Add Label อยู่ด้านล่างของ Button
  118.             '// Button
  119.             With B
  120.                 ' / ตัวอย่างกำหนดเอาไว้ให้แสดงผลปุ่มคำสั่ง (Button) 3 หลัก
  121.                 ' / --------------------------------------------------------------------------------
  122.                 '// หาตำแหน่งซ้าย (Left) ... ด้วยการหารเอาเศษ (Mod) ด้วย 3 จะได้คำตอบ 0, 1, 2 ตลอด เพื่อใช้จัดวางตำแหน่งหลัก Button ได้ทีละ 3 หลัก
  123.                 '// การหารเอาเศษจะได้ค่าสูงสุด คือ ค่าตัวหาร (Mod) ลบออก 1 เช่น X Mod 3 จะได้ค่า 0, 1, 2 (หรือ 3 - 1 = 2)
  124.                 '// เริ่มนับจาก 0 ไปเรื่อยๆ
  125.                 '// 0 Mod 3 = 0, 1 Mod 3 = 1, 2 Mod 3 = 2 ... รอบที่ 1
  126.                 '// 3 Mod 3 = 0, 4 Mod 3 = 1, 5 Mod 3 = 2 ... รอบที่ 2
  127.                 '// 6 Mod 3 = 0, 7 Mod 3 = 1, 8 Mod 3 = 2 ... รอบที่ 3 ... ทำไปเรื่อยๆ
  128.                 '// มีคำตอบแค่ 0, 1, 2 เราก็เลยหาจำนวนหลักได้ตามที่กำหนด คือ 3 หลัก
  129.                 '// เอาค่าที่ได้แต่ละหลักมาคูณความกว้างของปุ่มคำสั่ง
  130.                 '// เป็นการเลื่อนตำแหน่งไปทางซ้าย ด้วยการคูณด้วย 0, 1 และ 2 เป็นจำนวนเท่าของความกว้างของ Button
  131.                 .Left = (iCount Mod ColCount) * B.Width
  132.                 ' / --------------------------------------------------------------------------------
  133.                 '/ Left ของ Button และ Label จะเท่ากัน
  134.                 LB.Left = B.Left
  135.                 ' / --------------------------------------------------------------------------------
  136.                 '// หาตำแหน่งบน (Top) ... ด้วยการหารตัดเศษ \ ... การหารปกติ 3 / 2 = 1.5, การหารตัดเศษ 3 \ 2 = 1
  137.                 '// เริ่มนับจาก 0 ไปเรื่อยๆ
  138.                 '// 0 \ 3 = 0, 1 \ 3 = 0, 2 \ 3 = 0 ... รอบที่ 1 (คำตอบคือ 0 เหมือนกัน)
  139.                 '// 3 \ 3 = 1, 4 \ 3 = 1, 5 \ 3 = 1 ... รอบที่ 2 (คำตอบคือ 1 เหมือนกัน)
  140.                 '// 6 \ 3 = 2, 7 \ 3 = 2, 8 \ 3 = 2 ... รอบที่ 3 (คำตอบคือ 2 เหมือนกัน) ... ทำไปเรื่อยๆ (คือการเพิ่มตัวคูณเข้าไปทีละ 1)
  141.                 '// จะเห็นว่าหลักทั้ง 3 หรือ 3 ปุ่ม (Button) ในแต่ละแถว จะมีค่าคงที่ตลอด ไม่มีการเปลี่ยนค่าเลย จึงทำให้ตำแหน่ง Top ในแต่ละแถวเท่ากันเสมอ
  142.                 '// เอาค่าที่ได้จากการหารตัดเศษในแต่ละแถว X (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล)
  143.                 '// แถว 1 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 0 ดังนั้น Top = 0
  144.                 '// แถว 2 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 1 ดังนั้น Top = (ความสูงของ Button+ความสูงของ Label) X 1
  145.                 '// แถว 3 จึงคูณ (ความสูงของปุ่มคำสั่ง+ความสูงของลาเบล) ด้วย 2 ดังนั้น Top = (ความสูงของ Button+ความสูงของ Label) X 2
  146.                 .Top = (iCount \ ColCount) * (B.Height + LB.Height)
  147.                 ' / --------------------------------------------------------------------------------
  148.                 Dim row As DataRow = dt.Rows(iCount)
  149.                 .Name = "Button" & row(0).ToString
  150.                 .Text = "ID : " & row(1).ToString
  151.                 '// นำค่า ProductPK (Primary Key) ไปซ่อนไว้ในคุณสมบัติ Tag ของ Button ในแต่ละตัว ซึ่งเราจะใช้ค่านี้เมื่อตอนคลิ๊กกดปุ่มคำสั่งในแต่ละตัว
  152.                 '// เพื่อนำไปเปรียบเทียบค่าในตารางกริด (หลัก 0) หรือการค้นหาข้อมูลสินค้าด้วยค่า Primary Key
  153.                 '// หรือใครที่กำหนดฟิลด์เอาไว้แค่ ID โดยไม่มี PK ... ก็ใช้ให้ ID ไปเลยก็ได้
  154.                 .Tag = row(0).ToString
  155.                 '// ทำการแสดงผลภาพลงบนปุ่ม
  156.                 Dim imgFile As String = strImagePath & row(4).ToString
  157.                 '/ ถ้าไม่ได้กำหนดรูป หรือหารูปภาพไม่เจอ ให้ใส่ภาพ NoImage.jpg ป้องกัน Error
  158.                 If Not System.IO.File.Exists(imgFile) Then imgFile = strImagePath & "NoImage.jpg"
  159.                 '/ นำภาพไปแสดงบน Button
  160.                 .BackgroundImage = New System.Drawing.Bitmap(imgFile)
  161.                 .BackgroundImageLayout = ImageLayout.Stretch
  162.                 '/ ปรับคุณสมบัติ Button
  163.                 .Font = New Font("Century Gothic", 10, FontStyle.Bold)
  164.                 .ForeColor = Color.Black
  165.                 .TextAlign = ContentAlignment.BottomCenter
  166.                 .TextImageRelation = TextImageRelation.ImageAboveText
  167.                 .UseVisualStyleBackColor = True
  168.                 .Cursor = Cursors.Hand
  169.                 .FlatStyle = FlatStyle.Standard
  170.                 '// ปรับคุณสมบัติของ Label
  171.                 With LB
  172.                     .TextAlign = ContentAlignment.MiddleCenter
  173.                     .Top = B.Top + B.Height
  174.                     .ForeColor = Color.White
  175.                     .Font = New Font("Tahoma", 10, FontStyle.Bold)
  176.                     '/ Label ป้ายบอกเพื่อแสดงราคาใน Label
  177.                     .Text = row(2).ToString & vbCrLf & "ราคา: " & Format(Convert.ToDecimal(row(3).ToString), "#,##0.00")
  178.                 End With
  179.             End With
  180.             iCount += 1
  181.             ' / --------------------------------------------------------------------------------
  182.             '// Event Handler ในการกดคลิ๊กที่ปุ่มคำสั่ง (Button)
  183.             AddHandler B.Click, AddressOf ClickButton
  184.             ' / --------------------------------------------------------------------------------
  185.         End While
  186.     End Sub

  187.     ' / --------------------------------------------------------------------------------
  188.     Public Sub ClickButton(ByVal sender As Object, ByVal e As System.EventArgs)
  189.         Dim btn As Button = sender
  190.         'MessageBox.Show("Primary Key: " & btn.Tag)
  191.         '/ นำ Tag ซึ่งเก็บค่า ProductPK ไปใช้งานในการค้นหาสินค้า
  192.         Call AddToDataGridView(btn.Tag)
  193.     End Sub

  194.     ' / --------------------------------------------------------------------------------
  195.     ' / ค้นหารายการสินค้าของเดิมในตารางกริด ก่อนที่จะเพิ่มรายการแถวใหม่
  196.     ' / อันนี้เขียนโค้ดกลับด้านกับเหตุการณ์ txtSearch_KeyPress
  197.     ' / โดยใช้ค่า ProductPK (Primary Key ที่เป็นเลขจำนวนเต็ม) มาเปรียบเทียบกับค่าในตารางกริดก่อน
  198.     ' / หากหาข้อมูลในตารางกริดไม่เจอ ก็จะไปค้นจาก DataTable อีกที
  199.     ' / --------------------------------------------------------------------------------
  200.     Private Sub AddToDataGridView(ByVal PK As Integer)
  201.         Dim blnExist As Boolean = False
  202.         '// ตรวจสอบว่า Primary Key มีอยู่ในตารางกริดหรือไม่ (หากมีให้ +เพิ่ม, หากไม่มีค่อยไปค้นหาข้อมูล)
  203.         For iRow As Integer = 0 To dgvData.RowCount - 1
  204.             ' / หากพบ Primary Key ในหลัก 0 มาตรงกันกับค่าในแถวของตารางกริด
  205.             ' / ค่า Primary Key (PK) ตัวนี้ได้จากการกดปุ่ม (Button) โดยซ่อนค่าไว้ในคุณสมบัติ Tag ของ Button
  206.             If dgvData.Rows(iRow).Cells(0).Value = PK Then
  207.                 ' / ให้บวกจำนวนที่เลือกเพิ่มขึ้นอีก 1 (Quantity = Quantity + 1)
  208.                 dgvData.Rows(iRow).Cells(3).Value = dgvData.Rows(iRow).Cells(3).Value + 1
  209.                 '/ หลัก Index = 4 คือ UnitPrice
  210.                 lblLastPrice.Text = "Last Price: " & Format(CDbl(dgvData.Rows(iRow).Cells(4).Value), "#,##0.00")
  211.                 '// เจอข้อมูลเดิม
  212.                 blnExist = True
  213.                 '// ออกจากลูปไปเลย เพื่อไม่ให้เสียเวลา
  214.                 Exit For
  215.             End If
  216.         Next
  217.         '// ไม่พบข้อมูลในตารางกริด ก็ทำการเรียกจากตารางข้อมูลเข้ามาแสดงผล
  218.         If Not blnExist Then
  219.             '/ สร้าง DataTable สมมุติขึ้นมา
  220.             Dim DT As DataTable = GetDataTable()
  221.             '/ ค้นหาข้อมูลจาก DataTable แล้วรับค่ามาใส่ไว้ใน DataRow
  222.             '/ การค้นหาข้อมูลแบบเลขจำนวนเต็ม เช่น ProductPK = 1
  223.             Dim r() As DataRow = DT.Select(" ProductPK = " & PK)
  224.             '// หากพบข้อมูลใน DataTable
  225.             If r.Count > 0 Then
  226.                 '/ จากโครงสร้าง DataTable
  227.                 '/ Primary Key, Product ID, Product Name, Quantity, UnitPrice, Total
  228.                 dgvData.Rows.Add(r(0).Item(0), r(0).Item(1), r(0).Item(2), "1", Format(CDbl(r(0).Item(3).ToString), "0.00"), "0.00")
  229.                 lblLastPrice.Text = "Last Price: " & CDbl(r(0).Item(3)).ToString("0.00")
  230.             End If
  231.             DT.Dispose()
  232.         End If
  233.         '// หาจำนวนเงินรวมใหม่
  234.         Call CalSumTotal()
  235.         '// โฟกัสไปที่ DataGridView แล้วย้ายไปแถวล่าสุด และไปทางซ้ายเพื่อไปที่ช่องจำนวน (Quantity)
  236.         'dgvData.Focus()
  237.         'SendKeys.Send("^{END}{LEFT}{LEFT}{LEFT}")
  238.     End Sub

  239.     ' / --------------------------------------------------------------------------------
  240.     ' / DataTable ของกลุ่ม/ประเภทสินค้า (Category)
  241.     ' / --------------------------------------------------------------------------------
  242.     Function GetCatDataTable() As DataTable
  243.         Dim DT As New DataTable
  244.         With DT
  245.             .Columns.Add("CategoryPK", GetType(Byte)) '<<< Index = 0
  246.             .Columns.Add("CategoryName", GetType(String))    '<< Index = 1
  247.         End With
  248.         '// ... Add rows in the Category.
  249.         With DT
  250.             .Rows.Add(0, "ALL")
  251.             .Rows.Add(1, "Coffee")
  252.             .Rows.Add(2, "Burger")
  253.             .Rows.Add(3, "Soft Drink")
  254.             .Rows.Add(4, "Beverages")
  255.         End With
  256.         Return DT
  257.     End Function

  258.     ' / --------------------------------------------------------------------------------
  259.     ' / S A M P L E ... D A T A T A B L E (Products)
  260.     ' / --------------------------------------------------------------------------------
  261.     Function GetDataTable(Optional ByVal Cat As Byte = 0) As DataTable
  262.         '// Add Column
  263.         Dim DT As New DataTable
  264.         With DT
  265.             .Columns.Add("ProductPK", GetType(Integer)) '<< Index = 0
  266.             .Columns.Add("ProductID", GetType(String))    '<< 1
  267.             .Columns.Add("ProductName", GetType(String)) '<< 2
  268.             .Columns.Add("UnitPrice", GetType(Double)) '<< 3
  269.             .Columns.Add("PictureName", GetType(String)) '<< 4
  270.             .Columns.Add("CategoryFK", GetType(Byte))   '<< 5 (เอากลุ่ม/ประเภทสินค้า Foreign Key มาไว้ท้ายสุด เพราะในตารางข้อมูลจริงจะเชื่อมความสัมพันธ์กัน)
  271.         End With
  272.         '// ... Add rows in the first category. (1 - Coffee)
  273.         '/ ProductPK, ProductID, ProductName, UnitPrice, PictureName, CategoryFK
  274.         With DT.Rows
  275.             .Add(1, "01", "กาแฟร้อน", "50.00", "Coffee.jpg", 1)
  276.             .Add(2, "02", "กาแฟเย็น", "60.00", "Coffee4.png", 1)
  277.             .Add(3, "03", "คาปูชิโน่", "75.00", "Cappuccino.jpg", 1)
  278.             .Add(4, "04", "คาปูชิโน่ - ลาเต้", "80.00", "CappuccinoLatte.jpg", 1)
  279.             .Add(5, "05", "เอ็กซ์เพรสโซ่", "90.00", "Expresso.jpg", 1)
  280.         End With
  281.         '// ... Add rows in category. (2 - Burger)
  282.         With DT.Rows
  283.             .Add(11, "11", "Classic Chicken", "20.00", "BurgerChicken.png", 2)
  284.             .Add(12, "12", "Mexicana", "25.00", "BurgerMexicana.png", 2)
  285.             .Add(13, "13", "Lemon Shrimp", "30.00", "BurgerLemonShrimp.png", 2)
  286.             .Add(14, "14", "Bacon", "40.00", "BurgerBacon.png", 2)
  287.             .Add(15, "15", "Spicy Shrimp", "45.00", "BurgerSpicyShrimp.png", 2)
  288.             .Add(16, "16", "Tex Supreme", "50.00", "BurgerTexSupreme.png", 2)
  289.             .Add(17, "17", "Fish", "55.00", "BurgerFish.png", 2)
  290.         End With
  291.         '// ... Add rows in category. (3 - Soft Drink)
  292.         With DT.Rows
  293.             .Add(21, "21", "Pepsi Can", "20.00", "PepsiCan.png", 3)
  294.             .Add(22, "22", "Coke Can", "20.00", "CokeCan.png", 3)
  295.             .Add(23, "23", "7Up Can", "20.00", "7upCan.png", 3)
  296.             .Add(24, "24", "Pepsi 2 ลิตร", "50.00", "Pepsi2L.jpg", 3)
  297.             .Add(25, "25", "Coke 2 ลิตร", "50.00", "Coke2L.jpg", 3)
  298.             .Add(26, "26", "น้ำเปล่า", "15.00", "Water.jpg", 3)
  299.         End With
  300.         '// ... Add rows in category. (4 - Whisky)
  301.         With DT.Rows
  302.             .Add(41, "41", "วิสกี้ (เพียว)", "100.00", "Whisky.jpg", 4)
  303.             .Add(42, "42", "เหล้าขาว (เป๊ก)", "40.00", "Pek.png", 4)
  304.             .Add(43, "43", "ม้ากระทืบโรง (เป๊ก)", "50.00", "Horse.jpg", 4)
  305.             .Add(44, "44", "เบียร์สิงห์ (กระป๋อง)", "80.00", "SinghaCan.jpg", 4)
  306.             .Add(45, "45", "เบียร์ลีโอ (กระป๋อง)", "70.00", "LeoCan.jpg", 4)
  307.             .Add(46, "46", "เบียร์ช้าง (กระป๋อง)", "70.00", "ChangCan.jpg", 4)
  308.             .Add(47, "47", "Spy Wine Cooler", "50.00", "Spy.jpg", 4)
  309.             .Add(48, "48", "โซจู (สตรอเบอรี่)", "90.00", "Soju.jpg", 4)
  310.         End With
  311.         '// กรองเอาเฉพาะพวกที่แบ่งกลุ่ม/ประเภทสินค้า โดยมีการค้นหาด้วย CategoryFK (หลักสุดท้ายใน DataTable)
  312.         If Cat > 0 Then
  313.             Dim Result() As DataRow = DT.Select("CategoryFK = " & Cat)
  314.             Dim MyDT As New DataTable
  315.             If Not Result.Length = 0 Then MyDT = Result.CopyToDataTable
  316.             Return MyDT
  317.             '// เอาข้อมูลสินค้าทั้งหมด
  318.         Else
  319.             Return DT
  320.         End If
  321.     End Function

  322.     ' / --------------------------------------------------------------------------------
  323.     ' / ตั้งค่าเริ่มต้นให้กับ DataGridView แบบ Run Time (ใช้โค้ดทั้งหมด)
  324.     Private Sub InitializeGrid()
  325.         With dgvData
  326.             .RowHeadersVisible = False
  327.             .AllowUserToAddRows = False
  328.             .AllowUserToDeleteRows = False
  329.             .AllowUserToResizeRows = False
  330.             .MultiSelect = False
  331.             .ReadOnly = False
  332.             .RowTemplate.MinimumHeight = 27
  333.             .RowTemplate.Height = 27
  334.             '/ Columns Specified
  335.             '/ Index = 0
  336.             .Columns.Add("PK", "Primary Key")
  337.             With .Columns("PK")
  338.                 .ReadOnly = True
  339.                 .DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
  340.                 .Visible = False '/ ปกติหลัก Primary Key จะต้องถูกซ่อนไว้
  341.             End With
  342.             '/ Index = 1
  343.             .Columns.Add("ProductID", "Product ID")
  344.             .Columns("ProductID").ReadOnly = True
  345.             .Columns("ProductID").Visible = False
  346.             '/ Index = 2
  347.             .Columns.Add("ProductName", "Product Name")
  348.             .Columns("ProductName").ReadOnly = True
  349.             .Columns("ProductName").DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
  350.             '/ Index = 3
  351.             .Columns.Add("Quantity", "Quantity")
  352.             .Columns("Quantity").ValueType = GetType(Integer)
  353.             '/ Index = 4
  354.             .Columns.Add("UnitPrice", "Unit Price")
  355.             .Columns("UnitPrice").ValueType = GetType(Double)
  356.             '/ Index = 5
  357.             .Columns.Add("Total", "Total")
  358.             .Columns("Total").ValueType = GetType(Double)
  359.             .Font = New Font("Tahoma", 11)
  360.             '/ Total Column (5)
  361.             With .Columns("Total")
  362.                 .ReadOnly = True
  363.                 .DefaultCellStyle.BackColor = Color.LightGoldenrodYellow
  364.                 .DefaultCellStyle.ForeColor = Color.Blue
  365.                 .DefaultCellStyle.Font = New Font(dgvData.Font, FontStyle.Bold)
  366.             End With
  367.             '// เพิ่มปุ่มลบ (Index = 6)
  368.             Dim btnDelRow As New DataGridViewButtonColumn
  369.             dgvData.Columns.Add(btnDelRow)
  370.             With btnDelRow
  371.                 .HeaderText = "Delete F8"
  372.                 .Text = "Delete"
  373.                 .UseColumnTextForButtonValue = True
  374.                 .Width = 30
  375.                 .ReadOnly = True
  376.                 .HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter
  377.                 .SortMode = DataGridViewColumnSortMode.NotSortable  '/ Not sort order but can click header for delete row.
  378.             End With
  379.             '/ Alignment MiddleRight only columns 3 to 5
  380.             For i As Byte = 3 To 5
  381.                 '/ Header Alignment
  382.                 .Columns(i).HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleRight
  383.                 '/ Cell Alignment
  384.                 .Columns(i).DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleRight
  385.             Next
  386.             '/ Auto size column width of each main by sorting the field.
  387.             .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
  388.             '/ Adjust Header Styles
  389.             With .ColumnHeadersDefaultCellStyle
  390.                 .BackColor = Color.RoyalBlue
  391.                 .ForeColor = Color.White
  392.                 .Font = New Font("Tahoma", 11, FontStyle.Bold)
  393.             End With
  394.             .ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing
  395.             .ColumnHeadersHeight = 36
  396.             '/ กำหนดให้ EnableHeadersVisualStyles = False เพื่อให้ยอมรับการเปลี่ยนแปลงสีพื้นหลังของ Header
  397.             .EnableHeadersVisualStyles = False
  398.         End With

  399.     End Sub

  400.     ' / --------------------------------------------------------------------------------
  401.     ' / การค้นหาข้อมูลในช่อง TextBox
  402.     ' / --------------------------------------------------------------------------------
  403.     Private Sub txtSearch_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtSearch.KeyPress
  404.         '// เมื่อกดคีย์ ENTER เพื่อเริ่มต้นการค้นหาข้อมูล
  405.         If e.KeyChar = Chr(13) Then
  406.             '/ Replace some word for reserved in DataBase.
  407.             txtSearch.Text = txtSearch.Text.Trim.Replace("'", "").Replace("*", "").Replace("%", "")
  408.             e.Handled = True    '// ปิดเสียง
  409.             '/ สร้าง DataTable สมมุติขึ้นมา
  410.             Dim DT As DataTable = GetDataTable()
  411.             '/ ค้นหาข้อมูลจาก DataTable แล้วรับค่ามาใส่ไว้ใน DataRow
  412.             '/ การค้นหาข้อมูลแบบ String จะต้องใส่เครื่องหมาย Single Quote ครอบเอาไว้ เช่น ProductID = '01'
  413.             Dim r() As DataRow = DT.Select(" ProductID = " & "'" & txtSearch.Text.Trim & "'")
  414.             '// หากพบข้อมูลใน DataTable
  415.             If r.Count > 0 Then
  416.                 '/ ตัวแปรบูลีน Flag แจ้งการค้นหาข้อมูลในตารางกริด (True = พบรายการในแถว, False = ไม่พบ)
  417.                 Dim blnExist As Boolean = False
  418.                 '/ ต้องค้นหาข้อมูลจากตารางกริดก่อน เพื่อค้นหาว่ามีรายการสินค้าเดิมหรือไม่?
  419.                 '/ หากในตารางกริดยังไม่มีแถวรายการ ก็จะข้าม For Loop นี้ไปเพิ่มรายการใหม่ทันที (ครั้งแรกที่ยังไม่มีข้อมูลในตารางกริด)
  420.                 For iRow As Integer = 0 To dgvData.RowCount - 1
  421.                     '/ ทดสอบด้วย Primary Key r(0).Item(0) หรือ Product ID r(0).Item(1) ก็ได้
  422.                     If r(0).Item(0) = dgvData.Rows(iRow).Cells(0).Value Then
  423.                         '/ เมื่อพบรายการเดิม ก็ให้เพิ่มจำนวนขึ้น 1
  424.                         dgvData.Rows(iRow).Cells(3).Value += 1
  425.                         lblLastPrice.Text = "Last Price: " & CDbl(dgvData.Rows(iRow).Cells(4).Value).ToString("0.00")
  426.                         '/ Flag แจ้งว่าพบข้อมูลเดิมแล้ว
  427.                         blnExist = True
  428.                         '/ เมื่อเจอสินค้าเดิมในตารางกริดแล้ว ไม่ว่าจะอยู่แถวลำดับที่เท่าไหร่ ก็ให้ออกจาก For Loop การค้นหาได้เลย
  429.                         '/ เพราะรายการสินค้าใดๆ จะต้องมีอยู่เพียงแค่รายการเดียว ไม่ต้องเสียเวลาวนรอบกลับไปทำให้จนครบจำนวนแถว
  430.                         Exit For
  431.                     End If
  432.                 Next
  433.                 '/ กรณีที่พบสินค้าในตารางกริด กำหนด blnExist = True ทำให้ Not True = False จะทำให้ข้ามเงื่อนไขนี้ออกไป
  434.                 '/ กรณีที่ไม่พบข้อมูลสินค้าเดิมในตารางกริด กำหนด blnExist = False ทำให้ Not False = True เพิ่มรายการสินค้าแถวใหม่เข้าไปในตารางกริดได้
  435.                 If Not blnExist Then
  436.                     '/ Primary Key, Product ID, Product Name, Quantity, UnitPrice, Total
  437.                     dgvData.Rows.Add(r(0).Item(0), r(0).Item(1), r(0).Item(2), "1", Format(CDbl(r(0).Item(3).ToString), "0.00"), "0.00")
  438.                     lblLastPrice.Text = "Last Price: " & CDbl(r(0).Item(3)).ToString("0.00")
  439.                 End If
  440.                 '/ หากไม่ใช้ NOT ก็จะต้องเขียนโปรแกรมแบบนี้
  441.                 '/ If blnExist = True Then
  442.                 '/     ไม่ต้องทำอะไร
  443.                 '/ Else
  444.                 '/     ทำคำสั่งเพิ่มรายการ
  445.                 '/ End If
  446.                 '// คำนวณผลรวมใหม่
  447.                 Call CalSumTotal()
  448.                 DT.Dispose()
  449.             End If
  450.             txtSearch.Clear()
  451.             txtSearch.Focus()
  452.         End If
  453.     End Sub

  454.     ' / --------------------------------------------------------------------------------
  455.     ' / Calcualte sum of Total (Column Index = 5)
  456.     ' / ทำทุกครั้งที่มีการเพิ่มหรือลบแถวรายการ และมีการเปลี่ยนแปลงค่าในเซลล์ Quantity, UnitPrice
  457.     Private Sub CalSumTotal()
  458.         txtSumTotal.Text = "0.00"
  459.         '/ วนรอบตามจำนวนแถวที่มีอยู่ปัจจุบัน
  460.         For i As Integer = 0 To dgvData.RowCount - 1
  461.             '/ หลักสุดท้ายของตารางกริด = [จำนวน x ราคา]
  462.             dgvData.Rows(i).Cells(5).Value = Format(dgvData.Rows(i).Cells(3).Value * dgvData.Rows(i).Cells(4).Value, "#,##0.00")
  463.             '/ นำค่าจาก Total มารวมกันเพื่อแสดงผลในสรุปผลรวม (x = x + y)
  464.             txtSumTotal.Text = Format(CDbl(txtSumTotal.Text) + CDbl(dgvData.Rows(i).Cells(5).Value), "#,##0.00")
  465.         Next
  466.     End Sub

  467.     ' / --------------------------------------------------------------------------------
  468.     ' / โปรแกรมย่อยในการลบแถวรายการที่เลือกออกไป
  469.     Private Sub DeleteRow(ByVal ColName As String)
  470.         If dgvData.RowCount = 0 Then Return
  471.         '/ ColName เป็นชื่อของหลัก Index = 6 ของตารางกริด (ไปดูที่โปรแกรมย่อย InitializeGrid)
  472.         If ColName = "btnDelRow" Then
  473.             '// ลบรายการแถวที่เลือกออกไป
  474.             dgvData.Rows.Remove(dgvData.CurrentRow)
  475.             '/ เมื่อแถวรายการถูกลบออกไป ต้องไปคำนวณหาค่าผลรวมใหม่
  476.             Call CalSumTotal()
  477.         End If
  478.         txtSearch.Focus()
  479.     End Sub

  480.     ' / --------------------------------------------------------------------------------
  481.     ' / ปุ่มลดจำนวนสินค้าลงทีละ 1 ... แถวของตารางกริดที่ถูกโฟกัส
  482.     Private Sub btnDecrement_Click(sender As System.Object, e As System.EventArgs) Handles btnDecrement.Click
  483.         If dgvData.RowCount = 0 Then Return
  484.         dgvData.Focus()
  485.         For iRow As Integer = 0 To dgvData.RowCount - 1
  486.             ' / หากพบ Primary Key ในหลัก 0 มาตรงกันกับค่าปัจจุบันในแถวของตารางกริด
  487.             If dgvData.Rows(iRow).Cells(0).Value = dgvData.CurrentRow.Cells(0).Value Then
  488.                 If dgvData.Rows(iRow).Cells(3).Value = 0 Then
  489.                     '/ หรือหากจำนวนมีค่าเป็น 0 ก็ลบแถวออกไปเลย
  490.                     'dgvData.Rows.Remove(dgvData.CurrentRow)
  491.                     'dgvData.Refresh()
  492.                     Exit For
  493.                 Else
  494.                     ' / ให้ลดจำนวนลง 1 (Quantity = Quantity - 1)
  495.                     dgvData.Rows(iRow).Cells(3).Value -= 1
  496.                     Exit For
  497.                 End If
  498.             End If
  499.         Next
  500.         '// รวมจำนวนเงิน
  501.         Call CalSumTotal()
  502.     End Sub

  503.     ' / --------------------------------------------------------------------------------
  504.     ' / ปุ่มเพิ่มจำนวนสินค้าขึ้นทีละ 1 ... แถวของตารางกริดที่ถูกโฟกัส
  505.     Private Sub btnIncrement_Click(sender As System.Object, e As System.EventArgs) Handles btnIncrement.Click
  506.         If dgvData.RowCount = 0 Then Return
  507.         dgvData.Focus()
  508.         For iRow As Integer = 0 To dgvData.RowCount - 1
  509.             ' / หากพบ Primary Key ในหลัก 0 มาตรงกันกับค่าปัจจุบันในแถวของตารางกริด
  510.             If dgvData.Rows(iRow).Cells(0).Value = dgvData.CurrentRow.Cells(0).Value Then
  511.                 ' / ให้เพิ่มจำนวนขึ้น 1 (Quantity = Quantity + 1)
  512.                 dgvData.Rows(iRow).Cells(3).Value += 1
  513.                 Exit For
  514.             End If
  515.         Next
  516.         '// รวมจำนวนเงิน
  517.         Call CalSumTotal()
  518.     End Sub

  519.     Private Sub dgvData_CellClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvData.CellClick
  520.         Select Case e.ColumnIndex
  521.             '// Delete Button
  522.             Case 6
  523.                 'MsgBox(("Row : " + e.RowIndex.ToString & "  Col : ") + e.ColumnIndex.ToString)
  524.                 Call DeleteRow("btnDelRow")
  525.         End Select
  526.     End Sub

  527.     ' / --------------------------------------------------------------------------------
  528.     ' / After you press Enter
  529.     Private Sub dgvData_CellEndEdit(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvData.CellEndEdit
  530.         '/ เกิดการเปลี่ยนแปลงค่าในหลัก Index ที่ 3 หรือ 4
  531.         Select Case e.ColumnIndex
  532.             Case 3, 4 '/ Column Index = 3 (Quantity), Column Index = 4 (UnitPrice)
  533.                 '/ Quantity
  534.                 '/ การดัก Error กรณีมีค่า Null Value ให้ใส่ค่า 0 ลงไปแทน
  535.                 If IsDBNull(dgvData.Rows(e.RowIndex).Cells(3).Value) Then dgvData.Rows(e.RowIndex).Cells(3).Value = "0"
  536.                 Dim Quantity As Integer = dgvData.Rows(e.RowIndex).Cells(3).Value
  537.                 '/ UnitPrice
  538.                 '/ If Null Value
  539.                 If IsDBNull(dgvData.Rows(e.RowIndex).Cells(4).Value) Then dgvData.Rows(e.RowIndex).Cells(4).Value = "0.00"
  540.                 Dim UnitPrice As Double = dgvData.Rows(e.RowIndex).Cells(4).Value
  541.                 dgvData.Rows(e.RowIndex).Cells(4).Value = Format(CDbl(dgvData.Rows(e.RowIndex).Cells(4).Value), "0.00")

  542.                 '/ Quantity x UnitPrice
  543.                 dgvData.Rows(e.RowIndex).Cells(5).Value = CDbl((Quantity * UnitPrice).ToString("#,##0.00"))
  544.                 '/ Calculate Summary
  545.                 Call CalSumTotal()
  546.         End Select
  547.     End Sub

  548.     ' / --------------------------------------------------------------------------------
  549.     Private Sub dgvData_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles dgvData.EditingControlShowing
  550.         Select Case dgvData.Columns(dgvData.CurrentCell.ColumnIndex).Name
  551.             ' / Can use both Colume Index or Field Name
  552.             Case "Quantity", "UnitPrice"
  553.                 '/ Stop and Start event handler
  554.                 RemoveHandler e.Control.KeyPress, AddressOf ValidKeyPress
  555.                 AddHandler e.Control.KeyPress, AddressOf ValidKeyPress
  556.         End Select
  557.     End Sub

  558.     ' / --------------------------------------------------------------------------------
  559.     Private Sub ValidKeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
  560.         Dim tb As TextBox = sender
  561.         Select Case dgvData.CurrentCell.ColumnIndex
  562.             Case 3  ' Quantity is Integer
  563.                 Select Case e.KeyChar
  564.                     Case "0" To "9"   ' digits 0 - 9 allowed
  565.                     Case ChrW(Keys.Back)    ' backspace allowed for deleting (Delete key automatically overrides)

  566.                     Case Else ' everything else ....
  567.                         ' True = CPU cancel the KeyPress event
  568.                         e.Handled = True ' and it's just like you never pressed a key at all
  569.                 End Select

  570.             Case 4  ' UnitPrice is Double
  571.                 Select Case e.KeyChar
  572.                     Case "0" To "9"
  573.                         ' Allowed "."
  574.                     Case "."
  575.                         ' can present "." only one
  576.                         If InStr(tb.Text, ".") Then e.Handled = True

  577.                     Case ChrW(Keys.Back)
  578.                         '/ Return False is Default value

  579.                     Case Else
  580.                         e.Handled = True

  581.                 End Select
  582.         End Select
  583.     End Sub

  584.     Private Sub frmFoodDrinkMain_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
  585.         Me.Dispose()
  586.         GC.SuppressFinalize(Me)
  587.         Application.Exit()
  588.     End Sub

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

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

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

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

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

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

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

GMT+7, 2024-4-25 08:33 , Processed in 0.262260 second(s), 4 queries , File On.

Powered by Discuz! X3.4, Rev.62

Copyright © 2001-2020 Tencent Cloud.

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