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

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

[VB.NET] การสร้าง User Control และ Custom Control โปรเจคการสั่งซื้ออาหารเครื่องดื่ม บนจอแบบทัชสกรีน

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

319

กระทู้

511

โพสต์

6476

เครดิต

ผู้ดูแลระบบ

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

Rank: 9Rank: 9Rank: 9

เครดิต
6476
โพสต์ เมื่อวาน 15:20 | ดูโพสต์ทั้งหมด |โหมดอ่าน







การสร้าง User Control และ Custom Control โปรเจคการสั่งซื้ออาหารเครื่องดื่ม บนจอแบบทัชสกรีน ...
ครั้งที่แล้วได้แจกโค้ดที่นำหลักการ OOP (Object Oriented Programming) มาอธิบาย กับการใช้ Inherits TabControl หมายถึง Control ที่เราสร้างขึ้นมาใหม่ (FlatTabControl) จะได้รับคุณสมบัติ และพฤติกรรมทั้งหมดของ TabControl มาตรฐานของไมโครซอฟท์มาตั้งต้น แล้วเราก็สามารถ "โมดิฟาย" หรือ "Override" พฤติกรรมบางส่วนได้ด้วย เราจึงเรียก Control ใหม่นี้ว่า Custom Control หรือ Extended Control ...

Custom Control & User Control ...
1. FlatTabControl เป็น Custom Control เพราะสืบทอดมาจาก TabControl (Inherits TabControl) แล้ว Override การวาด (OnPaint) และเพิ่มพฤติกรรมของตัวเอง
2. ucFoodButton เป็น User Control คือการรวม Control หลายๆตัวเข้ามาประกอบร่างกันเพื่อสร้าง Control ขึ้นมาใหม่อีกตัว เพราะภายในประกอบด้วย PictureBox, Label, Panel หลายๆตัวรวมกันเป็นปุ่มสินค้า สาเหตุหลักๆที่ต้องสร้าง User Control ขึ้นมาใหม่ ก็คือ Control ที่มีอยู่ใช้งาน ยังไม่ตอบโจทย์ให้กับตัวเรานั่นเอง


อธิบายการทำงานของ Class FoodItem (แบบคร่าวๆล่ะกัน)
1. Class FoodItem เปรียบเสมือน "แบบฟอร์มเปล่า" หรือ "พิมพ์เขียว"
มันยังไม่เก็บข้อมูลอะไรเลย มันแค่บอกว่า "ถ้าจะมีสินค้าหนึ่งชิ้น มันจะต้องมีช่องให้กรอกอะไรบ้าง" เช่น ช่องรหัส (FoodID), ช่องชื่อ (FoodName), ช่องราคา (PriceCash)
Public Class FoodItem
    Public Property FoodPK As Integer      ' ช่องที่ 1: เก็บตัวเลข
    Public Property FoodID As String       ' ช่องที่ 2: เก็บข้อความ
    ' ... (อื่นๆ)
End Class

2. การเก็บข้อมูล (การสร้าง Object)
แบบฟอร์มเปล่าจะเก็บข้อมูลได้ ก็ต่อเมื่อเรา "พิมพ์ข้อมูลลงไป" หรือในภาษาโปรแกรมเรียกว่าการสร้าง Instance (Object) โดยใช้คำสั่ง New
' การสั่งให้คอมพิวเตอร์จองพื้นที่ในหน่วยความจำเพื่อสร้าง "สินค้า 1 ชิ้น"
Dim myBurger As New FoodItem()  
' การกรอกข้อมูลลงในช่องต่างๆ ของสินค้านั้น
myBurger.FoodPK = 1
myBurger.FoodName = "Classic Chicken"
myBurger.PriceCash = 45.00D
  1. ' Class FoodItem เป็น BluePrint หรือแม่แบบสำหรับสร้างวัตถุ (Object) ที่ใช้เก็บข้อมูลสินค้าแต่ละรายการ โดยมี Property ต่างๆ ดังนี้:
  2. Public Class FoodItem
  3.     Public Property FoodPK As Integer
  4.     Public Property FoodID As String
  5.     Public Property FoodName As String
  6.     Public Property PriceCash As Decimal
  7.     Public Property CategoryFK As Integer
  8.     Public Property PictureFood As String
  9. End Class
คัดลอกไปที่คลิปบอร์ด

การใช้ FoodItem แบบนี้ แทนที่จะส่งข้อมูลทีละตัว เช่น FoodPK, FoodName, PriceCash แต่เราส่งเป็น FoodItem เพียงตัวเดียว ทำให้โค้ดอ่านง่าย ขยายความสามารถในอนาคตได้สะดวก (เช่น เพิ่ม Discount, VatRate, Barcode, StockQty ก็ไม่ต้องเปลี่ยนเมธอดทุกตัว) และยังสอดคล้องกับหลัก OOP เรื่อง Encapsulation คือการรวมข้อมูลที่เกี่ยวข้องไว้ในอ็อบเจ็กต์เดียว

