|
|

การนำ FlatTabControl ไปใช้งาน เราไม่จำเป็นต้อง Build ก็ได้ แต่ใช้การเขียนโค้ด VB.NET ในแบบ Run Time (รันโปรแกรมถึงจะเห็นผลลัพธ์ของการทำงาน) เพื่อสร้าง FlatTabControl ขึ้นมาแบบไดนามิค ...
ตัวอย่างการเขียนโค้ดสร้าง FlatTabControl ขึ้นมาแบบ Run Time ...
- ' ประกาศและสร้าง Object ของ FlatTabControl1
- Dim FlatTabControl1 As New FlatTabControl()
- ' กำหนดค่า Properties ต่างๆ ในแบบ Run Time (Dynamic)
- With FlatTabControl1
- .Cursor = Cursors.Hand
- .Dock = DockStyle.Fill
- .DrawMode = TabDrawMode.OwnerDrawFixed
- .Font = New Font("Tahoma", 10.0!, FontStyle.Bold)
- .ItemSize = New Size(140, 50)
- .Location = New Point(0, 0)
- .Name = "FlatTabControl1"
- .SelectedIndex = 0
- .Size = New Size(749, 583)
- .SizeMode = TabSizeMode.Fixed
- .TabIndex = 0
- ' ====== กำหนดสีพื้นหลัง ======
- '.BackColor = Color.FromArgb(255, 255, 255) ' หรือสีอื่นที่ต้องการ เช่น Color.White
- ' สีเทาอ่อน
- .BackColor = Color.FromArgb(240, 240, 240)
- ' สีขาว
- '.BackColor = Color.White
- End With
- Me.Controls.Add(FlatTabControl1)
คัดลอกไปที่คลิปบอร์ด
OOP ย่อมาจาก Object-Oriented Programming หรือในภาษาไทยเรียกว่า "การเขียนโปรแกรมเชิงวัตถุ" เป็นแนวคิดในการออกแบบและพัฒนาซอฟต์แวร์โดยมองทุกอย่างในระบบให้เป็น "วัตถุ (Object)" ซึ่งมีคุณสมบัติและพฤติกรรมในตัวเอง ช่วยให้จัดระเบียบโค้ดได้ง่าย นำโค้ดกลับมาใช้ใหม่ได้สะดวก และดูแลรักษาระบบใหญ่ๆได้ดีขึ้น
วันนี้แอดมินจะมาอธิบายถึงการสร้าง FlatTabControl โดยใช้การสืบทอดคุณสมบัติ (Inheritance) มาจาก TabControl มาตรฐานของไมโครซอฟท์ ซึ่งจะต้องใช้ความรู้พื้นฐานของ OOP เข้ามาเกี่ยวข้อง จุดประสงค์ในการสร้าง FlatTabControl ขึ้นมา นั่นคือ เราไม่ต้องมาสร้าง Control ใหม่ตั้งแต่ศูนย์ แต่บอกคอมไพเลอร์ว่า FlatTabControl ก็คือ TabControl รุ่นหนึ่ง โดยใช้คำสั่ง Inherits TabControl ทำให้ได้คุณสมบัติทั้งหมดของ TabControl มาตรฐานมาโดยอัตโนมัติ: มีแท็บ, มี TabPages, มีคุณสมบัติ SelectedIndex, ItemSize และอื่นๆ อีกมากมาย แต่เราเขียนโค้ดทับ/เพิ่มเติม เพื่อเปลี่ยนพฤติกรรมที่ไม่พอใจหรือต้องการสไตล์ใหม่
สรุปหลักการ OOP ที่เกี่ยวข้อง
Inheritance
การใช้ Inherits TabControl → หมายถึง Control ที่เราสร้าง (FlatTabControl) จะได้รับคุณสมบัติและพฤติกรรมทั้งหมดของ TabControl มาตั้งต้น แล้วเราสามารถ "โมดิฟาย" หรือ "Override" พฤติกรรมบางส่วนได้เอง
Polymorphism
การใช้ Override เมธอด เช่น OnPaint, OnMouseMove, OnMouseLeave ทำให้พฤติกรรมการวาดและการตอบสนองต่อเมาส์เปลี่ยนไปตามที่เรากำหนดเอง
Encapsulation
เก็บสถานะ เช่น HoverIndex เป็น Private และเปิดเผยเฉพาะสิ่งที่ผู้ใช้ Control ใช้งาน เช่น FlatTabControl1.SelectedIndex
Abstraction
ผู้ใช้ FlatTabControl ไม่ต้องรู้รายละเอียดการวาดกราฟิกหรือการจัดการเมาส์ เพียงลาก Control ไปใช้เหมือน TabControl ปกติ
การทำงานของโค้ด
1. Constructor (New)
- กำหนด Style ให้ Control ใช้ Double Buffer, UserPaint → เพื่อให้วาดเองได้ลื่นไหล
- กำหนด DrawMode = OwnerDrawFixed → คุณเป็นคนวาดแท็บเองทั้งหมด
- กำหนด ItemSize, Font, Cursor → ปรับรูปลักษณ์แท็บ
2. OnMouseMove / OnMouseLeave
- ตรวจสอบว่าเมาส์อยู่บนแท็บไหน → เก็บค่าไว้ใน HoverIndex
- เรียก Invalidate() เพื่อบังคับให้ Control วาดใหม่
3. OnPaint
- ล้างพื้นหลังด้วยสีขาว
- วาดแท็บทีละตัว โดยเลือกสีตามสถานะ (Selected, Hover, Normal)
- ใช้ RoundRect เพื่อสร้างกรอบโค้งมน
- วาดข้อความด้วย TextRenderer.DrawText
- วาดพื้นหลังของ Page ด้วยสีขาว
4. RoundRect Function
- สร้าง GraphicsPath ที่มีมุมโค้งมน → ใช้ในการวาดแท็บให้ดู Flat + Modern
สรุป
การสร้าง Custom Control โดย Inherits จาก Control มาตรฐาน เป็นการใช้ OOP อย่างเต็มรูปแบบ:
1. Inheritance → รับคุณสมบัติเดิม
2. Polymorphism → เปลี่ยนพฤติกรรมด้วย Override
3. Encapsulation → ซ่อนรายละเอียดภายใน
4. Reusability → ใช้งานซ้ำได้ในหลายโปรเจกต์
โค้ดในส่วนของการสร้าง FlatTabControl ... FlatTabControl.vb
- Imports System.Drawing.Drawing2D
- Public Class FlatTabControl
- ' Inherits หมายถึง Control -> TabControl -> FlatTabControl
- ' การที่ใช้ Inherits TabControl แทนที่จะใช้ Inherits UserControl แปลว่า ไม่ได้สร้างของใหม่จากศูนย์
- ' แต่กำลัง "ดัดแปลง/ตกแต่ง" ของเดิมที่มีอยู่แล้วใน .NET Framework
- Inherits TabControl
- ' Custom Control หรือ Extended Control คือการสืบทอดจาก Control มาตรฐาน
- ' FlatTabControl ก็คือ TabControl ตัวหนึ่งนั่นแหละ แต่มีการเปลี่ยนแปลงคุณสมบัติ เช่น รูปร่าง สี ฯลฯ ให้เป็นไปตามที่เราต้องการ ดังนี้
- ' ลากลง Form ได้
- ' มี Properties เดิมทั้งหมด
- ' มี Events เดิมทั้งหมด
- ' มี TabPages เดิมทั้งหมด
- ' ==================================================================================
- ' | หลัก OOP | ใน FlatTabControl
- ' | **Inheritance** | Inherits TabControl การสืบทอดทำให้ใช้งานได้ทุกความสามารถของ TabControl มาใช้งานทันที (ไม่ต้องเขียนโค้ดใหม่)
- ' | **Encapsulation** | เก็บสถานะ เช่น HoverIndex เป็น Private และเปิดเผยเฉพาะสิ่งที่ผู้ใช้ Control ใช้งาน เช่น FlatTabControl1.SelectedIndex
- ' | **Polymorphism** | Overrides OnPaint, OnMouseMove, OnMouseLeave ใช้ชื่อ Method เดิม แต่เปลี่ยนพฤติกรรมเดิมของ TabControl
- ' | **Abstraction** | ผู้ใช้ FlatTabControl ไม่ต้องรู้รายละเอียดการวาดกราฟิกหรือการจัดการเมาส์ เพียงลาก Control ไปใช้เหมือน TabControl ปกติ
- ' ==================================================================================
- ' Encapsulation คือ ซ่อนข้อมูลภายใน
- ' ผู้ใช้ FlatTabControl จะไม่รู้เลยว่ามี HoverIndex เพราะมี Private ซ่อนเอาไว้
- Private HoverIndex As Integer = -1
- Public Sub New()
- ' เพื่อให้ System ตั้งค่าพื้นฐาน
- MyBase.New()
- ' Abstraction (การดูดซับ) ใช้ในการสร้าง Interface
- Me.SetStyle(ControlStyles.AllPaintingInWmPaint _
- Or ControlStyles.OptimizedDoubleBuffer _
- Or ControlStyles.ResizeRedraw _
- Or ControlStyles.UserPaint, True)
- Me.DrawMode = TabDrawMode.OwnerDrawFixed
- Me.SizeMode = TabSizeMode.Fixed
- Me.ItemSize = New Size(140, 50)
- Me.Font = New Font("Tahoma", 10, FontStyle.Bold)
- End Sub
- ' Overrides หมายถึงว่ามีของเดิมใน Tab Control อยู่แล้ว แต่ขอแก้ไขใหม่ (หรือเรียกของ Microsoft มาก่อน แล้วค่อยมาทำของเราอีกที)
- ' หรือกล่าวแบบสั้นๆ คือ การที่คลาสลูก เขียนทับพฤติกรรมของคลาสแม่
- Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
- ' ระบบของ Microsoft อาจจะไม่ทำงาน เราจึงต้องสั่ง MyBase.OnMouseMove(e) ดักเอาไว้ก่อน
- MyBase.OnMouseMove(e)
- HoverIndex = -1
- For i As Integer = 0 To Me.TabPages.Count - 1
- If Me.GetTabRect(i).Contains(e.Location) Then
- HoverIndex = i
- Exit For
- End If
- Next
- Me.Invalidate()
- End Sub
- Protected Overrides Sub OnMouseLeave(e As EventArgs)
- MyBase.OnMouseLeave(e)
- HoverIndex = -1
- Me.Invalidate()
- End Sub
- ' Encapsulation (การห่อหุ้ม) แม้จะเป็น Custom Control แต่เรายังคงซ่อนรายละเอียดการวาดภาพที่ซับซ้อนไว้ภายในคลาส
- ' ตัวแปร HoverIndex, ฟังก์ชัน RoundRect, การคำนวณสีภายใน OnPaint ถูกห่อหุ้มไว้
- ' ผู้ใช้งานภายนอก (คนเอา Control ไปใช้) ไม่ต้องรู้ ว่ามันวาดยังไง
- ' เขาจะแค่เห็นว่า Control มี Property SelectedIndex หรือ TabPages ให้ใช้งานเหมือนเดิม
- Protected Overrides Sub OnPaint(e As PaintEventArgs)
- e.Graphics.Clear(Color.White)
- e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
- '=========================
- ' วาดแท็บ
- '=========================
- For i As Integer = 0 To Me.TabPages.Count - 1
- Dim r As Rectangle = Me.GetTabRect(i)
- r.Inflate(-3, -3)
- Dim back As Color
- Dim fore As Color
- If i = Me.SelectedIndex Then
- back = Color.FromArgb(25, 118, 210)
- fore = Color.White
- ElseIf i = HoverIndex Then
- back = Color.Gainsboro
- fore = Color.Black
- Else
- back = Color.FromArgb(45, 45, 48)
- fore = Color.WhiteSmoke
- End If
- ' เมื่อออกจากบล็อก Using จะเรียก Dispose() ทันที (แม้จะเกิด Exception ก็ตาม)
- ' ถ้าสร้างทิ้งไว้ไม่ Dispose พอวน Loop หลายๆรอบ (หรือเปิดปิด Tab บ่อยๆ) จะทำให้เกิด Memory Leak
- ' และอาจทำให้โปรแกรมค้างหรือแสดงผลผิดเพี้ยนได้
- Using gp As GraphicsPath = RoundRect(r, 8) ' <------ สร้าง GraphicsPath
- Using br As New SolidBrush(back) ' <------ สร้าง Brush (ซ้อนกัน)
- e.Graphics.FillPath(br, gp)
- End Using
- Using pn As New Pen(Color.FromArgb(90, 90, 90)) ' <------ สร้าง Pen
- e.Graphics.DrawPath(pn, gp)
- End Using
- End Using
- TextRenderer.DrawText( _
- e.Graphics, _
- Me.TabPages(i).Text, _
- Me.Font, _
- r, _
- fore, _
- TextFormatFlags.HorizontalCenter Or _
- TextFormatFlags.VerticalCenter)
- Next
- '=========================
- ' พื้นหลังของ Page
- '=========================
- Dim PageRect As Rectangle
- PageRect = Me.DisplayRectangle
- PageRect.Inflate(1, 1)
- Using br As New SolidBrush(Color.White)
- e.Graphics.FillRectangle(br, PageRect)
- End Using
- End Sub
- '=========================
- ' วาดเส้นโค้ง
- '=========================
- Private Function RoundRect(r As Rectangle, radius As Integer) As GraphicsPath
- Dim gp As New GraphicsPath
- gp.AddArc(r.Left, r.Top, radius, radius, 180, 90)
- gp.AddArc(r.Right - radius, r.Top, radius, radius, 270, 90)
- gp.AddArc(r.Right - radius, r.Bottom - radius, radius, radius, 0, 90)
- gp.AddArc(r.Left, r.Bottom - radius, radius, radius, 90, 90)
- gp.CloseFigure()
- Return gp
- End Function
- End Class
คัดลอกไปที่คลิปบอร์ด
ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) & .Net Framework 4.0+ ได้ที่นี่ ... |
ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง
คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน
x
|