
Chú ý rằng hoạt động này diễn ra trực tiếp bên trong phương thức thụ lý sự kiện
MouseMove. Việc vẽ chỉ được thực hiện nếu phần chọn hiện tại thay đổi. Đối với một
đoạn mã đơn giản, bạn có thể làm mất hiệu lực toàn bộ form mỗi khi con trỏ chuột di
chuyển vào trong hoặc ra khỏi một vùng và thụ lý tất cả việc vẽ trong phương thức thụ lý
sự kiện Form.Paint, nhưng điều này dẫn đến việc phải vẽ nhiều hơn và tạo nên hiện
tượng rung hình (flicker) khi toàn bộ form được vẽ lại.
1.1 Tạo form có hình dạng tùy biến
V
V
Bạn cần tạo một form hoặc điều kiểm không phải hình chữ nhật.
#
#
Tạo một đối tượng System.Drawing.Region có hình dạng như bạn muốn, và
gán nó vào thuộc tính Form.Region hoặc Control.Region.
Để tạo một form hoặc điều kiểm không phải hình chữ nhật, trước hết bạn cần định nghĩa
hình dạng mình muốn. Cách tiếp cận dễ nhất là sử dụng đối tượng
System.Drawing.Drawing2D.GraphicsPath, nó có thể điều tiết bất kỳ sự kết hợp nào của
các hình ellipse, chữ nhật, và cung khép kín. Bạn có thể thêm các shape vào một đối
tượng GraphicsPath bằng các phương thức như AddEllipse, AddRectangle, và
AddClosedCurve. Một khi đã hoàn tất việc định nghĩa hình dạng như mong muốn, bạn có
thể tạo một đối tượng Region từ GraphicsPath này—chỉ cần trình ra GraphicsPath trong
phương thức khởi dựng của lớp Region. Cuối cùng, bạn có thể gán Region vào thuộc tính
Form.Region hoặc Control.Region.
Ví dụ dưới đây trình bày cách tạo một form có hình dáng bất thường (xem hình 8.3) bằng
hai cung tròn (hai cung này được chuyển thành một figure khép kín bằng phương thức
GraphicsPath.CloseAllFigures).
Hình 8.3 Form không phải hình chữ nhật
using System;
using System.Windows.Forms;
using System.Drawing;
The image part with relationsh ip ID rI d5 was not fo und in the file.

using System.Drawing.Drawing2D;
public class IrregularForm : System.Windows.Forms.Form {
private System.Windows.Forms.Button cmdClose;
private System.Windows.Forms.Label label1;
// (Bỏ qua phần mã designer.)
private void IrregularForm_Load(object sender, System.EventArgs e) {
GraphicsPath path = new GraphicsPath();
Point[] pointsA = new Point[] {new Point(0, 0),
new Point(40, 60), new Point(this.Width - 100, 10)};
path.AddCurve(pointsA);
Point[] pointsB = new Point[]
{new Point(this.Width - 40, this.Height - 60),
new Point(this.Width, this.Height),
new Point(10, this.Height)};
path.AddCurve(pointsB);
path.CloseAllFigures();
this.Region = new Region(path);
}
private void cmdClose_Click(object sender, System.EventArgs e) {
this.Close();
}
}
Đối với ví dụ tạo điều kiểm không phải hình chữ nhật, bạn hãy tham khảo mục 8.4.
1.2 Tạo điều kiểm có hình dạng tùy biến
V
V
Bạn cần tạo một shape mà người dùng có thể thao tác với nó trên form như kéo
rê, thay đổi kích thước....

