- Bước 1: Xây dựng giao diện như sau áp dụng từ giao diện cơ bản trong việc duyệt file, folder - Bước 2: Phân tích các tương tác hành động có thể xảy ra của người dùng đối với chương
Trang 1Mục tiêu
Biết cách sử dụng các lớp đối tượng quản lý file, folder
Biết cách sử dụng GDI+ để thực hiện vẽ cơ bản trên WinForm
Nội dung
Chương trình File Explorer đơn giản
Ở phần này chúng ta sẽ ôn lại cách xây dựng một chương trình WinForm
- Bước 1: Xây dựng giao diện như sau (áp dụng từ giao diện cơ bản trong việc duyệt file,
folder)
- Bước 2: Phân tích các tương tác (hành động) có thể xảy ra của người dùng đối với
chương trình để tìm các event cần thiết
Cần phải lấy dữ liệu các thư mục ổ đĩa khi chương trình khởi chạy nên cần xử lý
event Load của Form
Mục đích của cbView là để cho phép lựa chọn chế độ View của ListView nên cần
xử lý event SelectedIndexChanged của ComboBox
Với việc hiển thị cây thư mục trên TreeView thì khi chọn trên TreeView phải có
danh sách chứa trong thư mục được chọn nên cần xử lý event AfterSelect của
TreeView
Với ListView tương tác thông thường là lựa chọn xem ds con trong thư mục hay
thực thi file bằng cách nhấn đúp nên cần xử lý event DoubleClick của ListView
cbView
tv
tv
Trang 2- Bước 3: Sau khi có danh sách các event thì tiến hành tạo phương thức xử lý và gắn kết
thích hợp
public frmMain()
{
InitializeComponent();
Load += new EventHandler(frmMain_Load);
cbView.SelectedIndexChanged += new EventHandler(cbView_SelectedIndexChanged); tv.AfterSelect += new TreeViewEventHandler(tv_AfterSelect);
lv.DoubleClick += new EventHandler(lv_DoubleClick);
}
void frmMain_Load(object sender, EventArgs )
{
}
void cbView_SelectedIndexChanged(object sender, EventArgs )
{
}
void tv_AfterSelect(object sender, TreeViewEventArgs )
{
}
void lv_DoubleClick(object sender, EventArgs )
{
}
- Bước 4: Thực hiện cài đặt các phương thức xử lý event (đã qua quá trình phân tích yêu cầu để biết ở hành động nào thì cần làm gì)
Event Load của Form: cần thực hiện load cây thư mục trên máy cho TreeView (sử dụng các lớp đối tượng thích hợp từ namespace System.IO)
void frmMain_Load(object sender, EventArgs )
{
FillTreeView();
}
void FillTreeView()
{
tv.Nodes.Clear();
//đầu tiên thêm node gốc là "Computer"
TreeNode tn = new TreeNode("Computer");
tv.Nodes.Add(tn);
//lấy về ds ổ đĩa trên máy
DriveInfo[] arrDriveInfo = DriveInfo.GetDrives();
//lưu ý rằng: vì mỗi PC hiện với hệ thống file/folder là vô cùng lớn //(ít nhất là với folder Windows) nên việc duyệt hết cây thư mục //để đưa vào TreeView một lần là không khả thi mà chỉ nên đưa vào
Trang 3//các node mức ngoài, khi nào được lựa chọn mới tiếp tục đưa vào foreach (DriveInfo di in arrDriveInfo)
{
//cần kiểm tra ổ đĩa có sẵn sàng hay không
if (!di.IsReady)
{
continue;
}
tn = new TreeNode(string.Format("{0}{1}", di.Name,
di.VolumeLabel));
//giữ lại thông tin DirectoryInfo để mở tiếp khi được lựa chọn tn.Tag = di.RootDirectory;
//đưa vào node gốc của TreeView (là node "Computer")
tv.TopNode.Nodes.Add(tn);
//kiểm tra nếu node có node con (sẽ được thêm sau) thì thêm
//1 node con tạm (để xuất hiên hiển thị đúng trong TreeView)
if (di.RootDirectory.GetDirectories().Length > 0)
{
var tnTemp = new TreeNode("");
tn.Nodes.Add(tnTemp);
}
}
//expand node gốc cho đẹp
tv.TopNode.Expand();
}
Event SelectedIndexChanged của cbView: thay đổi thuộc tính View của ListView tùy vào sự lựa chọn trên ComboBox (cần khởi tạo item cho cbView trong hàm
khởi tạo của Form)
public frmMain()
{
InitializeComponent();
Load += new EventHandler(frmMain_Load);
cbView.SelectedIndexChanged += new
EventHandler(cbView_SelectedIndexChanged);
tv.AfterSelect += new TreeViewEventHandler(tv_AfterSelect);
lv.DoubleClick += new EventHandler(lv_DoubleClick);
//tạo các item của cbView chính là lấy các loại của một enum //(trong trường hợp này là enum View của ListView)
cbView.Items.AddRange(Enum.GetNames(typeof(View)));
//set lại cho phù hợp với current
cbView.SelectedText = lv.View.GetType().Name;
}
void cbView_SelectedIndexChanged(object sender, EventArgs )
{
if (cbView.SelectedIndex >= 0)
{
lv.View = (View)cbView.SelectedIndex;
}
}
Event AfterSelect của TreeView: khi lựa chọn item trên TreeView (thể hiện cây
thư mục) nghĩa là lựa chọn 1 thư mục nên cần thể hiện các con (thư mục và tệp
Trang 4tin) nếu có của thư mục được chọn và đồng thời load thêm các thư mục con vào
TreeView
void tv_AfterSelect(object sender, TreeViewEventArgs )
{
//lấy TreeNode đang được chọn
TreeNode tnCur = e Node;
//kiểm tra nếu là node "Computer" thì không xử lý
if (tnCur == tv.TopNode)
{
return;
}
//lấy DirectoryInfo tương ứng đã lưu giữ cùng TreeNode
DirectoryInfo diCur = tnCur.Tag as DirectoryInfo;
//thêm các node con cho TreeNode
AddChildNodeForTreeNode(tnCur, diCur);
//thực hiện điền các folder và file là con của
//folder đang được chọn vào ListView
FillListView(diCur);
}
void AddChildNodeForTreeNode(TreeNode tnCur, DirectoryInfo di)
{
//trước tiên clear để tránh trùng
tnCur.Nodes.Clear();
TreeNode tn = null;
foreach (DirectoryInfo diE in di.GetDirectories())
{
tn = new TreeNode(diE.Name);
tn.Tag = diE;
//vì một số folder bị phụ thuộc vào quyền truy xuất
//nên cần thực hiện khối bắt lỗi
try
{
if (diE.GetDirectories().Length > 0)
{
var tnTemp = new TreeNode("");
tn.Nodes.Add(tnTemp);
}
tnCur.Nodes.Add(tn);
}
catch (Exception)
{
}
}
tnCur.Expand();
}
void FillListView(DirectoryInfo diCur)
{
//trước tiên tạo column cho ListView nếu chưa có
if (lv.Columns.Count == 0)
{
string[] arrColumnName = new string[] { "Name", "Type",
"Extension" };
Trang 5ColumnHeader ch = null;
foreach (string cn in arrColumnName)
{
ch = new ColumnHeader();
ch.Text = cn;
lv.Columns.Add(ch);
}
}
//bắt đầu thêm các item cho ListView
lv.Items.Clear();
ListViewItem lvi = null;
//lấy các folder con trước
foreach (DirectoryInfo di in diCur.GetDirectories())
{
lvi = new ListViewItem(di.Name);
lvi.SubItems.Add("Folder");
lvi.Tag = di;
lv.Items.Add(lvi);
}
//tiếp theo lấy các file con
foreach (FileInfo fi in diCur.GetFiles())
{
lvi = new ListViewItem(fi.Name);
lvi.SubItems.Add("File");
lvi.SubItems.Add(fi.Extension);
lvi.Tag = fi;
lv.Items.Add(lvi);
}
}
Event DoubleClick của ListView: nếu là folder thì tiếp tục mở vào trong, nếu là
file thì thực thi (ở đây chỉ mở MessageBox)
void lv_DoubleClick(object sender, EventArgs )
{
if (lv.SelectedItems.Count == 0)
{
return;
}
//lấy ListViewItem được chọn
ListViewItem lviCur = lv.SelectedItems[0];
//lấy DirectoryInfo tương ứng
var diCur = lviCur.Tag as DirectoryInfo;
//phải kiểm tra vì có thể là file
if (diCur != null)
{
//thực hiện fill ListView
FillListView(diCur);
}
else
{
var fiCur = lviCur.Tag as FileInfo;
MessageBox.Show(string.Format("Là file: {0}", fiCur.Name));
}
}
- Bước 5: Thực thi chương trình
Trang 6Một số loại Custom Control
Extended Control là control tạo ra bằng cách kế thừa từ control có sẵn (mục đích là
không thay đổi về cách thể hiện và hành vi cơ bản mà chỉ thêm vào một số chức năng cần thiết)
Ví dụ TextBox chỉ cho nhập số
- Bước 1: Thêm 1 class vào project và đặt tên là MyTextBox
- Bước 2: Cài đặt cho class MyTextBox như sau:
public class MyTextBox : TextBox
{
//để ngăn chặn việc nhập không phải ký số thì
//cần cài đặt lại cách xử lý khi nhấn phím
//của TextBox
protected override void OnKeyPress(KeyPressEventArgs )
{
//tất cả phím không phải là ký số hay
//phím điều khiển (ENTER, BACK, ) thì bỏ qua
if (!char.IsControl( KeyChar) && !char.IsDigit( KeyChar))
{
//bỏ qua event bằng cách thông báo với
//hệ thống là event đã được xử lý xong
e Handled = true;
}
base.OnKeyPress( );
}
}
- Bước 3: Biên dịch chương trình và thêm MyTextBox vào Form từ ToolBox để sử dụng
Ví dụ PictureBox cho phép thay đổi hình khi nhấn chuột (nhấn LEFT hay RIGHT thì
thứ tự thay đổi khác nhau)
- Bước 1: Thêm 1 class MyPictureBox vào project
- Bước 2: Cài đặt như sau:
public class MyPictureBox : PictureBox
{
Trang 7//đặt thuộc tính lưu trữ các hình
public ImageList ListIMG { get; set; }
//lưu lại chỉ số hình hiện tại
int indexIMG = 0;
//để thay đổi hình dựa vào việc nhấn chuột
//thì cài đặt lại xử lý cho event MouseDown
protected override void OnMouseDown(MouseEventArgs )
{
int numIMG = ListIMG.Images.Count;
//kiểm tra ds hình đã có hay chưa
if (numIMG > 0)
{
//tùy theo việc nhấn LEFT hay RIGHT
switch (e Button)
{
case MouseButtons.Left:
indexIMG = (indexIMG + 1) % numIMG;
break;
case MouseButtons.Right:
indexIMG -= 1;
if (indexIMG < 0)
{
indexIMG = numIMG - 1;
}
break;
}
//thay đổi hình
this.Image = ListIMG.Images[indexIMG];
}
base.OnMouseDown( );
}
}
- Bước 3: Biên dịch và thêm MyPictureBox vào Form thông qua ToolBox để sử
dụng Có thể gán ImageList vào ListIMG ngay từ designer (trước đó phải tạo ít
nhất 1 ImageList)
Trang 8 Composite Control (hay User Control) là bộ tập hợp nhiều control có sẵn để hoàn thành
một hành động cộng tác nào đó Ví dụ như tạo bộ ProgressBar có hiển thị thông tin text
- Bước 1: Thêm UserControl vào project đặt tên là ucProgressBar
- Bước 2: Thiết kế giao diện của ucProgressBar như sau
- Bước 3: Xây dựng frmCC như sau
proBar
lblInfo
Trang 9- Bước 4: Cài đặt cho frmCC như sau
public partial class frmCC : Form
{
public frmCC()
{
InitializeComponent();
ucProgressBar1.Step = 5;
ucProgressBar1.Maximum = 200;
ucProgressBar1.Value = 36;
btnStep.Click += new EventHandler(btnStep_Click);
}
void btnStep_Click(object sender, EventArgs )
{
ucProgressBar1.PerformStep();
}
}
- Bước 5: Thực thi chương trình
Thực hành GDI+ cơ bản
Mở form và vẽ các hình cơ bản lên form (đoạn thẳng, hình chữ nhật, hình ellipse, hình vuông, hình tròn)
- Bước 1: Tạo 1 project WinForm và đặt tên form là frmGDIPlus
- Bước 2: Để có thể vẽ được thì cần yếu tố quan trọng nhất đó là đối tượng Graphics (hiểu đơn giản là đại diện cho bề mặt để vẽ, được gắn liền với đối tượng cụ thể nên chỉ có thể tạo ra từ đối tượng nào đó (1 control chẳng hạn) chứ không thể tự tạo) Cách đơn giản nhất để có đối tượng Graphics là lấy ở trong event Paint của control
public frmGDIPlus()
{
InitializeComponent();
Paint += new PaintEventHandler(frmGDIPlus_Paint);
}
Trang 10void frmGDIPlus_Paint(object sender, PaintEventArgs )
{
}
- Bước 3: Lấy đối tượng Graphics trong event Paint và thực hiện vẽ các hình
void frmGDIPlus_Paint(object sender, PaintEventArgs )
{
//lấy đối tượng Graphics
Graphics = e Graphics;
//để vẽ các hình cơ bản (liên quan đến vẽ nét)
//thì cần có đối tượng Pen
Pen pen = Pens.DarkRed;
//để tô màu thì cần có Brush
Brush brush = Brushes.LightSkyBlue;
//thực hiện vẽ đoạn thẳng
//cần 2 điểm đầu và cuối
Point p1 = new Point(10, 10);
Point p2 = new Point(100, 100);
g DrawLine(pen, p1, p2);
//thực hiện vẽ hình chữ nhật
//khái niệm hình chữ nhật là tương đương
//đối tượng Recangle trong NET
//định hình bởi tọa độ X, Y và kích thước Width, Height Rectangle rect = new Rectangle(p2 , p2 , 200, 150);
g DrawRectangle(pen, rect);
//tô màu hình chữ nhật
rect += (int)pen.Width;
rect += (int)pen.Width;
rect.Width -= (int)pen.Width * 2;
rect.Height -= (int)pen.Width * 2;
g FillRectangle(brush, rect);
//thực hiện vẽ hình ellipse
g DrawEllipse(pen, rect);
//thực hiện vẽ hình vuông
//hình vuông là hình chữ nhật có 2 cạnh bằng nhau
rect.Height = rect.Width;
rect += rect.Width + 10;
g DrawRectangle(pen, rect);
//thực hiện vẽ đường tròn
g DrawEllipse(pen, rect);
}
- Bước 4: Thực thi chương trình
Trang 11Bài tập
Bài 1
Hoàn thành bài Explorer, làm thêm chức năng có hiển thị icon tương đối hợp lý, đồng thời làm Button Back cho ListView
Bài 2
Hoàn thành các loại User Control ở trên
Bài 3
Sử dụng GDI+ để viết chương trình Paint đơn giản