มาดูโค้ดต้นฉบับในฟอร์มหลัก (frmFoodOrder.vb)
  1. Imports System.Data
  2. Imports System.Drawing
  3. Imports System.IO

  4. ' ==========================================================
  5. ' ฟอร์มหลักสำหรับสั่งอาหาร
  6. ' จัดการโหลดข้อมูลและภาพทั้งหมดที่นี่
  7. ' รองรับ VB.NET 2010 / .NET Framework 4.0
  8. ' ==========================================================
  9. Public Class frmFoodOrder

  10.     ' ตัวแปรเก็บข้อมูล
  11.     Private dtCategories As New DataTable()
  12.     Private dtFoods As New DataTable()

  13.     ' ประกาศคอนโทรลแท็บแบบกำหนดเอง
  14.     Dim FlatTabControl1 As New FlatTabControl()

  15.     ' ตัวแปรเก็บ Path โฟลเดอร์ภาพ เพื่อไม่ต้องเรียกซ้ำๆ
  16.     Private imgRootPath As String = ""

  17.     Private Sub frmFoodOrder_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  18.         ' เตรียมตำแหน่งโฟลเดอร์รูปภาพไว้ก่อน (My Project\Images)
  19.         imgRootPath = Path.Combine(MyPath(Application.StartupPath), "Images")

  20.         ' ตั้งค่าคอนโทรลแท็บ
  21.         With FlatTabControl1
  22.             .Cursor = Cursors.Hand
  23.             .Dock = DockStyle.Fill
  24.             .DrawMode = TabDrawMode.OwnerDrawFixed
  25.             .Font = New Font("Tahoma", 10.0!, FontStyle.Bold)
  26.             .ItemSize = New Size(140, 50)
  27.             .Location = New Point(0, 0)
  28.             .Name = "FlatTabControl1"
  29.             .SelectedIndex = 0
  30.             .Size = New Size(749, 583)
  31.             .SizeMode = TabSizeMode.Fixed
  32.             .TabIndex = 0
  33.             .BackColor = Color.FromArgb(240, 240, 240)
  34.         End With
  35.         Me.Controls.Add(FlatTabControl1)

  36.         ' โหลดข้อมูลตัวอย่าง (DataTable)
  37.         LoadSampleData()
  38.         ' การสร้างแท็บตามหมวดหมู่อาหาร/เครื่องดื่ม
  39.         CreateDynamicTabs()
  40.     End Sub

  41.     ' โหลดข้อมูลตัวอย่างลง DataTable เพื่อดัดแปลงนำไปใช้กับระบบฐานข้อมูลได้เลยทันที
  42.     Private Sub LoadSampleData()
  43.         Dim culture As System.Globalization.CultureInfo = System.Globalization.CultureInfo.InvariantCulture

  44.         ' โครงสร้างและข้อมูลหมวดหมู่
  45.         With dtCategories.Columns
  46.             .Add("CategoryPK", GetType(Integer))
  47.             .Add("CategoryName", GetType(String))
  48.         End With
  49.         With dtCategories.Rows
  50.             .Add(1, "รายการทั้งหมด")
  51.             .Add(2, "เบอเกอร์")
  52.             .Add(3, "เครื่องดื่ม")
  53.             .Add(4, "อาหาร")
  54.             .Add(5, "Soft Drink")
  55.             .Add(6, "ของหวาน")
  56.         End With

  57.         ' โครงสร้างและข้อมูลรายการอาหาร
  58.         With dtFoods.Columns
  59.             .Add("FoodPK", GetType(Integer))
  60.             .Add("FoodID", GetType(String))
  61.             .Add("FoodName", GetType(String))
  62.             .Add("PriceCash", GetType(Decimal))
  63.             .Add("CategoryFK", GetType(Integer))
  64.             .Add("PictureFood", GetType(String))
  65.         End With
  66.         ' ตัวอย่างรายการอาหาร/เครื่องดื่ม
  67.         With dtFoods.Rows
  68.             ' ไลเรียงฟิลด์ข้อมูลจาก Database (เพื่อนำไปใช้ในการออกแบบตารางข้อมูล)
  69.             ' FoodPK, FoodID, FoodName, PriceCash, CategoryFK, PictureFood
  70.             .Add(1, "FD000001", "Classic Checken", Decimal.Parse("45.00", culture), 2, "BurgerChicken.png")
  71.             .Add(2, "FD000002", "Mexicana", Decimal.Parse("85.00", culture), 2, "BurgerMexicana.png")
  72.             .Add(3, "FD000003", "Lemon Shrimp", Decimal.Parse("110.00", culture), 2, "BurgerLemonShrimp.png")
  73.             .Add(4, "FD000004", "Bacon", Decimal.Parse("90.00", culture), 2, "BurgerBacon.png")
  74.             .Add(5, "FD000005", "Spicy Shrimp", Decimal.Parse("120.00", culture), 2, "BurgerSpicyShrimp.png")
  75.             .Add(6, "FD000006", "Tex Supreme", Decimal.Parse("80.00", culture), 2, "BurgerTexSupreme.png")
  76.             .Add(7, "FD000007", "Fish", Decimal.Parse("100.00", culture), 2, "BurgerFish.png")
  77.             .Add(8, "FD00008", "Special Meatballs", Decimal.Parse("65.00", culture), 2, "Burger1.png")
  78.             .Add(9, "FD00009", "Grilled Burgers", Decimal.Parse("45.50", culture), 2, "Burger2.png")
  79.             .Add(10, "FD000010", "Normal Burgers", Decimal.Parse("25.90", culture), 2, "Burger3.png")
  80.             .Add(11, "FD000011", "Burgers", Decimal.Parse("33.00", culture), 2, "Burger4.png")
  81.             .Add(12, "FD000012", "Caramel Pineapple", Decimal.Parse("55.00", culture), 2, "Burger5.png")
  82.             .Add(13, "FD000013", "Chicken Burger", Decimal.Parse("48.00", culture), 2, "Burger6.png")
  83.             .Add(14, "FD000014", "ส้มตำเบอเกอร์", Decimal.Parse("999.00", culture), 2, "SomtumBurger.png")
  84.             .Add(15, "FD000015", "Pepsi Small", Decimal.Parse("20.00", culture), 3, "PepsiCan.png")
  85.             .Add(16, "FD000016", "Coke Small", Decimal.Parse("20.00", culture), 3, "CocaColaCan.png")
  86.             .Add(17, "FD000017", "7Up Small", Decimal.Parse("20.00", culture), 3, "7UpCan.png")
  87.             .Add(18, "FD000018", "มอคค่า", Decimal.Parse("85.00", culture), 3, "Coffee5.png")
  88.             .Add(19, "FD000019", "อเมริกาโน่", Decimal.Parse("95.00", culture), 3, "Coffee2.png")
  89.             .Add(20, "FD000020", "เอ็กซเพรสโซ่", Decimal.Parse("115.00", culture), 3, "Coffee7.png")
  90.             .Add(21, "FD000021", "ชานมไข่มุก", Decimal.Parse("45.00", culture), 3, "Tea1.png")
  91.             .Add(22, "FD000022", "โอเลี้ยง", Decimal.Parse("195.00", culture), 3, "Coffee4.png")
  92.             .Add(23, "FD000023", "กาแฟเย็น", Decimal.Parse("950.00", culture), 3, "Coffee6.png")
  93.             .Add(24, "FD000024", "น้ำดื่ม", Decimal.Parse("40.00", culture), 3, "Water.jpg")
  94.             .Add(25, "FD000025", "ข้าวไข่เจียวหมูสับ", Decimal.Parse("95.00", culture), 4, "RiceOmelet.jpg")
  95.             .Add(26, "FD000026", "ข้าวผัดหมู", Decimal.Parse("150.00", culture), 4, "1.jpg")
  96.             .Add(27, "FD000027", "ข้าวกะเพราหมูสับ ไข่ดาวสุกๆ", Decimal.Parse("1200.00", culture), 4, "2.jpg")
  97.             .Add(28, "FD000028", "เหล้าเป็ก", Decimal.Parse("99.00", culture), 5, "Pek.png")
  98.             .Add(29, "FD000029", "ทับทิมกรอบ", Decimal.Parse("250.00", culture), 6, "Tubtimkrob.png")
  99.             .Add(30, "FD000030", "ขนมชั้น", Decimal.Parse("120.00", culture), 6, "Kanomchun.png")
  100.             .Add(31, "FD000031", "ลอดช่องน้ำกะทิ", Decimal.Parse("150.00", culture), 6, "LodChong.png")
  101.         End With
  102.     End Sub

  103.     ' สร้างแท็บและปุ่มรายการอาหารแบบไดนามิก
  104.     Private Sub CreateDynamicTabs()
  105.         FlatTabControl1.TabPages.Clear()

  106.         ' วนสร้างแท็บตามหมวดหมู่
  107.         For Each drCat As DataRow In dtCategories.Rows
  108.             Dim tabPage As New TabPage(drCat("CategoryName").ToString())
  109.             tabPage.Padding = New Padding(5)
  110.             tabPage.BackColor = Color.FromArgb(240, 240, 240)
  111.             tabPage.ForeColor = Color.Black

  112.             ' พื้นที่แสดงรายการแบบเลื่อนได้
  113.             Dim flowPanel As New FlowLayoutPanel()
  114.             With flowPanel
  115.                 .Dock = DockStyle.Fill
  116.                 .AutoScroll = True
  117.                 .WrapContents = True
  118.                 .FlowDirection = FlowDirection.LeftToRight
  119.                 .Padding = New Padding(5)
  120.                 .BackColor = Color.FromArgb(240, 240, 240)
  121.             End With

  122.             ' กรองรายการอาหารตามหมวดหมู่
  123.             Dim filterRows As DataRow()
  124.             If CInt(drCat("CategoryPK")) = 1 Then
  125.                 filterRows = dtFoods.Select()
  126.             Else
  127.                 filterRows = dtFoods.Select("CategoryFK = " & drCat("CategoryPK").ToString())
  128.             End If

  129.             ' สร้างปุ่มรายการอาหาร
  130.             ' สร้าง Object FoodItem ชั่วคราวเพื่อส่งให้ ucFoodButton (Class FooItem อยู่ที่ไฟล์ FoodItem.vb)
  131.             ' การใช้ FoodItem แบบนี้ แทนที่จะส่งข้อมูลทีละตัว เช่น FoodPK, FoodName, PriceCash แต่เราส่งเป็น FoodItem เพียงตัวเดียว
  132.             ' ทำให้โค้ดอ่านง่าย ขยายความสามารถในอนาคตได้สะดวก (เช่น เพิ่ม Discount, VatRate, Barcode, StockQty ก็ไม่ต้องเปลี่ยนเมธอดทุกตัว)
  133.             ' และยังสอดคล้องกับหลัก OOP เรื่อง Encapsulation คือการรวมข้อมูลที่เกี่ยวข้องไว้ในอ็อบเจ็กต์เดียว
  134.             For Each drFood As DataRow In filterRows
  135.                 ' 1. สร้าง Object ข้อมูลสินค้า
  136.                 Dim tempFood As New FoodItem() With {
  137.                     .FoodPK = CInt(drFood("FoodPK")),
  138.                     .FoodID = drFood("FoodID").ToString(),
  139.                     .FoodName = drFood("FoodName").ToString(),
  140.                     .PriceCash = CDec(drFood("PriceCash")),
  141.                     .CategoryFK = CInt(drFood("CategoryFK")),
  142.                     .PictureFood = drFood("PictureFood").ToString()
  143.                 }

  144.                 ' 2. โหลดรูปภาพที่ฟอร์มหลัก (จัดการทั้งหมดที่นี่)
  145.                 Dim btnImage As Image = Nothing
  146.                 Dim targetImgPath As String = Path.Combine(imgRootPath, tempFood.PictureFood)
  147.                 Dim defaultImgPath As String = Path.Combine(imgRootPath, "BurgerBW.png")
  148.                 ' ภาพอาหาร/เครื่องดื่ม
  149.                 If File.Exists(targetImgPath) Then
  150.                     Using bmp As New Bitmap(targetImgPath)
  151.                         btnImage = New Bitmap(bmp)
  152.                     End Using
  153.                     ' หากไม่พบชื่อไฟล์ภาพ ให้ใช้ภาพ BurgerBW.png แสดงผลแทน
  154.                 ElseIf File.Exists(defaultImgPath) Then
  155.                     Using bmp As New Bitmap(defaultImgPath)
  156.                         btnImage = New Bitmap(bmp)
  157.                     End Using
  158.                     ' หากไม่มีไฟล์ภาพ BurgerBW.png ก็ไม่ต้องแสดงผลภาพประกอบ
  159.                 Else
  160.                     btnImage = Nothing
  161.                 End If

  162.                 ' 3. ส่งทั้งข้อมูลและภาพไปให้ปุ่ม (User Control ชื่อไฟล์ ucFoodButton.vb)
  163.                 Dim uc As New ucFoodButton()
  164.                 uc.SetData(tempFood, btnImage)  ' Method SetData อยู่ที่ ucFoodButton.vb
  165.                 uc.Margin = New Padding(5)
  166.                 flowPanel.Controls.Add(uc)
  167.             Next
  168.             '
  169.             tabPage.Controls.Add(flowPanel)
  170.             FlatTabControl1.TabPages.Add(tabPage)
  171.         Next
  172.     End Sub

  173.     ' ปิดโปรแกรมและล้างหน่วยความจำ
  174.     Private Sub frmFoodOrder_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
  175.         Me.Dispose()
  176.         GC.SuppressFinalize(Me)
  177.         Application.Exit()
  178.     End Sub

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