#
#
Tạo một điều kiểm tùy biến, và chép đè painting logic để vẽ shape. Gán shape
của bạn vào thuộc tính Control.Region. Kế đó, bạn có thể sử dụng Region này
để thực hiện “hit testing”.
Nếu muốn tạo một giao diện người dùng phức tạp kết hợp nhiều phần tử được vẽ tùy
biến, bạn cần có phương cách để theo vết các phần tử này và cho phép người dùng tương
tác với chúng. Cách tiếp cận dễ nhất trong .NET là tạo một điều kiểm chuyên biệt bằng
cách dẫn xuất một lớp từ System.Windows.Forms.Control. Kế đó, bạn có thể tùy biến
phương cách mà điều kiểm này được vẽ dựa theo tập các sự kiện cơ bản của nó.
Điều kiểm được trình bày dưới đây mô tả một hình ellipse đơn giản trên form. Tất cả các
điều kiểm đều được liên hợp với một vùng chữ nhật trên form, do đó điều kiểm
EllipseShape sẽ tạo một ellipse lắp đầy các đường biên này (được cấp thông qua thuộc
tính Control.ClientRectangle). Một khi shape đã được tạo, thuộc tính Control.Region
được thiết lập dựa theo biên trên ellipse. Điều này bảo đảm các sự kiện như MouseMove,
MouseDown, Click... sẽ xảy ra chỉ khi chuột ở trên ellipse, chứ không phải toàn bộ hình
chữ nhật.
Dưới đây là phần mã đầy đủ của lớp EllipseShape:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
public class EllipseShape : System.Windows.Forms.Control {
private GraphicsPath path = null;
private void RefreshPath() {
// Tạo GraphicsPath cho shape và áp dụng nó vào
// điều kiểm bằng cách thiết lập thuộc tính Region.
path = new GraphicsPath();
path.AddEllipse(this.ClientRectangle);
this.Region = new Region(path);
}
protected override void OnResize(System.EventArgs e) {
base.OnResize(e);
RefreshPath();

this.Invalidate();
}
protected override void OnPaint
(System.Windows.Forms.PaintEventArgs e) {
base.OnPaint(e);
if (path != null) {
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.FillPath(new SolidBrush(this.BackColor), path);
e.Graphics.DrawPath(new Pen(this.ForeColor, 4), path);
}
}
}
Bạn có thể định nghĩa điều kiểm EllipseShape trong một Class Library Assembly độc lập
để nó có thể được thêm vào hộp công cụ của Microsoft Visual Studio .NET và được sử
dụng lúc thiết kế. Tuy nhiên, ngay cả không thực hiện bước này, cũng dễ dàng tạo được
một ứng dụng thử nghiệm đơn giản. Ví dụ dưới đây tạo hai ellipse và cho phép người
dùng kéo rê cả hai vòng quanh form bằng cách giữ chuột xuống và di chuyển con trỏ.
Hình 8.4 Kéo rê các điều kiểm có hình dạng tùy biến trên form
public class SpriteTest : System.Windows.Forms.Form {
// (Bỏ qua phần mã designer.)
// Các cờ dùng để theo vết chuột khi chế độ kéo rê được kích hoạt.
private bool isDraggingA = false;
The image part with relationsh ip ID rI d6 was not fo und in the file.

private bool isDraggingB = false;
// Các điều kiểm có hình dạng ellipse.
private EllipseShape ellipseA, ellipseB;
private void SpriteTest_Load(object sender, System.EventArgs e) {
// Tạo và cấu hình cả hai ellipse.
ellipseA = new EllipseShape();
ellipseA.Width = ellipseA.Height = 100;
ellipseA.Top = ellipseA.Left = 30;
ellipseA.BackColor = Color.Red;
this.Controls.Add(ellipseA);
ellipseB = new EllipseShape();
ellipseB.Width = ellipseB.Height = 100;
ellipseB.Top = ellipseB.Left = 130;
ellipseB.BackColor = Color.Azure;
this.Controls.Add(ellipseB);
// Gắn cả hai ellipse vào cùng tập các phương thức
// thụ lý sự kiện.
ellipseA.MouseDown += new MouseEventHandler(Ellipse_MouseDown);
ellipseA.MouseUp += new MouseEventHandler(Ellipse_MouseUp);
ellipseA.MouseMove += new MouseEventHandler(Ellipse_MouseMove);
ellipseB.MouseDown += new MouseEventHandler(Ellipse_MouseDown);
ellipseB.MouseUp += new MouseEventHandler(Ellipse_MouseUp);
ellipseB.MouseMove += new MouseEventHandler(Ellipse_MouseMove);
}
private void Ellipse_MouseDown(object sender, MouseEventArgs e) {
// Thu lấy ellipse gây ra sự kiện này.
Control control = (Control)sender;
if (e.Button == MouseButtons.Left) {
control.Tag = new Point(e.X, e.Y);

