Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện (Phần 2)
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện (Phần 2)", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên
Tài liệu đính kèm:
- bai_giang_ky_thuat_lap_trinh_nganh_truyen_thong_da_phuong_ti.pdf
Nội dung text: Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện (Phần 2)
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Chương 2: Lập trình hướng đối tượng trong C++ 2.1 Lớp và đối tượng 2.1.1 Khái niệm, cú pháp khai báo Lớp: Lớp là thành phần cơ bản của chương trình hướng đối tượng, dùng để định nghĩa đối tượng. Đối tượng - Đối tượng là sự thể hiện của lớp. - Mỗi đối tượng được xác định bởi thuộc tính (dữ liệu, biến) và hành vi (phương thức). Thuộc tính để xác định tính chất riêng của đối tượng, hành vi là hành động tác động lên đối tượng. Cú pháp: //Cú pháp khai báo lớp class tên_lớp{ [mức_độ_truy_cập:] Các_thuộc_tính [mức_độ_truy_cập:] Các_phương_thức }[tên_đối_tượng]; //Cú pháp khai báo đối tượng tên_lớp tên_đối tượng; - Thuộc tính: như khai báo biến - Phương thức: như khai báo hàm Cách truy xuất: Tên_đối_tượng. Tên_thuộc_tính Tên_đối_tượng. Tên_phương_thức 2.1.2 Mức độ truy cập - Private: chỉ cho phép các hàm trong lớp truy cập đến thành phần này, các lớp khác không thể truy cập. - Public: được phép truy cập từ mọi lớp. - Protected: cho phép các thành viên của cùng một lớp hoặc từ một lớp dẫn xuất của nó. - Khi không có từ khóa truy cập thì toàn bộ các thành viên của lớp được hiểu mặc định là có thuộc tính private. class A class B { { //mac dinh la private void h() int x; { 38 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện void g() A a; { a.x++;//sai vì x là private của A /*g() trong cùng lớp A với x nên g() } truy xuất đươc x*/ }; x++; int main() } { public: A a; int f() a.g(); //sai vì g là private của A { cout >hoten; cout >dlt; cout >dth; } float tinhdtb() { return (dlt+dth)/2; } void xuat(float dtb) { cout<<"\n"<<"Ho ten: "<<hoten; cout<<"\n"<<"Dlt: "<<dlt; cout<<"\n"<<"Dth: "<<dth; 39 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout >hoten; cout >dlt; cout >dth; } float sinhvien::tinhdtb() { return (dlt+dth)/2; } void sinhvien::xuat(float dtb) { cout<<"\n"<<"Ho ten: "<<hoten; cout<<"\n"<<"Dlt: "<<dlt; cout<<"\n"<<"Dth: "<<dth; 40 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout<<"\n"<<"Dtb: "<<dtb; } 2.1.3 Hàm tạo (Constructor), Hàm hủy (Destructor) Hàm tạo - Khởi tạo giá trị ban đầu cho các thành viên của class - Được gọi tự động mỗi khi đối tượng được tạo ra - Hàm tạo không có kiểu dữ liệu trả về - Trùng với tên lớp và là hàm thành viên của lớp - Có thể có tham số hoặc không. using namespace std; class VD{ private: int a,b; public: VD() { a=18; b=27; } VD(int x, int y) { a=x; b=y; } void show() { cout<<"a= " <<a<<" b= "<<b << "\n"; } }; int main(){ VD o1; o1.show(); VD o2(2,3); o2.show(); system("pause"); } Hàm hủy 41 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện - Giải phóng bộ nhớ trước khi kết thúc công việc với đối tượng đó. - Có tên trùng với hàm khởi tạo nhưng thêm dấu ~ trước tên hàm. - Không có tham số. - Trong chương trình chính ta không gọi hàm giải phóng nhưng hàm này vẫn được thực hiện. ~VD() { cout <<"Giai phong doi tuong \n" ; } 2.1.4 Sử dụng lớp, đối tượng Mảng, biến đối tượng Một lớp (sau khi định nghĩa) có thể xem như một kiểu dữ liệu và có thể dùng để khai báo các biến, mảng đối tượng. Cách khai báo biến và mảng đối tượng cũng như những kiểu dữ liệu chuẩn của C++. Khai báo: - Tên_lớp danh_sách_biến; - Tên lớp danh_sách_mảng; Ví dụ: Sinhvien sv1, sv2, sv3; // khai báo 3 biến đối tượng sv1, sv2, sv3 Sinhvien sv[20]; // khai báo mảng đối tượng sv gồm 20 sinh viên Mỗi đối tượng sau khi khai báo sẽ được cấp phát một vùng nhớ riêng để chứa các thuộc tính của chúng. Chú ý rằng sẽ không có vùng nhớ riêng để chứa các phương thức cho mỗi đối tượng. Truy xuất: - Thuộc tính: tên_đối_tượng.tên_thuộc_tính - Phương thức: tên_đối_tượng.tên_phương_thức Tạo mảng các đối tượng từ ví dụ trên: VD o[MAX]; for (int i=0; i<MAX; i++) { o[i].input(); cout<<"\n"; } for (int i=0; i<MAX; i++) o[i].show(); 42 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Đối tượng làm tham số hàm, hàm trả về kiểu đối tượng Ví dụ: using namespace std; class VD{ private: int a,b; public: VD() { a=18; b=27; } VD(int x, int y) { a=x; b=y; } void show() { cout<<"a= " <<a<<" b= "<<b << "\n"; } void mul(VD &t) { a=a*a; b=b*b*b; } VD add(VD d) { VD temp; temp.a = a + d.a; temp.b= b + d.b; return temp; } }; int main(){ VD o1(3,3); o1.show(); VD o2(2,3); o2.show(); 43 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện VD o3; o3 = o1.add(o2); //o2.mul(o2); o3.show(); system("pause"); } 2.2 Nâng cao về lớp và đối tượng 2.2.1 Con trỏ đối tượng Chúng ta đã làm quen với mảng đối tượng và chúng ta cũng đã biết rằng có sự tương ứng 1-1 giữa mảng và con trỏ. Trong phần này, chúng ta sẽ thảo luận về con trỏ đối tượng. Việc khai báo con trỏ đối tượng hoàn toàn tương tự như khai báo con trỏ dữ liệu. Humans *man; Để truy cập đến các phương thức thành viên bên ngoài lớp (hàm thành viên), ta sử dụng dấu ->. Khi gọi phương thức khởi tạo, ta có thể gọi theo cách mà ta đã sử dụng cho con trỏ dữ liệu. Hoặc bạn có thể sử dụng toán tử new. Chương trình Kết quả int main() Andy, 22 Jack, 21 { Humans man(“Andy”, 22); Humans *man0 = &man; //Hoặc Humans *man1 = new Humans(“Jack”, 21); cout getName() getAge(); cout getName() getAge(); return 0; } Ngay sau toán tử new, chúng ta gọi phương thức khởi tạo của nó, khác với toán tử new dùng trong việc cung cấp bộ nhớ cho con trỏ. Khi liên đới đến con trỏ, có nhiều vấn đề liên quan đến cách đọc. Chúng ta có thể tổng kết theo bảng bên dưới đây Biểu thức Cách đọc *x trỏ bởi x &x địa chỉ của x 44 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện x.y thành viên y của đối tượng x x->y thành viên y của đối tượng trỏ bởi x (*x).y thành viên y của đối tượng trỏ bởi x x[i] đối tượng thứ i trỏ bởi x 2.2.2 Con trỏ this Từ khoá this ở bên trong một lớp đại diện cho đối tượng của lớp đó đang được thực hiện trong bộ nhớ. Nó là một con trỏ luôn có giá trị là địa chỉ của đối tượng. Nó có thể được dùng để kiểm tra xem tham số được truyền cho một hàm thành viên có phải chính bản thân đối tượng hay không. Ví dụ: class myClass { int a,b; int add(int a, int b) { this.a=a;//a là tham số của phương thức, this.a là thành viên lớp this.b=b; return this.a+this.b; } } 2.2.3 Thành viên tĩnh Một lớp có thể chứa các thành viên tĩnh, cả dữ liệu và các hàm. Các dữ liệu tĩnh còn được gọi là "biến của lớp" vì nội dung của chúng không phụ thuộc vào một đối tượng nào. Chỉ có một giá trị duy nhất cho tất cả các đối tượng trong cùng một lớp. Ví dụ, nó có thể được trong trường hợp bạn muốn có một biến chứa số đối tượng thuộc lớp đã được khai báo: 45 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 2.3 Nạp chồng Nạp chồng là một đặc tính quan trọng của C++ đó là cơ chế giúp bạn thực hiện tính đa hình trong lập trình hướng đối tượng. Có hai kiểu nạp chồng được cung cấp trong C++ đó là nạp chồng hàm và nạp chồng toán tử. Vậy thì hai kiểu nạp chồng này là gì, hoạt động như thế nào hôm nay chúng ta sẽ đi tìm hiểu về 2 hình thức nạp chồng này. 2.3.1 Nạp chồng phương thức Là một cơ chế của C++ cho phép chúng ta định nghĩa và sử dụng các hàm cùng tên, miễn là khác kiểu tham số hoặc là số lượng tham số khác nhau. Các hàm sử dụng cùng tên gọi là hàm chồng. Nạp chồng với kiểu tham số khác nhau Trong trường hợp này, các hàm có cùng số lượng tham số nhưng kiểu của tham số là khác nhau. Trình biên dịch sẽ dựa trên kiểu đối số của hàm để xác định hàm tương ứng. Ví dụ: class myClass { void hello(int a) // hàm này với tham số truyền vào là kiểu nguyên 46 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện { cout using namespace std; 47 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện class myClass { public:int add(int a=0, int b=0, int c=0) {return a+b+c;} }; int main() { myClass obj1; cout<<"Gia tri ham khi khong truyen tham so la: "<<obj1.add()<<"\n"; cout<<"Gia tri ham khi truyen 1 tham so la: "<<obj1.add(1)<<"\n"; cout<<"Gia tri ham khi truyen 2 tham so la: "<<obj1.add(1,2)<<"\n"; cout<<"Gia tri ham khi truyen 3 tham so la: "<<obj1.add(1,2,5)<<"\n"; system("pause"); } Kết quả: Gia tri ham khi khong truyen tham so la: 0 Gia tri ham khi truyen 1 tham so la: 1 Gia tri ham khi truyen 2 tham so la: 3 Gia tri ham khi truyen 3 tham so la: 8 2.3.2 Nạp chồng toán tử Như chúng ta đã biết các phép toán +,-,*,/,< có thể được thực hiện trên các kiểu dữ liệu đơn giản. Tuy nhiên mặc định sẽ không thể thực hiện được trên các kiểu dữ liệu tự định nghĩa như lớp, nhưng C++ lại có cơ chế cho phép ta định nghĩa việc thực hiện các toán tử đó thông qua việc nạp chồng toán tử. Trong c++ có thể nạp chồng được hầu hết các toán tử ngoại trừ toán tử (.), (::) và (:?). Hình thức chung cho nạp chồng toán tử: kieuTraVe tenLop :: operator kyHieuToanTu (tham so) { //Nội dung nạp chồng } Một số chú ý khi nạp chồng toán tử: 1. Kiểu trả về của toán tử so sánh và toán tử logic phải khác tên lớp 48 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 2. Không thể thay đổi thứ tự ưu tiên của các toán tử 3. Không thể thay đổi số lượng toán hạng 4. Toán tử > đã được nạp chồng rồi để thực hiện nhập/xuất 5. Hàm toán tử không được chứa tham số mặc định Nạp chồng toán tử hai ngôi Khi nạp chồng toán tử hai ngôi hàm toán tử sẽ chỉ có một tham số duy nhất. Tham số này sẽ nhận một đối tượng là toán hạng nằm bên phải của toán tử (phép toán). Ví dụ: // vidu.cpp : main project file. #include "stdafx.h" #include using namespace std; class phanso { public:int tu,mau; public: phanso(){}; public: phanso(int a, int b) { tu=a;mau=b;} void show() { cout<<"Mau so la: "<<tu<<", tu so la: "<<mau<<"\n"; } phanso operator + (phanso ps1) { phanso temp(0,0); temp.mau=mau+ps1.mau; temp.tu=tu+ps1.tu; return temp; } }; int main() { 49 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện phanso p1(1,2),p2(3,4),p3; p3=p1+p2; p3.show(); system("pause"); } Nạp chồng toán tử một ngôi Nạp chồng toán tử một ngôi cũng giống như đối với toán tử hai ngôi. Tuy nhiên toán tử một ngôi chỉ có một toán hạng và do đó hàm toán tử không có tham số. Ví dụ: // vidu.cpp : main project file. #include "stdafx.h" #include using namespace std; class phanso { public:int tu,mau; public: phanso(){}; public: phanso(int a, int b) { tu=a;mau=b; } void show() { cout<<"Mau so la: "<<tu<<", tu so la: "<<mau<<"\n"; } phanso operator + (phanso ps1) { phanso temp(0,0); temp.mau=mau+ps1.mau; temp.tu=tu+ps1.tu; return temp; } phanso operator ++() { 50 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện tu++; mau++; return *this; } }; int main() { phanso p1(1,2),p2(3,4),p3; p3=p1+p2;// Nạp chồng toán tử 2 ngôi p3.show(); // p3++;//Nạp chồng toán tử 1 ngôi p3.show(); system("pause"); } Nạp chồng toán tử so sánh và toán tử logic Như bạn đã biết biểu thức a>b trả về true nếu a lớn hơn b, false nếu a nhỏ hơn b. Trong C++ giá trị false tương ứng với 0, giá trị true tương ứng với một số nguyên khác 0. Do đó người ta thường sử dụng kiểu giá trị trả về của các hàm toán tử (khi chồng toán tử so sánh và toán tử logic) là kiểu số nguyên. Ví dụ: #include "stdafx.h" #include using namespace std; class phanso { public:int tu,mau; public: phanso(){}; public: phanso(int a, int b) { tu=a;mau=b; } void show() 51 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện { cout (phanso ps)//Nạp chồng toán tử so sánh { if(mau>ps.mau&&tu>ps.tu) return 1; if(mau==ps.mau&&tu>ps.tu) return 1; if(tu*ps.mau>mau*ps.tu) return 1; return 0; } }; int main() { phanso p1(1,4),p2(3,4),p3; 52 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện p3=p1+p2; p3.show(); // p3++; p3.show(); // if(p1>p2){cout<<"\np1 lon hon p2";}else cout<<"p2 lon hon p1"<<"\n"; system("pause"); } 2.4 Tính kế thừa 2.4.1 Khái niệm kế thừa Kế thừa là một cách trong lập trình hướng đối tượng để có thể thực hiện được khả năng “sử dụng lại mã chương trình”. Sử dụng lại mã chương trình có nghĩa là xây dựng một lớp mới dựa trên một lớp đã có sẵn. Bằng cách sử dụng lại các lớp đã có chúng ta có thể giảm bớt được thời gian và công sức cần thiết để phát triển chương trình đồng thời làm cho chương trình phần mềm có khả năng có quy mô lớn, rõ ràng hơn về mặt logic và tin cậy hơn. Cú pháp khai báo một lớp kế thừa một lớp khác: class ten_lop_con: mức độ truy cập ten_lop_cha { // thân lớp con } Trong đó “mức độ truy cập” sẽ quyết định xem đó là một sự kế thừa thuộc loại nào và tùy vào mức độ truy cập của các thành phần thuộc lớp cha mà lớp con có được phép sử dụng các thành phần của lớp cha hay không. 2.4.2 Các kiểu kế thừa Kiểu kế thừa sẽ quyết định xem các thành phần của lớp cha được lớp con sử dụng với mức độ truy cập như thế nào. Trong C++ có 3 kiểu kế thừa tương ứng với 3 “mức độ truy cập” được khai báo trong cú pháp khai báo kế thừa. 53 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Kế thừa kiểu public: class lop_con: public lop_cha{ } Đây là kiểu kế thừa chúng ta hay dùng nhất. Với kiểu kế thừa này, các đối tượng của lớp con có thể truy cập vào các thành viên public và protected của lớp cha. Các thành viên protected của lớp cha sẽ trở thành thành viên protected của lớp con và các thành viên public của lớp cha trở thành thành viên public của lớp con. Kế thừa kiểu private: class lop_con: private lop_cha{ } Đối với kiểu kế thừa này, tất cả các thành viên của lớp cha (trừ các thành viên có mức độ truy cập private) sẽ trở thành các thành viên private của lớp con và chỉ có thể được sử dụng bởi các phương thức trong lớp con. Kế thừa kiểu protected: class lop_con: protected lop_cha{ } Đối với kiểu kế thừa này, tất cả các thành viên của lớp cha (trừ các thành viên có mức độ truy cập private) sẽ trở thành các thành viên protected của lớp con và có thể được sử dụng bởi các phương thức trong lớp con và các đối tượng của nó. Có thể tóm tắt lại các kiểu kế thừa như sau: - Cột: các kiểu kế thừa - Hàng: phạm vi các biến/phương thức thành phần trong lớp cha - Kết quả: phạm vi các biến/phương thức trong lớp con 2.4.3 Kế thừa với hàm tạo và hàm hủy Tất cả các lớp cha và lớp con đều có thể có hàm tạo và hàm hủy. Nếu cả lớp cha và lớp con đều có hàm tạo, hàm hủy thì hàm tạo của lớp cha sẽ được thực hiện trước hàm tạo của lớp con khi một đối tượng của lớp con được tạo ra. Điều này ngược lại 54 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện với hàm hủy. Tức là, hàm hủy của lớp con sẽ được thực hiện trước hàm hủy của lớp cha. Ví du: #include "stdafx.h" #include using namespace System; using namespace std; class cha { int a,b; public: cha() { cout<<"Day la phuong thuc khoi tao cua lop cha\n"; } public: ~cha() { cout<<"ham huy cua lop cha\n"; } }; class con:public cha{ public:con() { cout<<"Day la phuong thuc khoi tao cua lop con\n"; } public:~con() { cout<<"Ham huy cua lop con\n"; } }; int main() { con obj;//Tạo ra một đối tượng thuộc lớp con system("pause"); } Kết quả: 55 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Day la phuong thuc khoi tao cua lop cha Day la phuong thuc khoi tao cua lop con Ham huy cua lop con ham huy cua lop cha 2.4.4 Phương thức ảo Phương thức ảo cũng giống như một phương thức thành viên khác của lớp. Trên thực tế, phương thức ảo là một phương thức thành viên được khai báo trong lớp cha và sẽ được định nghĩa lại trong các lớp con kế thừa nó. Khi một lớp chứa phương thức ảo được kế thừa bởi một lớp khác, nói chung phương thức này phải được định nghĩa lại cho mục đích riêng của lớp kế thừa. Phương thức ảo được tạo bằng cách đặt từ khóa virtual ngay trước khai báo phương thức. Khi hàm ảo được định nghĩa lại trong lớp con, ta không cần sử dụng từ khóa virtual. Ta có cú pháp khai báo hàm ảo như sau: 56 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện class lop_cha { //các thành phần của lớp //Khai báo hàm ảo có tên là ham_ao, có kiểu trả về là int và không có tham số Public: virtual int ham_ao() { } }; class lop_con : public lop_cha { //các thành phần khác của lớp //định nghĩa lại hàm ảo được kế thừa ở lớp cha Public: int ham_ao() { //nội dung định nghĩa lại hàm ảo } }; 2.4.5 Lớp trừu tượng Một lớp cơ sở trừu tượng là một lớp chỉ được dùng làm cơ sở cho các lớp khác. Không hề có đối tượng nào của một lớp trừu tượng được tạo ra cả, bởi vì nó chỉ được dùng để định nghĩa một số khái niệm tổng quát, chung cho các lớp khác. Một ví dụ về lớp trừu tượng là lớp CON_VAT (con vật), nó sẽ dùng làm cơ sở để xây dựng các lớp con vật cụ thể như lớp CON_CHO (con chó), CON_MEO (con mèo), (xem ví dụ bên dưới) Trong C++ , thuật ngữ “Lớp trừu tượng” đặc biệt áp dụng cho các lớp có chứa các phương thức ảo thuần tuý. Phương thức ảo thuần tuý là một phương thức ảo mà nội dung của nó không có gì. Cách thức định nghĩa một phương thức ảo thuần tuý như sau: virtual void tên_phương_thức() = 0 ; Ví dụ: class A { 57 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện public: virtual void nhap() = 0 ; virtual void xuat() = 0 ; void chuong(); } ; Trong ví dụ trên, thì A là lớp cơ sở trừu tượng. Các phương thức nhap và xuat được khai báo là các lớp ảo thuần tuý (bằng cách gán số 0 cho chúng thay cho việc cài đặt các phương thức này). Phương thức chuong() là một phương thức bình thường và sẽ phải có một định nghĩa ở đâu đó cho phương thức này. Không có đối tượng nào của một lớp trừu tượng lại có thể được phát sinh. Tuy nhiên các con trỏ và các biến tham chiếu đến các đối tượng của lớp trừu tượng thì vẫn hợp lệ. Bất kỳ lớp nào dẫn xuất từ một lớp cớ sở trừu tượng phải định nghĩa lại tất cả các phương thức thuần ảo mà nó thừa hưởng, hoặc bằng các phương thức ảo thuần tuý, hoặc bằng những định nghĩa thực sự. Ví dụ: class B : public A { public: virtual void nhap() = 0 ; virtual void xuat() { // Các câu lệnh } } ; Theo ý nghĩa về hướng đối tượng, ta vẫn có thể có một lớp trừu tượng mà không nhất thiết phải chứa đựng những phương thức thuần tuý ảo. Một cách tổng quát mà nói thì bất kỳ lớp nào mà nó chỉ được dùng làm cơ sở cho những lớp khác đều có thể được gọi là “lớp trừu tượng”. Một cách dễ dàng để nhận 58 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện biết một lớp trừu tượng là xem có dùng lớp đó để khai báo các đối tượng hay không? . Nếu không thì đó là lớp cơ sở trừu tượng. 2.4.6 Đa kế thừa Đa kế thừa là cơ chế, trong đó lớp dẫn xuất có thể kế thừa từ hai hay nhiều lớp cơ sở. Khai báo đa kế thừa class : , , { // nội dung lớp dẫn xuất } Ví dụ: Lớp Bus kế thừa từ 2 lớp: Car và PublicTransport class Bus: public Car, protected PublicTransport{ //nội dung lớp Bus }; Chú ý: - Trong đa kế thừa, mỗi lớp cơ sở được phân cách nhau bởi dấu “,” - Mỗi lớp cơ sở có thế có từ khóa mức độ truy cập khác nhau - Nguyên tắc truy cập vào các thành phần của lớp cơ sở cũng hoàn toàn tương tự như trong kế thừa đơn. Vấn đề trùng tên trong đa kế thừa class Legged { public: void move() { } }; class Winged { public: void move() { } }; class Pigeon: public Legged, public Winged { 59 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện }; Pigeon p1; p1.move(); // lỗi p1.Legged::move(); // Legged p1.Winged::move(); // Winged trong ví dụ trên ta thấy một đối tượng p1 thuộc lớp Pigeon kế thừa từ 2 lớp Legged và Winged, cả 2 lớp đó đều có phương thức move() nên khi gọi p1.move() sẽ báo lỗi nên chúng ta phải truy cập thông qua cú pháp: tên_đối_tượng.Tên_lớp_cơ_sở::tên_thành_phần 2.5 Sử dụng một số lớp hữu ích có sẵn 2.5.1 Lớp Container Lớp vật chứa (Container) bao gồm nhiều lớp cơ bản của C++: lớp Vector, lớp danh sách (List) và các kiểu hàng đợi (Stack và Queue), lớp tập hợp (Set) và lớp ánh xạ(Map). Trong chương này sẽ trình bày một số lớp cơ bản của Container là: Set, Stack, Queue và List. a. Giao diện của lớp Container Các lớp cơ bản của Container có một số toán tử và phương thức có chức năng giống nhau, bao gồm: • ==: Toán tử so sánh bằng • <: Toán tử so sánh nhỏ hơn • begin(): Giá trị khởi đầu của con chạy iterator • end(): Giá trị kết thúc của con chạy iterator • size(): Số lượng phần tử đối tượng của vật chứa • empty(): Vật chứa là rỗng • front(): Phần tử thứ nhất của vật chứa • back(): Phần tử cuối của vật chứa • []: Toán tử truy nhập đến phần tử của vật chứa • insert(): Thêm vào vật chứa một (hoặc một số) phần tử 60 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện • push_back(): Thêm một phần tử vào cuối vật chứa • push_front(): Thêm một phần tử vào đầu vật chứa • erase(): Loại bỏ một (hoặc một số) phần tử khỏi vật chứa • pop_back(): Loại bỏ phần tử cuối của vật chứa • pop_front(): Loại bỏ phần tử đầu của vật chứa. Ngoài ra, tuỳ vào các lớp cụ thể mà có một số toán tửvà phương thức đặc trưng của lớp đó. Các toán tử và phương thức này sẽ được trình bày chi tiết trong nội dung từng lớp tiếp theo. b. Con chạy Iterator Iterator là một con trỏ trỏ đến các phần tử của vật chứa. Nó đóng vai trò là một con chạy cho phép người dùng di chuyển qua từng phần tử có mặt trong vật chứa. Mỗi phép tăng giảm một đơn vị của con chạy này tương ứng với một phép dịch đến phần tử tiếp theo hay phần tử trước của phần tử hiện tại mà con chạy đang trỏ tới. Khai báo con chạy Cú pháp chung để khai báo một biến con chạy iterator như sau: Tên_lớp ::iterator Tên_con_chạy; Trong đó: • Tên lớp: là tên của lớp cơ bản ta đang dùng, ví dụ lớp Set, lớp List • T: là tên kiểu lớp của các phần tử chứa trong vật chứa. Kiểu có thể là các kiểu cơ bản trong C++, cũng có thể là các kiểu phức tạp do người dùng tự định nghĩa. • Tên con chạy: là tên biến sẽ được sử dụng làm biến chạy trong vật chứa. Ví dụ: Set ::iterator iter; là khai báo một biến con chạy iter cho lớp tập hợp (Set), trong đó, các phần tử của lớp vật chứa có kiểu cơ bản int. Hoặc: List ::iterator iter; 61 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện là khai báo một biến con chạy iter cho lớp danh sách (List), trong đó, các phần tử có kiểu lớp do người dùng tự định nghĩa là Person. Sử dụng con chạy Con chạy được sử dụng khi cần duyệt lần lượt các phần tử có mặt trong vật chứa. Ví dụ sau sẽ in ra các phần tử có kiểu int của một tập hợp: Set mySet; // Khai báo một đối tượng của lớp Set // các phần tửcó kiểu int Set ::iterator i; // Khai báo con chạy của lớp Set, // các phần tử có kiểu int // Thêm phần tửvào for(i=mySet.begin(); i // Thưviện riêng của lớp tập hợp hoặc: #include // Thưviện chung cho các lớp vật chứa a. Hàm khởi tạo 62 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Lớp tập hợp có ba kiểu khởi tạo chính: • Khởi tạo không tham số: Set Tên_đối_tượng; • Khởi tạo bằng một mảng các đối tượng phần tử: Set Tên_đối_tượng(T*, chiều_dài_mảng); • Khởi tạo bằng một đối tượng thuộc lớp tập hợp khác: Set Tên_đối_tượng(Set ); Trong đó: • T: là tên kiểu của các phần tử của tập hợp. Kiểu này có thể là kiểu cơ bản của C++, cũng có thể là các kiểu cấu trúc (struct) hoặc lớp (class) do người dùng tự định nghĩa. Ví dụ: Set mySet; là khai báo một đối tượng mySet của lớp tập hợp, mySet khởi đầu chưa có phần tử nào, các phần tử của đối tượng này có kiểu cơ bản int. Hoặc: Person *myPerson = new Person[10]; // Khởi tạo mảng đối tượng Set mySet(myPerson, 10); // Khai báo tập hợp là khai báo một đối tượng mySet của lớp tập hợp, có 10 phần tử tương ứng với các phần tử trong mảng động myPerson, các phần tử có kiểu lớp Person. b. Toán tử Các toán tửtrên lớp tập hợp là tương ứng với các toán tửsốhọc trên tập hợp thông thường: OR “|”, AND “&”, XOR “^” và phép trừ“-”. Phép toán “|” và “|=” Phép toán này trả vềp hép hợp (OR) của hai đối tượng của lớp tập hợp, kết quả cũng là một đối tượng của lớp tập hợp: = | ; 63 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện |= ; Ví dụ, mySet1 chứa hai phần tử kiểu int {1,2}, mySet2 chứa ba phần tử kiểu int {2,3,4}, và: mySet3 = mySet1 | mySet2; thì mySet3 sẽ chứa các phần tử kiểu int là {1,2,3,4}. Phép toán “&” và “&=” Phép toán này trả về phép giao (AND) giữa hai đối tượng tập hợp, kết quả cũng là một đối tượng tập hợp: = & ; &= ; Ví dụ, mySet1 chứa hai phần tử kiểu int {1,2}, mySet2 chứa ba phần tử kiểu int {2,3,4}, và: mySet3 = mySet1 & mySet2; thì mySet3 sẽ chứa các phần tử có kiểu int là {2}. Phép toán “^” và “^=” Phép toán này trả về phép hợp ngoại (XOR) giữa hai đối tượng tập hợp, kết quả cũng là một đối tượng tập hợp: = ^ ; ^= ; Ví dụ, mySet1 chứa hai phần tử kiểu int {1,2}, mySet2 chứa ba phần tử kiểu int {2,3,4}, và: mySet3 = mySet1 ^ mySet2; thì mySet3 sẽ chứa các phần tử có kiểu int là {1,3,4}. Phép toán “-” và “-=” Phép toán này trả về phép hiệu (loại trừ) giữa hai đối tượng tập hợp, kết quả cũng là một đối tượng tập hợp: = - ; -= ; 64 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Ví dụ, mySet1 chứa hai phần tử kiểu int {1,2}, mySet2 chứa ba phần tử kiểu int {2,3,4}, và: mySet3 = mySet1 - mySet2; thì mySet3 sẽ chứa các phần tử có kiểu int là {1}. c. Phương thức Lớp tập hợp có một số phương thức cơ bản sau: • Thêm một phần tử vào tập hợp • Loại một phần tử khỏi tập hợp • Tìm kiếm một phần tử trong tập hợp Thêm một phần tử vào tập hợp Có hai cú pháp để thêm một phần tử vào tập hợp: pair insert(T&); iterator insert( , T&); Trong đó: • Phương thức thứ nhất thêm một phần tử vào tập hợp, nếu phần tử đã có mặt trong tập hợp, trả về false và vị trí con chạy của phần tử đó. Nếu phần tử chưa tồn tại, trả về true và vị trí con chạy của phần tử mới thêm vào. • Phương thức thứ hai cũng thêm vào một phần tử, nhưng chỉ kiểm tra xem phần tử đã tồn tại hay chưa bắt đầu từ vị trí con chạy được chỉ ra trong biến . Phương thức này trả về vị trí con chạy của phần tử mới thêm vào (nếu thành công) hoặc vị trí của phần tử đã có mặt. Ví dụ, mySet là một tập hợp kiểu int: mySet.insert(10); sẽ thêm một phần tử có giá trị 10 vào tập hợp. Lưu ý: 65 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện • Do tuân thủ theo lí thuyết tập hợp, nên khi chèn vào tập hợp nhiều lần với cùng một giá trị phần tử. Trong tập hợp ch ỉtồn tại duy nhất một giá trị phần tử đó, không được trùng lặp. Loại một phần tử khỏi tập hợp Có ba cú pháp để loại bỏ phần tử khỏi tập hợp: int erase(T&); void erase( ); void erase( , ); Trong đó: • T: là tên kiểu các phần tử của tập hợp. • Phương thức thứ nhất xoá phần tử có giá trị được chỉ rõ trong tham số đầu vào. • Phương thức thứ hai loại bỏ phần tử ở vị trí của con chạy được xác định bởi tham số đầu vào. • Phương thức thứ ba loại bỏ một số phần tử nằm trong phạm vi từ cho đến của con chạy. Ví dụ, mySet là một tập hợp các phần tử có kiểu int: mySet.erase(10); sẽ xoá phần tử có giá trị 10, hoặc: mySet.erase((Set ::iterator)10); sẽ xoá phần tử ở vị trí thứ 10 trong tập hợp, hoặc: mySet.erase(mySet.begin(), mySet.end()); sẽ xoá toàn bộ các phần tử hiện có của tập hợp mySet. Tìm kiếm một phần tử trong tập hợp Có hai cú pháp để tìm kiếm một phần tử trong tập hợp: iterator find(T&); int count(T&); 66 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Trong đó: • Phương thức thứ nhất tìm phần tử có giá trị xác định bởi tham số đầu vào, kết quả là vị trí con chạy của phần tử đó. • Phương thứ thứ hai chỉ để kiểm tra xem phần tử có xuất hiện trong tập hợp hay không: trả về1 nếu có mặt, trả về 0 nếu không có mặt. Ví dụ, mySet là một tập hợp các phần tử có kiểu int: Set ::iterator index = mySet.find(10); cout #include #include void main(){ clrscr(); Set mySet; int function; do{ clrscr(); cout << “CAC CHUC NANG:” << endl; cout << “1: Them mot phan tu vao tap hop” << endl; cout << “2: Loai bo mot phan tu khoi tap hop” << endl; cout << “3: Xem tat ca cac phan tu cua tap hop” << endl; cout << “5: Thoat!” << endl; cout << “===” << endl; 67 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout > function; switch(function){ case ‘1’: // Thêm vào char phantu; cout > phantu; mySet.insert(phantu); break; case ‘2’: // Loại ra char phantu; cout > phantu; mySet.erase(phantu); break; case ‘3’: // Duyệt cout ::iterator i; for(i=mySet.begin(); i<mySet.end(); i++) cout << mySet[i] << “ ”; break; }while(function != ‘5’); return; } 2.5.3 Lớp chuỗi kí tự 68 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Lớp chuỗi (String) cũng là một loại lớp chứa, nó chứa một tập các phần tử là một dãy các kí tự có phân biệt thứ tự, các phần tử không nhất thiết phải phân biệt nhau. Muốn sử dụng lớp String, cần thêm vào chỉ thị đầu tệp: #include a. Hàm khởi tạo Lớp String có ba hàm khởi tạo chính: • Hàm khởi tạo không tham số: String ; • Hàm khởi tạo từ một string khác: String (const String &); • Hàm khởi tạo từ một mảng các kí tự: String (char*, ); Ví dụ: String myStr; là khai báo một chuỗi myStr chưa có phần tử nào (rỗng). Hoặc: String myStr(“hello!”); là khai báo một chuỗi myStr có các phần tử theo thứ tự là {‘h’, ’e’, ’l’, ’l’, ’o’, ’!’}. Hoặc: char* myChar = new char[10]; String myStr(myChar, 10); là khai báo một chuỗi myStr có 10 phần tử tương ứng với các kí tự trong mảng myChar. Lưu ý: • Trong trường hợp khởi tạo bằng một chuỗi khác, ta có thể truyền vào một đối số có kiểu cơ bản khác, trình biên dịch sẽ tự động chuyển đối số đó sang dạng string. 69 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Ví dụ: String myStr(12); thì chuỗi myStr sẽ chứa hai phần tửkí tự{‘1’, ’2’}. Hoặc: String myStr(15.55); thì chuỗi myStr sẽchứa năm phần tửkí tự{‘1’, ’5’, ’.’, ’5’, ’5’}. b. Toán tử Lớp String có các toán tử cơ bản là: • Phép gán chuỗi • Phép cộng chuỗi • Phép so sánh chuỗi • Phép vào/ra Phép gán chuỗi “=” Cú pháp phép gán chuỗi là tương tự cú pháp gán các đối tượng cơ bản: = ; Ví dụ: String s1(12), s2; s2 = s1; thì chuỗi s2 cũng chứa hai phần tử như s1 {‘1’, ‘2’}. Lưu ý: • Có thể gán trực tiếp các đối tượng cơ bản cho chuỗi: String myStr = 12; // myStr có hai phần tử{‘1’, ‘2’} • Nhưng phép gán lại có độ ưu tiên thấp hơn phép toán học: String myStr = 12+1.5; // tương đương myStr = 13.5 Phép cộng chuỗi “+” và “+=” 70 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Phép cộng chuỗi sẽ nối chuỗi thứ hai vào sau chuỗi thứ nhất, kết quả cũng là một chuỗi: = + ; += ; Ví dụ: String s1(12), s2(3); s1+= s2; thì s1 sẽ có ba phần tử kí tự{‘1’, ‘2’, ‘3’}. Phép so sánh chuỗi Các phép so sánh chuỗi đều là các phép toán hai ngôi, trả về kết quả ở dạng bool (true/false): • Phép so sánh lớn hơn “>”: chuỗi_1 > chuỗi_2; • Phép so sánh lớn hơn hoặc bằng “>=”: chuỗi_1 >= chuỗi_2; • Phép so sánh nhỏhơn “<”: chuỗi_1 < chuỗi_2; • Phép so sánh nhỏhơn hoặc bằng “<=”: chuỗi_1 <= chuỗi_2; • Phép so sánh bằng “==”: chuỗi_1 == chuỗi_2; • Phép so sánh khác (không bằng) “!=”: chuỗi_1 != chuỗi_2; Lưu ý: • Phép so sánh chuỗi thực hiện so sánh mã ASCII của từng kí tự ởhai chuỗi theo thứtự tương ứng cho đến khi có sựkhác nhau đầu tiên giữa hai kí tự. • Phép so sánh là phép so sánh dựa trên từ điển, có phân biệt chữhoa và chữthường. Ví dụ: “12” < “a”; // có giá trị đúng “a” <= “A”; // có giá trịsai 71 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Phép vào/ra • Phép xuất ra “ >”: cin >> biến_chuỗi; Ví dụ: String s(“hello!”); cout .length(); trả về chiều dài của chuỗi (số lượng phần tử kí tự trong chuỗi). Ví dụ: String s(“hello!”); cout .find( , , ); 72 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Trong đó: • Tham số thứ nhất là chuỗi con cần tìm. • Tham số thứ hai là vị trí để bắt đầu tìm, mặc định là bắt đầu tìm từ phần tử có chỉ số 0. • Tham số thứ ba chỉ ra cách so khớp có phân biệt chữ hoa với chữ thường: SM_IGNORE là không phân biệt, SM_SENSITIVE là có phân biệt. • Phương thức này trả về kết quả dạng bool, tương ứng là có tìm thấy hay không. Ví dụ: s.find(“12”, 0, SM_IGNORE); sẽ tìm trong chuỗi s xem có sự xuất hiện của chuỗi “12” hay không, vị trí bắt đầu tìm là 0, với cách tìm không phân biệt chữ hoa chữ thường. Thêm một chuỗi con Cú pháp: .insert( , ); Trong đó: • Tham số thứ nhất là vịtrí chỉ số mà tại đó, chuỗi con sẽ được chèn vào • Tham số thứ hai là chuỗi con cần chèn, chuỗi con này cũng có thể là một kí tự. Ví dụ: s.insert(0, “12”); sẽ chèn vào đầu chuỗi s một chuỗi con có hai phần tử “12”. Xoá một chuỗi con Cú pháp: .delete( , ); Trong đó: • Tham số thứ nhất là vị trí bắt đầu xoá chuỗi con • Tham số thứ hai là độ dài chuỗi con bị xoá, giá trị mặc định là 1. 73 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Ví dụ: s.delete(0, 2); sẽ xoá hai kí tự đầu của chuỗi s. Chuyển kiểu kí tự • Đổi chuỗi thành các kí tự hoa: .toUpper(); • Đổi chuỗi thành các kí tự thường: .toLower(); Ví dụ: s.toUpper(); // chuyển chuỗi s thành kí tự hoa s.toLower(); // chuyển chuỗi s thành kí tự thường Ví dụ áp dụng #include #include #include void main(){ clrscr(); String myStr; int function; do{ clrscr(); cout << “CAC CHUC NANG:” << endl; cout << “1: Cong them mot chuoi” << endl; cout << “2: Chen them mot chuoi” << endl; cout << “3: Xoa di mot chuoi” << endl; cout << “4: Tim mot chuoi con” << endl; cout << “5: Chuyen thanh chu hoa” << endl; 74 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout > function; switch(function){ case ‘1’: // Thêm vào cuối String subStr; cout > subStr; myStr += subStr; break; case ‘2’: // Chèn vào chuỗi String subStr; int position; cout > subStr; cout > position; myStr.insert(position, subStr); break; case ‘3’: // Xoá đi một chuỗi con 75 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện int position, count; cout > position; cout > count; myStr.delete(position, count); break; case ‘4’: // Tìm chuỗi con String subStr; int position; cout > subStr; cout > position; if(myStr.find(position, subStr)) cout << “Co xuat hien!” << endl; else cout << “Khong xuat hien!” << endl; break; case ‘5’: // Chuyển thành chữhoa myStr.toUpper(); cout << myStr << endl; break; case ‘6’: // Chuyển thành chữthường myStr.toLower(); 76 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout a. Hàm khởi tạo Lớp Stack có hai cách khởi tạo: • Khởi tạo không tham số: Stack biến_ngăn_xếp; • Khởi tạo bằng một ngăn xếp khác, có cùng kiểu phần tử: 77 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Stack biến_ngăn_xếp(Stack ); Trong đó: • T: là kiểu của các phần tử chứa trong ngăn xếp. T có thể là các kiểu cơ bản, cũng có thể là các kiểu phức tạp do người dùng tự định nghĩa. Ví dụ: Stack myStack; là khai báo một biến myStack, chứa các phần tử có kiểu cơ bản int. b. Toán tử Lớp Stack chỉ dùng đến các toán tử gán “=” và toán tử so sánh bằng “==”: • Phép gán “=”: = ; Dùng để gán hai đối tượng ngăn xếp. • Phép so sánh bằng “==”: == ; Dùng để kiểm tra xem hai đối tượng ngăn xếp có bằng nhau hay không. Kết quả trả về có kiểu bool (true/false). c. Phương thức Thêm một phần tử: .push(T); sẽ thêm một phần tử có kiểu T vào đỉnh ngăn xếp. Lấy một phần tử: .pop(); sẽ trả về phần tử đang nằm ở đỉnh ngăn xếp. Kiểm tra tính rỗng: .empty(); sẽ trả về kết quả kiểu bool, tương ứng với trạng thái của ngăn xếp có rỗng hay không. 78 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Kích thước ngăn xếp: .size(); sẽ trả về số lượng các phần tử hiện đang có mặt trong ngăn xếp. Ví dụ áp dụng #include #include #include #include void main(){ clrscr(); Stack myStack; char strIn[250]; cout > strIn; // Nhập chuỗi kí tựtừbàn phím for(int i=0; i<strlen(strIn); i++) // Đặt vào ngăn xếp myStack.push(strIn[i]); while(!myStack.empty()) // Lấy ra từngăn xếp cout << myStack.pop(); return; } 2.5.4.2 Lớp hàng đợi Lớp hàng đợi (queue) cũng là một loại lớp vật chứa, nó chứa các phần tử cùng kiểu, không bắt buộc phải phân biệt nhau nhưng có phân biệt về thứ tự: các thao tác thêm phần tử được thực hiện ở một đầu, các thao tác lấy phần tử ra được thực hiện ở một đầu còn lại của hàng đợi. Phần tử nào được thêm vào trước thì sẽ bị lấy ra trước. Muốn dùng lớp Queue phải dùng chỉ thị đầu tệp: 79 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện #include a. Hàm khởi tạo Lớp Queue có hai cách khởi tạo: • Khởi tạo không tham số: Queue biến_hàng_đợi; • Khởi tạo bằng một hàng đợi khác, có cùng kiểu phần tử: Queue biến_hàng_đợi(Queue ); Trong đó: • T: là kiểu của các phần tử chứa trong hàng đợi. T có thể là các kiểu cơ bản, cũng có thể là các kiểu phức tạp do người dùng tự định nghĩa. Ví dụ: Queue myQueue; là khai báo một biến myQueue, chứa các phần tử có kiểu cơ bản int. b. Toán tử Lớp Queue chỉ dùng đến các toán tử gán “=” và toán tử so sánh bằng “==”: • Phép gán “=”: = ; Dùng để gán hai đối tượng hàng đợi. • Phép so sánh bằng “==”: == ; Dùng để kiểm tra xem hai đối tượng hàng đợi có bằng nhau hay không. Kết quả trả về có kiểu bool (true/false). c. Phương thức • Thêm một phần tử: .push(T); sẽ thêm một phần tử có kiểu T vào cuối hàng đợi. 80 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện • Loại một phần tử: .pop(); sẽ trảvề phần tử đang nằm ở đỉnh đầu hàng đợi. • Kiểm tra tính rỗng: .empty(); sẽ trả về kết quả kiểu bool, tương ứng với trạng thái của hàng đợi có rỗng hay không. • Kích thước hàng đợi: .size(); sẽ trả về số lượng các phần tử hiện đang có mặt trong hàng đợi. Ví dụ áp dụng #include #include #include void main(){ clrscr(); Queue myQueue; int function; do{ clrscr(); cout << “CAC CHUC NANG:” << endl; cout << “1: Them mot tien trinh vao hang doi” << endl; cout << “2: Dua mot tien trinh trinh vao thuc hien” << endl; cout<<“3: Xem tat ca cac tien trinh trong hang doi”<< endl; cout << “5: Thoat!” << endl; 81 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout > function; switch(function){ case ‘1’: // Thêm vào hàng đợi int maso; cout > maso; myQueue.push(maso); break; case ‘2’: // Lấy ra khỏi hàng đợi cout ::iterator i; for(i=myQueue.begin(); i<myQueue.end(); i++) cout << myQueue[i] << “ ”; break; }while(function != ‘5’); return; } 2.5.5 Lớp danh sách liên kết Lớp danh sách liên kết (List) cũng là một kiểu lớp vật chứa, nó chứa các phần tử cùng kiểu, có tính đến thứ tự. Muốn sử dụng lớp List của thư viện C++, phải khai báo chỉ thị đầu tệp: 82 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện #include // Dành riêng cho lớp List hoặc: #include // Dùng chung cho các lớp vật chứa a. Hàm khởi tạo Lớp List có ba kiểu khởi tạo: • Khởi tạo không tham số: List biến_danh_sách; • Khởi tạo tửmột danh sách cùng kiểu: List biến_danh_sách(List ); • Khởi tạo từmột mảng các phần tử: List biến_danh_sách(T* , int ); Trong đó: • T: là kiểu của các phần tử chứa trong danh sách liên kết. T có thể là các kiểu cơ bản, cũng có thể là các kiểu phức tạp do người dùng tự định nghĩa. Ví dụ: List myList; sẽ khai báo một danh sách liên kết myList, các phần tử của nó có kiểu cơ bản int. b. Toán tử Toán tửgán “=” Cú pháp: = ; sẽ copy toàn bộ các phần tử của vào . Toán tử so sánh bằng “==” Cú pháp: = ; 83 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện sẽ trả về một giá trị kiểu bool, tương ứng với việc hai danh sách này có bằng nhau hay không. Việc so sánh được tiến hành trên từng phần tử ởvịtrí tương ứng nhau. Lưu ý: • Ngoài ra còn có các phép toán so sánh khác cũng có thểthực hiện trên danh sách: , =, !=. c. Phương thức Thêm một phần tử vào danh sách Cú pháp: .insert( , ); .push_front( ); .push_back( ); Trong đó: • Phương thức thứ nhất chèn một phần tử vào một vị trí bất kì của danh sách, vị trí chèn được chỉ ra bởi tham số thứ nhất. • Phương thức thứ hai chèn một phần tử vào đầu danh sách • Phương thức thứ ba chèn một phần tử vào cuối danh sách. Ví dụ: List myList; myList.push_front(7); sẽ chèn vào đầu danh sách myList một phần tử có giá trị là 7. Xoá đi một phần tử Cú pháp: .erase( ); .pop_front(); .pop_back(); 84 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Trong đó: • Phương thức thứ nhất xóa một phần tử ở một vị trí bất kì của danh sách, vị trí xoá được chỉ ra bởi tham số thứ nhất. • Phương thức thứ hai xoá một phần tử ở đầu danh sách • Phương thức thứ ba xoá một phần tử ở cuối danh sách. Ví dụ: List myList; cout .empty(); trả về giá trị bool, tương ứng với trạng thái hiện tại của biến danh sách là rỗng hay không. Xem kích thước danh sách Cú pháp: .size(); Ví dụ: cout .get(); .next(); Trong đó: • Phương thức thứ nhất trả về phần tử ở vị trí hiện tại của con chạy 85 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện • Phương thức thứ hai trả về phần tử tiếp theo, và con chạy cũng di chuyển sang phần tử đó. Ví dụ: List myList; cout #include #include #include typedef struct{ char name[25]; // Tên nhân viên int age; // Tuổi nhân viên float salary; // Lương nhân viên } Employee; void main(){ clrscr(); List myList; int function; do{ clrscr(); cout << “CAC CHUC NANG:” << endl; cout << “1: Them mot nhan vien” << endl; cout << “2: Xoa mot nhan vien” << endl; 86 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện cout > function; switch(function){ case ‘1’: // Thêm vào ds int position; Employee employee; cout > position; cout > employee.name; cout > employee.age; cout > employee.salary; myList.insert(position, employee); break; case ‘2’: // Lấy ra khỏi ds int position; cout > position; Employee result = myList.erase(position); 87 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện if(result != NULL){ cout << “Nhan vien bi loai: ” endl; cout << “Ten: ” << result.name << endl; cout << “Tuoi: ” << result.age << endl; cout << “Luong: ” << result.salary << endl; } break; case ‘3’: // Duyệt ds cout << “Cac nhan vien cua phong:” << endl; Employee result = myList.front(); do{ cout << result.name << “ ” << result.age << “ ” << result.salary << endl; result = myList.next(); }while(result != NULL); break; }while(function != ‘5’); return; } Chương 4: Xử lý đồ họa căn bản 4.1. Winform căn bản 4.1.1. Giới thiệu căn bản về ứng dụng winform với C++ .Net Lập trình winform là một trong những cách phát triển ứng dụng phổ biến nhất hiện nay. Ứng dụng winform có thể xem như là một tập hợp các form, mỗi form lại gồm các control cần thiết (ô nhập văn bản, danh sách lựa chọn, nút bấm, tab ) nhằm tạo 88 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện một giao diện người dùng thân thiện nói cách khác là nơi hiển thị và tiếp nhận các thông tin tương tác giữa người sử dụng và chương trình. Các form này có thể hoạt động độc lập hoặc có quan hệ tương tác với nhau. Đa số các ứng dụng trên desktop windows là các ứng dụng winform (phần mềm office, windows media player, các phần mềm quản lý ). Form ví dụ gồm một số control (điều khiển) căn bản Ngày nay việc phát triển một ứng ứng dụng winform trở lên cực kỳ dễ dàng thông qua bộ công cụ Visual Studio cụ thể trong tài liệu này tôi đề cập tới bộ Visual Studio 2010, và tất nhiên đi kèm với nó là nền tảng .Net vô cùng mạnh mẽ, ngày càng được nâng cấp, cải tiến qua từng phiên bản với sự hỗ trợ của gã khổng lồ Microsoft. Như đã nói ở trên, một ứng dụng winform là tập hợp của các form. Mỗi form trong ứng dụng lại chứa các control, form được chia làm 2 phần: - Phần Designer: hiển thị form và các control hay nói cách khác đây chính là phần giao diện của chương trình. 89 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Form Designer đơn giản của form Đăng Nhập - Phần Code Behind: phần code xử lý cho các sự kiện, các tương tác của người dùng. Lập trình winform cũng có thể xem như là một hình thức của lập trình hướng sự kiện vì tất cả mọi hành động, tương tác của người dùng được chương trình tiếp nhận và xử lý thông qua các sự kiện. Form và các control đều được hỗ trợ rất nhiều sự kiện cho lập trình viên dễ dàng sử dụng, điều khiển chúng trong ứng dụng. Một form được chúng ta tạo ra là một lớp được kế thừa từ lớp Windows::Forms::Form chính vì vậy khi chúng ta tạo ra một form nó đã kế thừa rất nhiều thuộc tính và phương thức từ lớp Form, và tất nhiên đi kèm không thể thiếu với nó là các sự kiện. Một số sự kiện, thuộc tính này có thể được tìm thấy trong khung Properties (chọn form click chuột phải, 90 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện chọn properties hoặc chọn form nhấn F4). Bảng dưới đây liệt kê một số thuộc tính và sự kiện thông dụng của form: Thuộc tính Ý nghĩa Name Tên form Text Tiêu đề form AcceptButton Thiết lập nút được nhấn khi ta nhấn phím Enter CancelButton Tthiết lập nút được nhấn khi ta nhấn phím Esc BackColor Thiết lập màu nền cho form BackgroundImage Thiết lập hình nền cho form Icon Thiết lập icon cho form Opacity Thiết lập độ mờ của form ShowIcon Có cho phép hiện icon của form hay không ShowInTaskar Có hiện biểu tượng form tại thanh taskbar hay không Size Thiết lập kích thước của form StartPosition Thiết lập vị trí khi form khởi chạy WindowState Thiết lập trạng thái của form khi khởi chạy Sự kiện Ý nghĩa Activited Định nghĩa phương thức sẽ được thực hiện khi form được activited Click Định nghĩa phương thức sẽ được thực hiện khi form được click KeyDown Định nghĩa phương thức sẽ được thực hiện khi ta nhấn một phím KeyPress Định nghĩa phương thức sẽ được thực hiện khi ta nhấn một phím và nhả ra KeyUp Định nghĩa phương thức sẽ được thực hiện khi ta nhả một phím Load Định nghĩa phương thức sẽ được thực hiện khi người sử dụng gọi tới form, và form được hiện ra Các bước cơ bản tạo một ứng dụng winform - Tạo mới một Project Bước 1: Vào menu File -> New->Project 91 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Bước 2: Hộp thoại New Project xuất hiện, tại ô Recent Tamplate chọn Visaul C++, tiếp theo chọn Windows Form Application, đặt tên cho Project tại ô Name và nhấn OK Kết quả sẽ được một Project bao gồm 1 form mặc định tên là Form1 như hình dưới. 92 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện - Thêm một form mới vào Project Bước 1: Tại khung Solution Explorer click chuột phải vào tên project → Add → New Item Hộp thoại Add New Item hiện ra click chọn Windows Form, đặt tên cho form và nhấn Add 93 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện - Chọn form chạy đầu tiên khi bắt đầu ứng dụng Như ta đã biết, trong một ứng dụng sẽ có thể có nhiều form và chúng ta có thể chọn một form bất kỳ trong số đó là form khởi động ứng dụng tức là form đó sẽ chạy đầu tiên khi ứng dụng của ta được bắt đầu, để làm được điều đó chúng ta thực hiện như sau: Tại khung Solution Explorer, tìm đến thư mục Source Files, mở file ten_project_.cpp, tìm tới dòng Application::Run(gcnew Form1()); thay Form1 bằng tên form muốn chạy đầu tiên. 94 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 95 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 4.1.2. Một số điều khiển cơ bản - Button: là điều khiển cho phép người dùng click để thực hiện một hành động, với điều khiển này ta thường quan tâm nhất tới sự kiện click và thuộc tính text. Để viết hàm xử lý cho sự kiện click của button, tại cửa sổ desinger của form ta click đúp vào button, Visual studio sẽ chuyển tới cửa sổ viết code xử lý cho sự kiện click vào button, để viết cho các sự kiện khác của button ta tham khảo cửa sổ Properties. - CheckBox: điều khiển cho phép người dùng tích chọn một số điều kiện. Trong một nhóm các checkbox chúng ta có thể chọn cùng lúc nhiều checkbox. - ComboBox: hiển thị một danh sách xổ xuống các dọng dữ liệu cho phép người dùng lựa chọn, chỉ được lựa chọn một dòng và có thể nhập liệu như textbox - Label: điều khiển dùng để hiển thị nhãn văn bản - PictureBox: điều khiển cho phép người dùng hiển thị hình ảnh trên form - RadioButton: tương tự checkbox tuy nhiên trong một nhóm chỉ có một radiobutton được lựa chọn - TextBox: điều khiển cho người dùng nhập liệu văn bản, thuộc tính cần quan tâm nhất là Name và Text. - Panel: là một khung để chứa các điều khiển khác, hoặc có thể là một vùng để vẽ - ColorDialog: hộp thoại cho phép người dùng chọn màu sắc - FontDialog: hộp thoại cho phép người dùng chọn font chữ - OpenFileDialog: hộp thoại hỗ trợ người dùng duyệt mở các file trong máy tính - SaveFileDialog: hộp thoại hỗ trợ người dùng lưu một file từ ứng dụng vào máy tính 96 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 4.2. Tổng quan về đồ họa trong winform Trong phần 4.1 chúng ta đã được làm quen với winform và các điều khiển căn bản trên winform. Trong phần này, chúng ta sẽ đi sâu hơn về đồ họa trong winform, làm thế nào để vẽ được các đối tượng đồ họa (điểm, đoạn thẳng, hình tròn, hình chữ nhật ), hình ảnh, văn bản lên form. .Net framwork sử dụng một giao diện lập trình ứng dụng (API) được nâng cấp lên từ Windows Graphics Device Interface (GDI) gọi à GDI+. GDI+ cung cấp một thư viện các lớp cho phép chúng ta làm việc với các đối tượng đồ họa hai chiều như là các đối tượng hình học cơ bản, hiển thị văn bản, hình ảnh và in ấn. Tuy nhiên, mặc dù GDI + được cải thiện nhiều so với GDI ban đầu, nhưng nó vẫn chỉ là một thư viện đồ họa hai chiều đơn giản, không có các tính năng cao cấp như diễn hoạt hay các hiệu ứng ba chiều. GDI+ cung cấp các chức năng xử lý các đối tượng đồ họa thông qua các NameSpace sau: 1. System::Drawing cung cấp các chức năng vẽ căn bản 2. System::Drawing::Drawing2D cung cấp các chức năng cao cấp hơn cho việc thao tác với các đối tượng đồ họa 2D 3. System::Drawing::Imaging cung cấp các phương thức làm việc với ảnh 4. System::Drawing::Text cung cấp các phương thức làm việc với văn bản 5. System::Drawing::Printing giúp xử lý in ấn 4.3. Làm quen với các đối tượng đồ họa 4.3.1. NameSpace System::Drawing NameSpace System::Drawing cung cấp cách thức truy cập tới các chức năng đồ họa căn bản trong GD+. Dưới đây là bảng liệt kê danh sách các lớp chính trong namespace này: Tên lớp Mô tả Bitmap Làm việc với một bitmap. Lớp này có thể làm việc với nhiều định dạng ảnh khác nhau như: BMP, GIF, và JPG Brush Lớp này được sử dụng để tô màu cho hình Color Lớp màu sắc 97 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Font Thao tác với font chữ Graphics Đây sẽ là lớp thực hiện mọi thao tác đồ họa Icon Làm việc với một biểu tượng (icon) Pen Sử dụng để vẽ hình ( hình rỗng chưa tô màu) Point 2 lớp được sử dụng để thao tác với điểm Rectangle Thao tác với hình chữ nhật Region Thao tác với một vùng Size Trình bày một kích thước StringFormat Giúp làm việc với các thông tin trình bày văn bản TextureBrush Tương tự lớp Brush tuy nhiên nó sử dụng hình ảnh để tô màu 4.3.2. Lớp Graphics Khi cần vẽ lên một form chúng ta cần phải xem xét tới rất nhiều vấn đề. Ví dụ như, vẽ cái gì, vẽ màu như thế nào? Nó sẽ được hiển thị trên loại thiết bị nào? Màu sắc, độ phân giải của thiết bị ra sao? Tuy nhiên không cần quá lo lắng vì GD+ đã giúp bạn giải quyết được các vấn đề đó thông qua lớp Graphics, lớp này sẽ đại diện như một vùng vẽ lý tưởng cho chúng ta. Lớp Graphics cung cấp rất nhiều thao tác hỗ trợ chúng ta trong việc vẽ (trình bày) và hiển thị các đối tượng đồ họa (điểm, đường, đa giác ). Tạo một đối tượng Graphics: Một đối tượng Graphics được tạo ra mà không sử dụng bất kì phương thức khởi tạo nào của lớp Graphics, mà nó sẽ sử dụng phương thức tạo hoặc thuộc tính của các đối tượng mà nó được gắn vào. Vì một đối tượng Graphics được tạo ra luôn phải được gắn với một đối tượng nào đó. Ví dụ như gắn với một form, một panel, picturebox nghĩa là khi tạo ra một đối tượng Graphics thì chúng ta cần phải chỉ ra được rằng đối tượng này sẽ thực hiện việc vẽ của nó tại đâu. Tạo một đối tượng gắn với form: Graphics^ pg = myForm->CreateGraphics(); Tạo một đối tượng mà nó sẽ vẽ trên một panel: Graphics^ pg = myPanel->CreateGraphics(); 98 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 4.3.3. Vẽ Các thao tác vẽ cơ bản được thực hiện bằng cách sử dụng các đối tượng Pen (bút vẽ) và đối tượng Brush (cọ tô màu). Trong khi các đối tượng Pen được sử dụng để vễ đường và các đường nét bao quay một hình thì các đối tượng Brush dùng để tô màu cho phần trong của các hình đó. Đối tượng Pen Cách tạo một đối tượng Pen căn bản // Tạo một bút màu đen với độ rộng nét vẽ là 1pixel (mặc định) Pen^ pen1 = gcnew Pen(Color::Black); // Tạo một bút màu đỏ với động rộng nét vẽ là 2pixel Pen^ pen2 = gcnew Pen(Color::Red, 2.0); Ta thấy việc tạo ra 2 bút ở ví dụ trên có sử dụng một tham số để định nghĩa màu vẽ cho chúng, ở 2 ví dụ trên ta sử dụng thuộc tính tĩnh để thể hiện 2 màu đỏ và đen, bạn có thể tùy chỉnh màu sắc của đối tượng này bằng cách sử dụng đối tượng thuộc lớp Color. Đối tượng Brush Có rất nhiều loại cọ tô màu khác nhau, tất cả chúng đều kế thừa từ lớp Brush. Trong đó, loại cọ SolidBrush là loại cọ đơn giản nhất, nó sẽ tiến hành tô màu vùng được tô với màu thuần nhất (soilid color). // tạo một cọ tô màu xanh da trời SolidBrush^ br1 = gcnew SolidBrush(Color::Blue); Một đối tượng thuộc lớp TextureBrush lại sử dụng một ảnh như là chất liệu để tô lên các đối tượng cần tô. Nếu ảnh nhỏ hơn hình cần tô thì nó sẽ tiến hành tô như kiểu lát gạch. // tạo một TextureBrush sẽ được tô theo kiểu lát gạch TextureBrush^ br2 = gcnew TextureBrush(gcnew Bitmap("brush.bmp"), WrapMode::Tiled); 4.3.4. Các thao tác vẽ cơ bản Chúng ta đã có bút vẽ, cọ tô màu, trong phần này chúng ta sẽ đi tìm hiểu về các thao tác vẽ cơ bản. Lớp Graphics cung cấp cho chúng ta rất nhiều phương thức vẽ, bảng dưới đây là danh sách một số phương thức vẽ phổ biến, hay sử dụng nhất. 99 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Phương thức Mô tả Clear Tô màu kín toàn bộ vùng vẽ DrawClosedCurve, FillClosedCurve Vẽ và tô màu một đường cong kín DrawCurve Vẽ đường cong DrawEllipse, FillEllipse Vẽ và tô màu hình elip DrawIcon Vẽ một biểu tượng DrawImage Vẽ một hình ảnh DrawLine Vẽ đường thẳng DrawPolygon, FillPolygon Vẽ và tô màu đa giác DrawRectangle, FillRectangle Vẽ và tô màu hình chữ nhật DrawString Vẽ một chuỗi văn bản Ví dụ: //tạo đối tượng đồ họa Graphics^ gr=this->CreateGraphics(); //tạo bút vẽ Pen^ p = gcnew Pen(Color::Black); //tạo cọ tô màu SolidBrush^ br= gcnew SolidBrush(Color::Blue); //vẽ đường thẳng gr->DrawLine(p,0,0,200,200); //vẽ hình elip gr->DrawEllipse(p, 20, 20, 60, 80); //tô màu hình elip gr->FillEllipse(br,20,20,60,80); //vẽ hình chữ nhật gr->DrawRectangle(p,50,50,60,100); //tô màu hình chữ nhật gr->FillRectangle(br,100,100,60,100); 100 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện //vẽ một đường cong kín PointF point1 = PointF(50.0F,50.0F); PointF point2 = PointF(100.0F,25.0F); PointF point3 = PointF(200.0F,5.0F); PointF point4 = PointF(250.0F,50.0F); PointF point5 = PointF(300.0F,100.0F); PointF point6 = PointF(350.0F,200.0F); PointF point7 = PointF(250.0F,250.0F); array ^ curvePoints = {point1,point2,point3,point4,point5,point6,point7}; float tension = 1.0F; FillMode aFillMode = FillMode::Alternate; gr->DrawClosedCurve( p, curvePoints,tension, aFillMode); //vẽ tập đường thẳng //gr->DrawLines(p, curvePoints ); //vẽ đa giác Pen^ blackPen = gcnew Pen( Color::Black,3.0f ); // Draw polygon to screen. gr->DrawPolygon( blackPen, curvePoints ); 4.4. Vẽ theo sự kiện Trong lập trình Winform cung cấp cho chúng ta rất nhiều control khác nhau, các control này lại được định nghĩa sẵn rất nhiều sự kiện. Vẽ theo sự kiện có thể được hiểu là chúng ta lập trình sao cho việc vẽ gắn với một sự kiện nào đó xảy ra khi người dùng tương tác với form và các control thông qua một hành động nào đó (bấm nút, click chuột, nhấn phím, chọn một danh sách ). Vẽ theo sự kiện tương tác với một control (nhấn nút) Với một nút bấm thì sự kiện thường dùng nhất là sự kiện click, ví dụ sau đây sẽ trình bày cách vẽ theo sự kiện click của một nút bấm Ví dụ vẽ theo sự kiện nhấn một nút bấm trên form: Bước 1. Tạo một project C++ Windows Forms Application mới đặt tên là CppDraw. 101 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Bước 2. Sử dụng khung Properties đổi tiêu đề form thành Drawing hoặc bất kỳ cái gì bạn muốn, đặt kích thước form khoảng 300x300 pixels. Bước 3. Từ khung toolbox kéo thả một button vào form, tùy chỉnh các thuộc tính cần thiết (Name, Text, Location ) cho button. 102 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Để viết mã lệnh thực thi cho sự kiện click chuột vào nút ta chọn nút, di chuyển sang khung Properties chọn tab event (biểu tượng hình tia sét), tại đây sẽ hiện ra một danh sách rất nhiều các event gắn với button này, tìm tới Click và kích đúp vào đó hoặc cách đơn giản nhất là click đúp vào nút trong form. Sau khi tiến hành thao tác như trên VS sẽ tự sinh ra cho chúng ta một hàm (trong ví dụ này là hàm drawBtn_Click) và tất cả những gì chúng ta viết trong hàm đó sẽ được thực thi khi nút được bấm. private: System::Void drawBtn_Click(System::Object^ sender, System::EventArgs^ e) { // Tạo một đối tượng Graphics Graphics^ pg = CreateGraphics(); // Tạo một bút vẽ Pen^ pen1 = gcnew Pen(Color::Red); // Vẽ một đường thẳng pg->DrawLine(pen1, 20, 20, 100, 250); // Hủy đối tượng Graphics delete pg; } Vậy kết quả sau khi viết xong code, thực thi chương trình, ta bấm nút thì chương trình sẽ vẽ cho chúng ta một đường thẳng màu đỏ từ tọa độ (20,20) đến (100,250) 103 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Chúng ta có thể thay đổi code thực thi trong hàm thành như sau: // Tạo bút vẽ màu Blue, kích thước 3 pixel Pen^ pen2 = gcnew Pen(Color::Blue, 3.0); //Tạo nét vẽ kiểu nét đứt pen2->DashStyle = Drawing2D::DashStyle::DashDotDot; //Vẽ một đoạn thẳng với bút vừa tạo từ (10,120) đến (250,60) pg->DrawLine(pen2, 10, 120, 250, 60); // Tạo một cọ vẽ màu đỏ SolidBrush^ sb1 = gcnew SolidBrush(Color::Red); //Vẽ một hình chữ nhật và tô màu cho nó bằng cọ vẽ vừa tạo (không vẽ viền) pg->FillRectangle(sb1, 60,30, 40,40); // Vẽ một hình chữ nhật với bút màu đỏ (viền đỏ), và trong tô màu vàng SolidBrush^ sb2 = gcnew SolidBrush(Color::Yellow); pg->FillRectangle(sb2, 90, 40, 45, 45); pg->DrawRectangle(pen1, 90, 40, 45, 45); // Vẽ một hình elip và tô màu xanh SolidBrush^ sb3 = gcnew SolidBrush(Color::Green); pg->FillEllipse(sb3, 30,100, 65, 50); và kết quả sau khi click 104 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Vẽ theo sự kiện tương tác với chuột Để biết được .Net cung cấp cho chúng ta những sự kiện tương tác nào với chuột ta chọn khung Properties, chọn tab Event kéo xuống phí dưới ta sẽ nhìn thầy một loạt các sự kiện về Mouse liên quan tới đối tượng đang được chọn bên form nghĩa là các sự kiện của chuột này sẽ xảy ra khi ta làm hành động tương ứng với đối tượng đang được chọn bên form (có thể là form hoặc các điều khiển trong form). Để hiểu rõ hơn về việc vẽ theo sự kiện tương tác với chuột chúng ta sẽ đi làm một ví dụ. Ví dụ vẽ đoạn thẳng với tọa độ phụ thuộc vào tọa độ chuột trên đối tượng: Ta tiếp tục làm việc trên project đã được ta ra ở phần trên. Ta khai báo thêm hai biến thành viên theo kiểu Point để lưu tọa đọ điểm đầu và điểm cuối của đoạn thẳng. Trong các sự kiện về chuột được liệt kê trong khung Properties có sự kiện MouseDown xảy ra khi ta nhấn chuột và sự kiện MouseUp xảy ra khi ta nhả chuột, chúng ta sẽ sử dụng 2 sự kiện này. 105 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Code thực hiện cho sự kiện MouseDown: Khi nhấn chuột ta sẽ lấy tọa độ hiện tại của chuột trên form và gán cho điểm p1 private: System::Void Form1_MouseDown(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { p1.X = e->X;//Tọa độ X của chuột được gán cho X của điểm p1 p1.Y = e->Y;// Tọa độ Y của chuột được gán choY của điểm p1 } Tương tự với sự kiện MouseUp và sau khi lấy được tọa độ khi nhả chuột gán cho p2 ta tiến hành vẽ đoạn thẳng ngay với điểm bắt đầu là p1 và kết thúc ở p2 private: System::Void Form1_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { p2.X = e->X; p2.Y = e->Y; Graphics^ gr = CreateGraphics(); Pen^ pen1 = gcnew Pen(Color::Black); gr->DrawLine(pen1, p1.X, p1.Y, p2.X, p2.Y); //gr->Dispose(); delete gr; } 106 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện 4.5. Sử dụng màu sắc, fonts 4.5.1. Sử dụng màu sắc Vấn đề Color (màu sắc) được trình bày trong cấu trúc System::Drawing::Color và được tạo lên từ 4 thành phần R, G, B và A. Ba thành phần đầu tiên đại diện cho 3 yếu tố đỏ (R), xanh lá cây (G), xanh da trời (B) của một màu theo hệ màu RGB, các giá trị này nằm trong khoảng từ 0 đến 255. Thành phần A trình bày độ trong suốt của màu sắc và cũng có giá trị chạy từ 0 (trong suốt hoàn toàn) đến 255 (mờ hoàn toàn). Cũng giống như Graphics, cấu trúc Color không có hàm khởi tạo. Chúng ta có thể tạo ra một thể hiển của cấu trúc Color bằng 3 phương thức sau đây: - FromArgb: tạo ra một Color từ tập các giá trị A, R, G, B. // Tạo một đối tượng màu đỏ với độ trong suốt là 255 (mờ đục hoàn toàn) Color c1 = Color::FromArgb(255, 255, 0, 0); - FromKnownColor: tạo ra một Color từ thành phần KnownColor. Lớp Color định nghĩa ra một số lượng rất lớn các thuộc tính để trình bày các màu sắc được định nghĩa bởi hệ thống bao gồm một dãy các màu từ AliceBlue cho đến YellowGreen. Kiểu liệt kê KnownColor định nghĩa một danh sách các màu trong hệ thống, nó bao gồm các màu chuẩn được định nghĩa sẵn, chính là các màu sắc được sử dụng trong Windows GUI như ActiveCaption và WindowText. Các giá trị màu sắc này có thể được thay đổi nếu người dùng điều chỉnh màu sắc desktop trong Control Panel. // Khởi tạo một màu chuẩn từ KnownColor Color c2 = Color::FromKnownColor(KnownColor::Cornsilk); - FromName: tạo một Color với tham số là tên màu //Tạo một màu với tên là Blue 107 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Color c1 = Color::FromName( "Blue" ); //Thêm một cách nữa để tao ra một màu Color c3 = Color::Cornsilk; Chú ý rằng khi một màu đã được tạo ra thì không thể thay đổi giá trị của nó. Nếu cần thay đổi một màu, bạn sẽ phải tạo ra một màu mới dựa trên một màu đã có. Ví dụ: // tạo ra một màu đỏ Color c4 = Color::FromArgb(255, 255, 0, 0); // tạo ra một màu khác dựa trên màu c4 và thay đổi thông số độ trong suốt Color c5 = Color::FromArgb(127, c4.R, c4.G, c4.B); Ngoài các cách sử dụng màu sắc ở trên thì trong lập trình winform còn hỗ trợ chúng ta một cách sử dụng màu sắc rất trực quan và thuận tiện cho người sử dụng đó là sử dụng control hộp thoại màu ColorDialog. - Cú pháp khai báo và gọi một ColorDialog như sau: //Khai báo ColorDialog^ MyDialog = gcnew ColorDialog; //Gọi nó ra MyDialog->ShowDialog(); 108 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện - Sau khi ColorDialog được gọi ra, người sử dụng chọn màu sắc ưng ý và nhấn ok thì ta có thể sử dụng màu sắc vừa được chọn đó thông qua thuộc tính quan trọng nhất của ColorDialog đó là thuộc tính: Color Ví dụ sử dụng ColorDialog: private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { //Tạo đối tượng hộp thoại màu ColorDialog^ MyDialog = gcnew ColorDialog; //tạo đối tượng đồ họa trên panel1 Graphics^ gr=panel1->CreateGraphics(); //Sau khi chọn xong màu và nhấn ok sẽ thực hiện tô toàn bộ vùng vẽ theo màu chọn if ( MyDialog->ShowDialog() == ::System::Windows::Forms::DialogResult::OK ) { gr->Clear(MyDialog->Color); } } 4.5.2. Sử dụng fonts Trong namspace System::Drawing có cung cấp cho chúng ta lớp Font để làm việc với font chữ. Một đối tượng của lớp Font sẽ trình bình một font với một số thuộc tính như tên, kích cỡ hay kiểu font. Bảng dưới đây liệt kê một số thuộc tính của lớp Font, các thuộc tính này là thuộc tính chỉ đọc (read-only) nghĩa là khi đã tạo ra đối tượng Font với các thuộc tính được khai báo thì các thuộc tính này không thể thay đổi được nữa. Thuộc tính Mô tả Bold Có giá trị True nếu style của font là in đậm (Bold) FontFamily Trả về họ font của font hiện tại Height Trả về độ cao Italic Có giá trị True nếu style của font là in nghiêng (Italic) Name Trả về tên font Size Kích thước font 109 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Strikeout Trả về true nếu font có style là kiểu gạch giữa Style Trả về thông tin kiểu (style) của font Underline Trả về true nếu font có style là kiểu gạch chân Unit Trả về kiểu đơn vị đo của font. Mặc định là pixels Style của font có thể được kết hợp từ nhiều giá trị thuộc tập hợp FontStyle, nó bao gồm Bold, Italic, Regular, Strikeout, và Underline. Một font được tạo ra có thể gồm một hoặc nhiều Style. Cú pháp khai báo sử dụng một font như sau: //Khai báo một font, bạn nên khai báo rõ ràng từ NameSpace để tránh nhầm với thuộc tính /font của Form private: System::Drawing::Font^ font1; //Tạo font với một style font1 = gcnew System::Drawing::Font("Verdana", 8, FontStyle::Regular, GraphicsUnit::Millimeter); //Tạo font với nhiều style ta dùng dấu | để phân biệt giữa các style font1 = gcnew System::Drawing::Font("Verdana", 8, FontStyle::Regular|FontStyle::Italic, GraphicsUnit::Millimeter); trong đó - “Verdana” là tên font, có rất nhiều tên font ví dụ như “Tahoma”, “Times New Roman” - 8: kích cỡ font - FontStyle::Regular: kiểu font có thể là Bold, Italic, Regular, Strikeout, và Underline - GraphicsUnit::Millimeter: xách định đơn vị đo của font nó có thể là các giá trị: Inch, Millimeter, Pixel. Sau đây là ví dụ vẽ một dòng text theo sự kiện click chuột như ví dụ trước tuy nhiên lần này ta sẽ vẽ ra một dòng text khi chuột phải được click: private: System::Void Form1_MouseUp(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) { Graphics^ gr = CreateGraphics(); 110 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện Pen^ pen1 = gcnew Pen(Color::Black); //Chuột trái được click if (e->Button == ::CppDraw::MouseButtons::Left) { // vẽ đoạn thẳng p2.X = e->X; p2.Y = e->Y; gr->DrawLine(pen1, p1.X,p1.Y, p2.X,p2.Y); } //Nếu chuột phải được click else if (e->Button == ::CppDraw::MouseButtons::Right) { // Vẽ text với font1, chữ màu đen, tại vị trí click chuột phải gr->DrawString(L"Right click Text", font1, Brushes::Black, (float)e->X, (float)e->Y); } delete gr; } Tương tự như màu sắc, đối với việc sử dụng font chữ, lập trình winform cũng hỗ trợ chúng ta một cách sử dụng trực quan thông qua hộp thoại font 111 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện - Cú pháp khai báo và gọi một FontDialog như sau: //Khai báo FontDialog^ MyDialog = gcnew ColorDialog; //Gọi nó ra MyDialog->ShowDialog(); - Sau khi FontDialog được gọi ra, người sử dụng chọn font chữ và nhấn ok thì ta có thể sử dụng font đó thông qua thuộc tính Font của ColorDialog, ngoài ra FontDigalog còn cho phép chúng lựa chọn và sử dụng màu sắc (một số màu cơ bản). Ví dụ sử dụng FontDialog: //khai báo FontDialog^ myFd=gcnew FontDialog(); //cho phép chọn màu sắc myFd->ShowColor=true; //tạo đối tượng đồ họa Graphics^ gr=panel1->CreateGraphics(); tạo cọ tô màu với màu lấy từ Fontdiglog 112 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện SolidBrush^ br= gcnew SolidBrush(myFd->Color); //Sau khi chọn màu xong nhấn Ok sẽ vẽ chuỗi if ( myFd->ShowDialog() == ::System::Windows::Forms::DialogResult::OK ) { gr->DrawString("Day la vi du ve font chu",myFd->Font,br,20,50); } 4.6. Thao tác với hình ảnh Để làm việc với hình ảnh chúng ta sử dụng lớp Bitmap được cung cấp sẵn trong System::Drawing. Lớp này hỗ trợ chúng ta trong việc trình bày và thao tác với một số định dạng ảnh như jpg, png, gif Lớp Bitmap là một bản tóm lược của GDI + bitmap, nó bao gồm tập các dữ liệu pixel của hình ảnh và thuộc tính của nó. Một bitmap là một đối tượng được sử dụng để làm việc với ảnh như một tập hợp các điểm ảnh (pixel). Bảng dưới đây liệt kê một số thuộc tính và phương thức phổ biến của lớp Bitmap. Thuộc tính Mô tả Height Trả về chiều cao bằng của ảnh (pixel) HorizontalResolution Trả về độ phân giải ngang (pixel/inch) Palette Trả về hoặc thiết lập bảng màu PhysicalDimension Trả về kích thước của ảnh PixelFormat Trả về định dạng điểm ảnh RawFormat Trả về định dạng ảnh Size Trả về chiều rộng và chiều cao của ảnh (pixel) VerticalResolution Trả về độ phân giải dọc (pixel/inch) Width Trả về độ rộng của ảnh (pixel) Phương thức 113 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện FromFile Tạo ra một ảnh từ file FromHbitmap Tạo ra một ảnh Bitmap từ một Windows handle FromHicon Tạo ra một ảnh Bitmap từ một Windows handle thành icon. FromResource Tạo ra một ảnh Bitmap từ một Windows resource. FromStream Tạo ra một ảnh Bitmap từ một data stream GetBounds Trả về đường bao của ảnh GetPixel Trả về một điểm ảnh ( Color) GetThumbnailImage Tạo ảnh thumbail Trả về giá trị để biểu thị xem pixel có chứa thông tin alpha IsAlphaPixelFormat hay không LockBits Khóa một Bitmap trong bộ nhớ hệ thống MakeTransparent Tạo độ trong suốt mặc định cho ảnh RotateFlip Quay, lật ảnh Save Lưu ảnh SetPixel Thiết lập một điểm ảnh cho ảnh SetResolution Thiết lập độ phân giải cho ảnh UnlockBits Mở khóa ảnh này ra khỏi bộ nhớ hệ thống Ví dụ: Vẽ một ảnh lên form // Vẽ một ảnh của tên là ramp1.gif, ảnh này đặt cùng thư mục với file nguồn chương trình Bitmap^ bmp = gcnew Bitmap(L"ramp1.gif"); gr->DrawImage(bmp, 10,10);//Vẽ ảnh tại vị trí 10,10 Như đã trình bày ở trên, một đối tượng của lớp Bitmap sẽ trình bày một ảnh như là một tập hợp các pixel, trong khi xử lý ảnh số ta thường thao tác xử lý ảnh dựa trên các pixel này, để lấy thông tin của một điểm ảnh ta dùng phương thức GetPixel, để thiết lập một điểm ảnh (pixel) cho ảnh ta sử dụng SetPixel. Ví dụ sau đây minh họa cho việc load một ảnh, đọc từng điểm ảnh của nó và thay thành điểm ảnh khác: private: Bitmap^ image1; void Button1_Click( System::Object^ /*sender*/, System::EventArgs^ /*e*/ ) { 114 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông
- Bài giảng Kỹ thuật lập trình – Ngành Truyền thông đa phương tiện try { // Đọc ảnh từ máy tính image1 = gcnew Bitmap( "C:\\Documents and Settings\\All Users\\" "Documents\\My Music\\music.bmp",true ); int x; int y; // Duyệt toàn bộ điểm ảnh for ( x = 0; x Width; x++ ) { for ( y = 0; y Height; y++ ) { Color pixelColor = image1->GetPixel( x, y ); Color newColor = Color::FromArgb( pixelColor.R, 0, 0 ); image1->SetPixel( x, y, newColor ); } } // Hiển thị ảnh lên picturebox PictureBox1->Image = image1; } catch ( ArgumentException^ ) { MessageBox::Show( "There was an error." "Check the path to the image file." ); } } 115 Bộ môn Truyền thông đa phương tiện – Trường Đại học Công nghệ thông tin và truyền thông