โค้ดในสร้างปุ่มคำสั่งแบบ User Control (ucFoodButton.vb)
  1. Imports System.Drawing
  2. Imports System.Drawing.Drawing2D

  3. Public Class ucFoodButton

  4.     ' ตัวแปรเก็บข้อมูลสินค้า (Class FooItem อยู่ที่ไฟล์ FoodItem.vb)
  5.     Private _currentFood As FoodItem

  6.     ' สีสำหรับการแสดงผลสถานะต่างๆ สำหรับปุ่มคำสั่ง
  7.     Private ReadOnly _defaultColor As Color = Color.White
  8.     Private ReadOnly _hoverColor As Color = Color.FromArgb(70, Color.Green)
  9.     Private ReadOnly _pressColor As Color = Color.FromArgb(120, Color.Orange)

  10.     ' ประกาศคอนโทรลภายใน
  11.     Private pnlContainer As Panel
  12.     Private table As TableLayoutPanel
  13.     Private picFood As PictureBox
  14.     Private lblName As Label
  15.     Private lblPrice As Label

  16.     Public Sub New()
  17.         InitializeComponent()
  18.         ' การตั้งค่าเริ่มต้นของ User Control
  19.         Me.SetStyle(ControlStyles.ResizeRedraw, True)
  20.         Me.Size = New Size(130, 160)    ' ขนาดของปุ่มคำสั่ง
  21.         Me.Cursor = Cursors.Hand
  22.         Me.BackColor = _defaultColor

  23.         ' สร้างโครงสร้างคอนโทรลภายใน
  24.         BuildControl()
  25.     End Sub

  26.     ' ปรับขอบโค้งเมื่อมีการปรับขนาด
  27.     Protected Overrides Sub OnResize(ByVal e As EventArgs)
  28.         MyBase.OnResize(e)
  29.         MakeRounded()
  30.     End Sub

  31.     ' --- ส่วนของการวาดมุมโค้ง (Rounded Rectangle) ---
  32.     Private Sub MakeRounded()
  33.         Dim radius As Integer = 15 ' รัศมีของความโค้ง
  34.         Dim path As New GraphicsPath()
  35.         path.AddArc(0, 0, radius, radius, 180, 90)
  36.         path.AddArc(Me.Width - radius, 0, radius, radius, 270, 90)
  37.         path.AddArc(Me.Width - radius, Me.Height - radius, radius, radius, 0, 90)
  38.         path.AddArc(0, Me.Height - radius, radius, radius, 90, 90)
  39.         path.CloseFigure()
  40.         Me.Region = New Region(path)
  41.     End Sub

  42.     ' สร้างโครงสร้างปุ่ม
  43.     Private Sub BuildControl()
  44.         Me.Controls.Clear()

  45.         ' Panel หลัก
  46.         pnlContainer = New Panel()
  47.         With pnlContainer
  48.             .Dock = DockStyle.Fill
  49.             .Padding = New Padding(5)
  50.             .BackColor = Color.White
  51.         End With

  52.         ' ตารางจัดวางของ TableLauoutPanel
  53.         table = New TableLayoutPanel()
  54.         With table
  55.             .Dock = DockStyle.Fill
  56.             .ColumnCount = 1    ' กำหนด 1 หลัก
  57.             .RowCount = 3         ' กำหนด 3 แถว (แถวแรกใส่ PictureBox, แถวที่ 2 ใส่ Label ชื่ออาหาร/เครื่องดื่ม, แถวที่ 3 ใส่ Label ราคา)
  58.             .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 100))   ' Size แบบ Percent ทั้ง Column และ Row
  59.             .RowStyles.Add(New RowStyle(SizeType.Percent, 70))
  60.             .RowStyles.Add(New RowStyle(SizeType.Percent, 20))
  61.             .RowStyles.Add(New RowStyle(SizeType.Percent, 10))
  62.         End With

  63.         ' ส่วนแสดงรูปภาพ
  64.         picFood = New PictureBox()
  65.         With picFood
  66.             .Dock = DockStyle.Fill
  67.             .SizeMode = PictureBoxSizeMode.StretchImage
  68.             .Margin = New Padding(0)
  69.             .BackColor = Color.White
  70.         End With

  71.         ' ส่วนแสดงชื่อ
  72.         lblName = New Label()
  73.         With lblName
  74.             .Dock = DockStyle.Fill
  75.             .Font = New Font("Tahoma", 9, FontStyle.Bold)
  76.             .TextAlign = ContentAlignment.MiddleCenter
  77.             .AutoEllipsis = True
  78.             .MaximumSize = New Size(0, 36)
  79.             .Margin = New Padding(0)
  80.         End With

  81.         ' ส่วนแสดงราคา
  82.         lblPrice = New Label()
  83.         With lblPrice
  84.             .Dock = DockStyle.Fill
  85.             .Font = New Font("Tahoma", 10, FontStyle.Bold)
  86.             .ForeColor = Color.DarkRed
  87.             .TextAlign = ContentAlignment.MiddleCenter
  88.             .Margin = New Padding(0)
  89.         End With

  90.         '// ตำแหน่งการวาง Control ใน TableLayoutPanel (table) เพื่อสร้างปุ่มคำสั่ง
  91.         '+---------------------------+
  92.         '|                                  |
  93.         '|         PictureBox          |
  94.         '|      (StretchImage)       |
  95.         '|                                  |
  96.         '+---------------------------+
  97.         '|      Classic Checker      |
  98.         '|                                  |
  99.         '+---------------------------+
  100.         '|         69.00 ฿              |
  101.         '+---------------------------+
  102.         ' จัดวางคอนโทรล
  103.         table.Controls.Add(picFood, 0, 0)
  104.         table.Controls.Add(lblName, 0, 1)
  105.         table.Controls.Add(lblPrice, 0, 2)

  106.         ' วาง TableLayoutPanel เอาไวใน Panel
  107.         pnlContainer.Controls.Add(table)
  108.         ' เอา Panel ไปวางไว้ในฟอร์ม
  109.         Me.Controls.Add(pnlContainer)

  110.         ' ผูกเหตุการณ์เมาส์ (Add Event Handler)
  111.         RegisterEvents(Me)
  112.         RegisterEvents(pnlContainer)
  113.         RegisterEvents(table)
  114.         RegisterEvents(picFood)
  115.         RegisterEvents(lblName)
  116.         RegisterEvents(lblPrice)
  117.     End Sub

  118.     ' ผูกเหตุการณ์เมาส์ให้กับคอนโทรลทั้งหมด
  119.     Private Sub RegisterEvents(ctrl As Control)
  120.         AddHandler ctrl.MouseEnter, AddressOf Control_MouseEnter
  121.         AddHandler ctrl.MouseLeave, AddressOf Control_MouseLeave
  122.         AddHandler ctrl.MouseDown, AddressOf Control_MouseDown
  123.         AddHandler ctrl.MouseUp, AddressOf Control_MouseUp
  124.         AddHandler ctrl.Click, AddressOf Control_Click
  125.     End Sub

  126.     ' เปลี่ยนสีเมื่อเมาส์ชี้
  127.     Private Sub Control_MouseEnter(sender As Object, e As EventArgs)
  128.         SetHighlight(_hoverColor)
  129.     End Sub

  130.     ' คืนสีเดิมเมื่อเมาส์ออก
  131.     Private Sub Control_MouseLeave(sender As Object, e As EventArgs)
  132.         SetHighlight(_defaultColor)
  133.     End Sub

  134.     ' เปลี่ยนสีเมื่อกดเมาส์
  135.     Private Sub Control_MouseDown(sender As Object, e As MouseEventArgs)
  136.         SetHighlight(_pressColor)
  137.     End Sub

  138.     ' เปลี่ยนสีเมื่อปล่อยเมาส์
  139.     Private Sub Control_MouseUp(sender As Object, e As MouseEventArgs)
  140.         SetHighlight(_hoverColor)
  141.     End Sub

  142.     ' ตั้งค่าสีพื้นหลัง
  143.     Private Sub SetHighlight(ByVal clr As Color)
  144.         pnlContainer.BackColor = clr
  145.         table.BackColor = clr
  146.         lblName.BackColor = Color.Transparent
  147.         lblPrice.BackColor = Color.Transparent
  148.         picFood.BackColor = Color.Transparent
  149.     End Sub

  150.     ' เมื่อมีการกดปุ่มคำสั่ง Button เพื่อแสดงรายการอาหาร/เครื่องดื่ม
  151.     ' ส่วนนี้จะถูกส่งต่อไปแสดงผลยังตารางกริด เพื่อแจ้งยอดการสั่งซื้อ
  152.     Private Sub Control_Click(sender As Object, e As EventArgs)
  153.         If _currentFood IsNot Nothing Then
  154.             ' แสดง MessageBox เมื่อ {0} = vbCrLf หรือ NewLine
  155.             Dim msg As String = String.Format(
  156.                 "===== รายละเอียดสินค้า ====={0}{0}" & _
  157.                 "FoodPK : {1}{0}" & _
  158.                 "FoodID : " & vbTab & "{2}{0}" & _
  159.                 "Name : " & vbTab & "{3}{0}" & _
  160.                 "Price : " & vbTab & "{4:0.00} บาท{0}{0}",
  161.                 Environment.NewLine,
  162.                 _currentFood.FoodPK,
  163.                 _currentFood.FoodID,
  164.                 _currentFood.FoodName,
  165.                 _currentFood.PriceCash)

  166.             MessageBox.Show(msg, "คำสั่งในการสั่งซื้อ", MessageBoxButtons.OK, MessageBoxIcon.Information)
  167.         End If
  168.     End Sub

  169.     ' ==========================================================
  170.     ' เมธอดรับข้อมูลและภาพจากภายนอก (ฟอร์มหลัก)
  171.     ' รับแค่ข้อมูลที่ต้องแสดง ไม่ต้องไปค้นหาไฟล์เอง
  172.     ' ==========================================================
  173.     Public Sub SetData(food As FoodItem, foodImage As Image)
  174.         _currentFood = food

  175.         lblName.Text = food.FoodName
  176.         lblPrice.Text = food.PriceCash.ToString("N2") & " ฿"

  177.         ' กำหนดภาพที่ส่งมาจากฟอร์มหลักโดยตรง
  178.         picFood.Image = foodImage
  179.     End Sub

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

โค้ดในการสร้าง Custom Control หรือ FlatTabControl ที่สืบทอดมาจาก TabControl มาตรฐาน (FlatTabControl.vb)
ดูรายละเอียดได้ที่นี่ ...

  1. Imports System.Drawing.Drawing2D

  2. Public Class FlatTabControl
  3.     ' Inherits หมายถึง Control -> TabControl -> FlatTabControl
  4.     ' การที่ใช้ Inherits TabControl แทนที่จะใช้ Inherits UserControl แปลว่า ไม่ได้สร้างของใหม่จากศูนย์
  5.     ' แต่กำลัง "ดัดแปลง/ตกแต่ง" ของเดิมที่มีอยู่แล้วใน .NET Framework
  6.     Inherits TabControl
  7.     ' Custom Control หรือ Extended Control คือการสืบทอดจาก Control มาตรฐาน
  8.     ' FlatTabControl ก็คือ TabControl ตัวหนึ่งนั่นแหละ แต่มีการเปลี่ยนแปลงคุณสมบัติ เช่น รูปร่าง สี ฯลฯ ให้เป็นไปตามที่เราต้องการ ดังนี้
  9.     ' ลากลง Form ได้
  10.     ' มี Properties เดิมทั้งหมด
  11.     ' มี Events เดิมทั้งหมด
  12.     ' มี TabPages เดิมทั้งหมด
  13.     ' ==================================================================================
  14.     ' | หลัก OOP                | ใน FlatTabControl
  15.     ' | **Inheritance**      | Inherits TabControl ทำให้ใช้งานได้ทุกความสามารถของ TabControl มาใช้งานทันที (ไม่ต้องเขียนโค้ดใหม่)
  16.     ' | **Encapsulation**   | เก็บสถานะ เช่น HoverIndex เป็น Private และเปิดเผยเฉพาะสิ่งที่ผู้ใช้ Control ใช้งาน เช่น FlatTabControl1.SelectedIndex
  17.     ' | **Polymorphism**  | Overrides OnPaint, OnMouseMove, OnMouseLeave ใช้ชื่อ Method เดิม แต่เปลี่ยนพฤติกรรมเดิมของ TabControl
  18.     ' | **Abstraction**      | ผู้ใช้ FlatTabControl ไม่ต้องรู้รายละเอียดการวาดกราฟิกหรือการจัดการเมาส์ เพียงลาก Control ไปใช้เหมือน TabControl ปกติ
  19.     ' ==================================================================================

  20.     ' Encapsulation คือ ซ่อนข้อมูลภายใน
  21.     ' ผู้ใช้ FlatTabControl จะไม่รู้เลยว่ามี HoverIndex เพราะมี Private ซ่อนเอาไว้
  22.     Private HoverIndex As Integer = -1

  23.     Public Sub New()
  24.         ' เพื่อให้ System ตั้งค่าพื้นฐาน
  25.         MyBase.New()

  26.         ' Abstraction (การดูดซับ) ใช้ในการสร้าง Interface
  27.         Me.SetStyle(ControlStyles.AllPaintingInWmPaint _
  28.                     Or ControlStyles.OptimizedDoubleBuffer _
  29.                     Or ControlStyles.ResizeRedraw _
  30.                     Or ControlStyles.UserPaint, True)

  31.         Me.DrawMode = TabDrawMode.OwnerDrawFixed
  32.         Me.SizeMode = TabSizeMode.Fixed
  33.         Me.ItemSize = New Size(140, 50)
  34.         Me.Font = New Font("Tahoma", 10, FontStyle.Bold)
  35.     End Sub

  36.     ' Overrides หมายถึงว่ามีของเดิมใน Tab Control อยู่แล้ว แต่ขอแก้ไขใหม่ (หรือเรียกของ Microsoft มาก่อน แล้วค่อยมาทำของเราอีกที)
  37.     ' หรือกล่าวแบบสั้นๆ คือ การที่คลาสลูก เขียนทับพฤติกรรมของคลาสแม่
  38.     Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
  39.         ' ระบบของ Microsoft อาจจะไม่ทำงาน เราจึงต้องสั่ง MyBase.OnMouseMove(e) ดักเอาไว้ก่อน
  40.         MyBase.OnMouseMove(e)
  41.         HoverIndex = -1
  42.         For i As Integer = 0 To Me.TabPages.Count - 1
  43.             If Me.GetTabRect(i).Contains(e.Location) Then
  44.                 HoverIndex = i
  45.                 Exit For
  46.             End If
  47.         Next
  48.         Me.Invalidate()
  49.     End Sub

  50.     Protected Overrides Sub OnMouseLeave(e As EventArgs)
  51.         MyBase.OnMouseLeave(e)
  52.         HoverIndex = -1
  53.         Me.Invalidate()
  54.     End Sub

  55.     ' Encapsulation (การห่อหุ้ม) แม้จะเป็น Custom Control แต่เรายังคงซ่อนรายละเอียดการวาดภาพที่ซับซ้อนไว้ภายในคลาส
  56.     ' ตัวแปร HoverIndex, ฟังก์ชัน RoundRect, การคำนวณสีภายใน OnPaint ถูกห่อหุ้มไว้
  57.     ' ผู้ใช้งานภายนอก (คนเอา Control ไปใช้) ไม่ต้องรู้ ว่ามันวาดยังไง
  58.     ' เขาจะแค่เห็นว่า Control มี Property SelectedIndex หรือ TabPages ให้ใช้งานเหมือนเดิม
  59.     Protected Overrides Sub OnPaint(e As PaintEventArgs)
  60.         e.Graphics.Clear(Color.White)
  61.         e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
  62.         '=========================
  63.         ' วาดแท็บ
  64.         '=========================
  65.         For i As Integer = 0 To Me.TabPages.Count - 1
  66.             Dim r As Rectangle = Me.GetTabRect(i)
  67.             r.Inflate(-3, -3)
  68.             Dim back As Color
  69.             Dim fore As Color
  70.             If i = Me.SelectedIndex Then
  71.                 back = Color.FromArgb(25, 118, 210)
  72.                 fore = Color.White
  73.             ElseIf i = HoverIndex Then
  74.                 back = Color.Gainsboro
  75.                 fore = Color.Black
  76.             Else
  77.                 back = Color.FromArgb(45, 45, 48)
  78.                 fore = Color.WhiteSmoke
  79.             End If

  80.             ' เมื่อออกจากบล็อก Using จะเรียก Dispose() ทันที (แม้จะเกิด Exception ก็ตาม)
  81.             ' ถ้าสร้างทิ้งไว้ไม่ Dispose พอวน Loop หลายๆ รอบ (หรือเปิดปิด Tab บ่อยๆ) จะทำให้เกิด Memory Leak
  82.             ' และอาจทำให้โปรแกรมค้างหรือแสดงผลผิดเพี้ยนได้
  83.             Using gp As GraphicsPath = RoundRect(r, 8)   ' <------ สร้าง GraphicsPath
  84.                 Using br As New SolidBrush(back)          ' <------ สร้าง Brush (ซ้อนกัน)
  85.                     e.Graphics.FillPath(br, gp)
  86.                 End Using
  87.                 Using pn As New Pen(Color.FromArgb(90, 90, 90))   ' <------ สร้าง Pen
  88.                     e.Graphics.DrawPath(pn, gp)
  89.                 End Using
  90.             End Using
  91.             TextRenderer.DrawText( _
  92.                 e.Graphics, _
  93.                 Me.TabPages(i).Text, _
  94.                 Me.Font, _
  95.                 r, _
  96.                 fore, _
  97.                 TextFormatFlags.HorizontalCenter Or _
  98.                 TextFormatFlags.VerticalCenter)
  99.         Next
  100.         '=========================
  101.         ' พื้นหลังของ Page
  102.         '=========================
  103.         Dim PageRect As Rectangle
  104.         PageRect = Me.DisplayRectangle
  105.         PageRect.Inflate(1, 1)
  106.         Using br As New SolidBrush(Color.White)
  107.             e.Graphics.FillRectangle(br, PageRect)
  108.         End Using
  109.     End Sub

  110.     '=========================
  111.     ' วาดเส้นโค้ง
  112.     '=========================
  113.     Private Function RoundRect(r As Rectangle, radius As Integer) As GraphicsPath
  114.         Dim gp As New GraphicsPath
  115.         gp.AddArc(r.Left, r.Top, radius, radius, 180, 90)
  116.         gp.AddArc(r.Right - radius, r.Top, radius, radius, 270, 90)
  117.         gp.AddArc(r.Right - radius, r.Bottom - radius, radius, radius, 0, 90)
  118.         gp.AddArc(r.Left, r.Bottom - radius, radius, radius, 90, 90)
  119.         gp.CloseFigure()
  120.         Return gp
  121.     End Function

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

Class ในการจัดเก็บข้อมูลอาหารหรือเครื่องดื่ม (FoodItem.vb)
  1. ' Class FoodItem เป็น BluePrint หรือแม่แบบสำหรับสร้างวัตถุ (Object) ที่ใช้เก็บข้อมูลสินค้าแต่ละรายการ โดยมี Property ต่างๆ ดังนี้:
  2. Public Class FoodItem
  3.     Public Property FoodPK As Integer
  4.     Public Property FoodID As String
  5.     Public Property FoodName As String
  6.     Public Property PriceCash As Decimal
  7.     Public Property CategoryFK As Integer
  8.     Public Property PictureFood As String
  9. End Class
คัดลอกไปที่คลิปบอร์ด

ฟังค์ชั่นเกี่ยวกับการกำหนดพาธ (modFunction.vb)
  1. Module modFunction
  2.     ' ==========================================================
  3.     ' ฟังก์ชัน MyPath ตามที่กำหนด
  4.     ' ==========================================================
  5.     Public Function MyPath(ByVal AppPath As String) As String
  6.         ' แทนที่ path ของ bin ต่างๆ ให้กลับไปที่ root folder ของโปรเจกต์
  7.         Dim resultPath As String = AppPath.ToLower.Replace("\bin\debug", "") _
  8.                                           .Replace("\bin\release", "") _
  9.                                           .Replace("\bin\x86\debug", "")

  10.         ' ถ้าไม่มี \ (BackSlash) ต่อท้าย ให้เติมเข้าไป
  11.         If Not resultPath.EndsWith("") Then resultPath = resultPath & ""

  12.         Return resultPath
  13.     End Function

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

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

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

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

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

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

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

GMT+7, 2026-7-29 02:43 , Processed in 0.162604 second(s), 4 queries , File On.

Powered by Discuz! X3.4, Rev.62

Copyright © 2001-2020 Tencent Cloud.

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