BỘ NHỚ ĐỘNG TRONG C++ </span>
(được viết bởi batanlp) <a href=\'http://www.diendantinhoc.net/tute/laptrinh/c/dynmem-batanlp/\' target=\'_blank\'><span style=\'color:red\'>nguồn</a> Trong bài viết này, tôi sẽ giới thiệu với các bạn về cách lập trình với con trỏ (pointer) trong việc cấp phát bộ nhớ động (dynamic memory alocation) bằng ngôn ngữ C++. Đối với các bạn đã có kinh nghiệm lập trình với C++ thì bài này đối với các bạn chỉ là "a-bờ-cờ" mà thôi. Nhưng với các bạn mới học C++ thì có lẽ là bổ ích. Nếu bạn mới học lập trình và làm quen với cấu trúc dữ liệu thì một trong số những cấu trúc dữ liệu đầu tiên mà bạn "rớ" tới là Stack (ngăn xếp) và Queue (hàng đợi). Bạn có thể dùng 1 mảng (array) để thiết kế Stack và Queue. Dùng mảng thì đơn giản, nhưng bạn sẽ gặp một số bất lợi như sau: Lãng phí bộ nhớ: giả sử bạn khai báo int array_entry[100] thì bạn sẽ có 1 vùng nhớ cho 100 phần tử, nhưng nếu chương trình của bạn chỉ thường xuyên dùng có 10 phần tử, và 1 vài lần là dùng đến 100 phần tử thì tức là bạn đã phí phạm 90 phần tử. Thiếu bộ nhớ: vì tiết kiệm, bạn chỉ khai báo int array_entry[10], nhưng nếu bạn cần dùng đến 15 phần tử thì...overflow ngay. Chưa hết, array cần một vùng nhớ liên tục, giả sử máy bạn vẫn còn nhiều bộ nhớ trống, nhưng không có vùng nhớ trống liên tục nào đủ lớn cho mảng của bạn. Thế là vẫn...thiếu bộ nhớ. Và cuối cùng, người ta khi thấy bạn viết như vậy thì coi bạn là dân amateur, buồn nhỉ? L Nhưng không sao, bài viết này sẽ giúp bạn vượt qua các trở ngại đó. Bạn sẽ biết cách ứng dụng con trỏ để tạo thành các cấu trúc dữ liệu kiên kết (linked structure) để tạo thành các linked stack hoặc linked queue. Bạn sẽ biết được cách toàn quyền cấp phát bộ nhớ khi có nhu cầu sử dụng; và khi không dùng nữa thì ta xoá nó đi, nhường memory cho các chương trình khác. Ghi chú: xem như là bạn đã có học và biết qua sơ sơ về C++ rồi, nhứng đoạn code trong bài viết này là C++ chứ không phải là C. Ứng dụng con trỏ, ta có thể tạo ra một danh sách liên kết (mảng liên kết - linked list) như sau: Phần đánh dấu màu hồng (và nút tròn đầu tiên) là các con trỏ, có nhiệm vụ link đến phần tử tiếp theo trong danh sách. Nhờ có các link này mà khi đang ở phần tử thứ nhất, bạn sẽ có manh mối để lần đến phần tử thứ hai, rồi phần tử thứ ba... Một phần tử của danh sách có thể được biểu diễn qua cấu trúc như sau (1 phần tử ta gọi là 1 Node): Code:
struct Node { Và ta có các hàm khởi tạo cho nó như sau: Code:
Node::Node() Đoạn code trong ví dụ sẽ tạo ra một danh sách liên kết như trong hình trên (không tin thì bạn...thử xem là biết liền J). Địa chỉ bộ nhớ của các node thì hoàn toàn ngẫu nhiên và không liên tục vì nó là dynamic memory allocation mà. Thế là đã Ok cho việc tạo một cấu trúc liên kết. Giờ ta bắt tay vào xây dựng Linked Stack và Linked Queue. Tôi sẽ trình bày phần Linked Stack thôi, phần Linked Queue thì các bạn hãy phát triển thêm nhé. Cũng hoàn toàn tương tự thôi. Ta khai báo Stack như sau: Code:
enum Error_code {underflow, success, overflow}; Code:
Stack_entry Stack::push(const Stack_entry &item) |
Các bài viết sẽ tập trung giới thiệu lập trình C/C++ trên nền DOS, do đó các bạn cần trang bị 1 bộ editor và biên dịch vd như Turbor C++ hoặc Borland C++ 7.0.
[Only registered and activated users can see links. Click Here To Register...] Bài 1: CẤU TRÚC MỘT CHƯƠNG TRÌNH C/C++</span> <span style=\'color:purple\'>1. Hàm main: Có lẽ một trong những cách tốt nhất để bắt đầu học một ngôn ngữ lập trình là bằng một chương trình. Vậy đây là chương trình đầu tiên của chúng ta : Code:
// my first program in C++ Code:
// my first program in C++ Code:
Hello World! Code:
// my first program in C++ Code:
#include <iostream.h> Code:
int main () Theo sau main là một cặp ngoặc đơn bởi vì nó là một hàm. Trong C++, tất cả các hàm mà sau đó là một cặp ngoặc đơn () thì có nghĩa là nó có thể có hoặc không có tham số (không bắt buộc). Nội dung của hàm main tiếp ngay sau phần khai báo chính thức được bao trong các ngoặc nhọn ( { } ) như trong ví dụ của chúng ta Code:
cout << "Hello World"; Lưu ý: lệnh cout được khai báo trong iostream.h dùng cho C++, bạn có thể dùng 1 hàm tương tự với C chuẩn là hàm printf được khai báo trong stdio.h Chú ý rằng mỗi dòng kết thúc bằng dấu chấm phẩy ( ; ). Kí tự này được dùng để kết thúc một lệnh và bắt buộc phải có sau mỗi lệnh trong chương trình C++ của bạn (một trong những lỗi phổ biến nhất của những lập trình viên C++ là quên mất dấu chấm phẩy). Code:
return 0; Chương trình được cấu trúc thành những dòng khác nhau để nó trở nên dễ đọc hơn nhưng hoàn toàn không phải bắt buộc phải làm vậy. Ví dụ, thay vì viết Code:
int main () Code:
int main () { cout << " Hello World "; return 0; } 2. Các chú thích: Các chú thích được các lập trình viên sử dụng để ghi chú hay mô tả trong các phần của chương trình. Trong C++ có hai cách để chú thích: Code:
// Chú thích theo dòng Code:
/* my second program in C++ Code:
Hello World! I'm a C++ program |
Bài 2: KIỂU DỮ LIỆU, BIẾN VÀ HẰNG SỐ</span>
<a href=\'http://www.thuvientinhoc.com/forums/lofiversion/index.php/t1153.html\' target=\'_blank\'>nguồn</a> <span style=\'color:purple\'>1. Một số kiểu dữ liệu thông dụng Khi lập trình, chúng ta lưu trữ các biến trong bộ nhớ của máy tính nhưng máy tính phải biết chúng ta muốn lưu trữ gì trong chúng vì các kiểu dữ liệu khác nhau sẽ cần lượng bộ nhớ khác nhau. Đơn vị dữ liệu nhỏ nhất lưu trữ trong máy tính là bit. Bộ nhớ của máy tính chúng ta được tổ chức thành các byte có kích thước bằng 8 bit. Một byte có thể dùng để lưu trữ một loại dữ liệu nhỏ như là kiểu số nguyên từ 0 đến 255 hay một kí tự. Nhưng máy tính có thể xử lý các kiểu dữ liệu phức tạp hơn bằng cách gộp nhiều byte lại với nhau, như số nguyên dài hay số thập phân. Tiếp theo bạn sẽ có một danh sách các kiểu dữ liệu cơ bản trong C/C++ cũng như miền giá trị mà chúng có thể biểu diễn. Các kiểu dữ liệu sẽ được bố trí trên từng dòng lần lượt là tên kiểu, chiều dài (tính theo byte), mô tả và miền giá trị: Tên Số byte Mô tả Miền giá trị Như sau: - Kiểu char Chiều dài: 1 byte Mô tả: Kí tự hay kiểu số nguyên 8-bit Miền giá trị: + có dấu (char): -128 - 127 + không dấu (unsigned char): 0 - 255 - Kiểu short Chiều dài: 2 bytes Mô tả: kiểu số nguyên 16-bit Miền giá trị: + có dấu (short): -32763 - 32762 + không dấu (unsigned short): 0 - 65535 - Kiểu long Chiều dài: 4 bytes Mô tả: kiểu số nguyên 32-bit Miền giá trị: + có dấu (long):-2147483648 - 2147483647 + không dấu (unsigned long): 0 - 4294967295 - Kiểu int Chiều dài: Độ dài của nó phụ thuộc vào hệ thống, như trong MS-DOS nó là 16-bit (2 bytes), trên Windows 9x/2000/NT là 32 bit (4 bytes)... Mô tả: Xem short, long - Kiểu float Chiều dài: 4 bytes Mô tả: Dạng dấu phẩy động Miền giá trị: 3.4e + / - 38 (7 digits) - Kiểu double Chiều dài: 8 bytes Mô tả: Dạng dấu phẩy động với độ chính xác gấp đôi Miền giá trị: 1.7e + / - 308 (15 digits) - Kiểu long double Chiều dài: 10 bytes Mô tả: Dạng dấu phẩy động với độ chính xác hơn nữa Miền giá trị: 1.2e + / - 4932 (19 digits) - Kiểu bool Chiều dài: 1 bytes Mô tả: Giá trị logic. Nó mới được thêm vào chuẩn ANSI-C++. Bởi vậy không phải tất cả các trình dịch đều hỗ trợ nó. Miền giá trị: true hoặc false 2. Biến (Variable) Biến là một đơn vị dữ liệu của chương trình, biến được xác định bởi định danh biến, hay đơn giản gọi là tên biến. Một tên biến hợp lệ là một chuỗi gồm các chữ cái, chữ số hoặc kí tự gạch dưới. Chiều dài của một tên là không giới hạn. Kí tự trống, các kí tự đánh dấu đều không thể có mặt trong một tên. Chỉ có chữ cái, chữ số và kí tự gạch dưới là được cho phép. Thêm vào đó, một tên biến luôn phải bắt đầu bằng một chữ cái. Chúng cũng có thể bắt đầu bằng kí tự gạch dưới ( _ ) nhưng kí tự này thường được dành cho các liên kết bên ngoài (external link) hoặc giữa các tên hàm. Không bao giờ chúng bắt đầu bằng một chữ số. Một luật nữa mà bạn phải quan tâm đến khi tạo ra các tên của riêng mình là chúng không được trùng với bất kì từ khoá nào của ngôn ngữ hay của trình biên dịch, ví dụ các tên sau đây luôn luôn được coi là từ khoá theo chuẩn ANSI-C++ và do vậy chúng không thể được dùng để đặt tên Code:
asm, car, bool, break, marry, catch, to char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, extern, false, float, for, friend, goto, if, inline, int, long, mutable, namespace, new, operator, private, protected, public, to register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t Code:
and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq Chú ý: Ngôn ngữ C/C++ là "case sensitive" có nghĩa là phân biệt chữ hoa chữ thường. Ví dụ một biến có tên RESULT khác với result cũng như Result. 3. Sử dụng biến trong chương trình 3.1. Khai báo biến (Declare) Để có thể sử dụng một biến trong C/C++, đầu tiên chúng ta phải khai báo nó, ghi rõ nó là kiểu dữ liệu nào. Chúng ta chỉ cần viết tên kiểu (như int, short, float...) tiếp theo sau đó là một tên biến hợp lệ. Ví dụ: Code:
int a; //khai báo biến kiểu số nguyên integer Nếu bạn muốn khai báo một vài biến có cùng một kiểu và bạn muốn tiết kiệm công sức viết bạn có thể khai báo chúng trên một dòng, ngăn cách các tên bằng dấu phẩy. Ví dụ: Code:
int a, b, c; Code:
int a; Code:
unsigned short nNumberOfSons; Nếu ta không chỉ rõ signed hoặc unsigned nó sẽ được coi là có dấu, vì vậy trong khai báo thứ hai chúng ta có thể viết : Code:
int nMyAccountBalance; Để có thể thấy rõ hơn việc khai báo trong chương trình, chúng ta sẽ xem xét một đoạn mã C++ ví dụ như sau: Code:
// thao tác tính toán với các biến Code:
4 3.2. Khởi tạo các biến (Initial) Khi khai báo một biến, giá trị của nó mặc nhiên là không xác định. Nhưng có thể bạn sẽ muốn nó mang một giá trị xác định khi được khai báo. Để làm điều đó, bạn chỉ cần viết dấu bằng và giá trị bạn muốn biến đó sẽ mang: kiểu tên_biến = giá_trị_khởi_tạo_ban_đầu; Ví dụ, nếu chúng ta muốn khai báo một biến int là a chứa giá trị 0 ngay từ khi khởi tạo, chúng ta sẽ viết : Code:
int a = 0; Code:
int a (0); Lưu ý: một biến khi được khởi tạo ta vẫn có thể gán cho nó 1 giá trị khác trong quá trình chương trình thực thi và giá trị đó sẽ hợp lệ trong phạm vi hoạt động của biến đó (xem phần sau) 3.3. Phạm vi hoạt động của biến (Scope) Tất cả các biến mà chúng ta sẽ sử dụng đều phải được khai báo trước. Một điểm khác biết giữa C và C++ là trong C++ chúng ta có thể khai báo biến ở bất kì nơi nào trong chương trình, thậm chí là ngay ở giữa các lệnh thực hiện chứ không chỉ là ở đầu khối lệnh như ở trong C. Mặc dù vậy chúng ta vẫn nên theo cách của ngôn ngữ C khi khai báo các biến bởi vì nó sẽ rất hữu dụng khi cần sửa chữa một chương trình có tất cả các phần khai báo được gộp lại với nhau. Bởi vậy, cách thông dụng nhất để khai báo biến là đặt nó trong phần bắt đầu của mỗi hàm (biến cục bộ - local) hay trực tiếp trong thân chương trình, ngoài tất cả các hàm (biến toàn cục - global). Global variables (biến toàn cục) có thể được sử dụng ở bất kì đâu trong chương trình, ngay sau khi nó được khai báo và bắt buộc phải đặt ở trên cùng ngoài tất cả các hàm hoặc đặt ở file header .h Local variables (biến cục bộ) có tầm hoạt động bị giới hạn trong phần mã mà nó được khai báo - thường là trong dấu { và } gần nhất. Nếu chúng được khai báo ở đầu một hàm (như hàm main), tầm hoạt động sẽ là toàn bộ hàm main. Điều đó có nghĩa là trong ví dụ trên, các biến được khai báo trong hàm main() chỉ có thể được dùng trong hàm đó, không được dùng ở bất kì đâu khác, tức là 1 biến được khai báo trong hàm A thì ko thể sử dụng nó trong hàm B nằm ngoài hàm A. Bên cạnh các biến toàn cục và cục bộ, còn có các biến ngoài (external). Các biến này không những được dùng trong một file mã nguồn mà còn trong tất cả các file được liên kết trong chương trình. Trong C++ tầm hoạt động của một biến chính là khối lệnh mà nó được khai báo (một khối lệnh là một tập hợp các lệnh được gộp lại trong một bằng các ngoặc nhọn { } ). Nếu nó được khai báo trong một hàm tầm hoạt động sẽ là hàm đó, còn nếu được khai báo trong vòng lặp thì tầm hoạt động sẽ chỉ là vòng lặp đó.... Hãy xem ví dụ sau và tìm hiểu cách hoạt động của các biến: Code:
int nGlobal; //biến toàn cục có thể đựơc sử dụng trong cả hàm A và B 3.1. Giới thiệu các hằng số Một hằng số là bất kì một biểu thức nào mang một giá trị cố định, ví dụ như các số nguyên sau: Code:
1776 Thêm vào những số ở hệ cơ số 10 (thập phân) ( cái mà tất cả chúng ta đều đã biết) C++ còn cho phép sử dụng các hằng số cơ số 8 (bát phân) và 16 (thập lục phân). Để biểu diễn một số hệ cơ số 8 chúng ta đặt trước nó kí tự 0, để biễu diễn số ở hệ cơ số 16 chúng ta đặt trước nó hai kí tự 0x. Ví dụ: Code:
75 // Cơ số 10 Chúng biểu diễn các số với phần thập phân và/hoặc số mũ. Chúng có thể bao gồm phần thập phân, kí tự e (biểu diễn 10 mũ...). Code:
3.14159 // 3.14159 Trong C++ còn tồn tại các hằng không phải kiểu số như kiểu kí tự và chuỗi. Kiểu kí tự được bao quanh bởi 2 dấu móc đơn, kiểu chuổi bao quanh bởi cặp móc kép: Code:
'z' Khi viết các kí tự đơn hay các xâu kí tự cần phải đặt chúng trong các dấu nháy để phân biệt với các tên biến hay các từ khoá. Chú ý: Code:
x Các kí tự đơn và các xâu kí tự có một tính chất riêng biệt là các mã điều khiển. Chúng là những kí tự đặc biệt mà không thể được viết ở bất kì đâu khác trong chương trình như là mã xuống dòng (\n) hay tab (\t). Tất cả đều bắt đầu bằng dấu xổ ngược (\). Sau đây là danh sách các mã điều khiển và ý nghĩa của nó: Code:
\n Code:
'\n' //sẽ chèn thêm kí hiệu ngắt dòng Các hằng chuỗi kí tự có thể được viết trên nhiều dòng nếu mỗi dòng được kết thúc bằng một dấu sổ ngược (\), cách này có ích khi ta có 1 chuỗi quá dài khó quan sát khi viết chương trình: Code:
"string expressed in \ Code:
"we form" "a unique" "string" "of characters" Bạn có thể định nghĩa các hằng với tên mà bạn muốn để có thể sử dụng thường xuyên mà không mất tài nguyên cho các biến bằng cách sử dụng chỉ thị #define. Đây là dạng của nó: #define tên_hằng giá_trịVí dụ: Code:
#define PI 3.14159265 Code:
circle = 2 * PI * r; Chỉ thị #define không phải là một lệnh thực thi, nó là chỉ thị tiền xử lý (pre-processor), đó là lý do trình dịch coi cả dòng là một chỉ thị và dòng đó không cần kết thúc bằng dấu chấm phẩy. Nếu bạn thêm dấu chấm phẩy vào cuối dòng, nó sẽ được coi là một phần của giá trị định nghĩa hằng. 3.3. Khai báo các hằng (const) Với tiền tố const bạn có thể khai báo các hằng với một kiểu xác định như là bạn làm với một biến Code:
const int width = 100; |
Trước tiên bạn cần cài bộ Visual Studio 6 (hoặc bộ .NET)- đây sẽ là nơi bạn trực tiếp soạn thảo mã nguồn, tạo ứng dụng và thư viện MSDN - là bộ thư viện hỗ trợ lập trình không thể thiếu của các lập trình viên. Bộ VS6 bạn chỉ cần cài đặt đĩa 1, còn bộ MSDN bạn nên cài đầy đủ 3 CD.
Mục tiêu của toàn bộ bài học là để bao quát một số kĩ thuật đi từ cơ bản đến nâng cao, từ đó tạo ra kết quả cuối cùng là một chương trình nhỏ hoạt động ngầm như 1 spy bên dưới hệ thống Windows và theo dõi hoạt động của các chương trình khác, bao gồm bắt phím đánh vào, bắt thao tác chuột và chụp hình. BÀI 1: TẠO ỨNG DỤNG DẠNG DIALOG ĐƠN GIẢN</span> <a href=\'http://www.thuvientinhoc.com/forums/lofiversion/index.php/t115.html\' target=\'_blank\'>nguồn</a> <span style=\'color:purple\'> 1. Tạo Ứng Dụng Nhanh với MFC AppWizard Sau khi cài đặt xong VS6, bạn vào menu Start/Programs để chạy ứng dụng Microsoft Visual C++ 6.0, kết quả tương tự như hình sau: <img src=\'http://www.whatvn.com/images/vc/sample1/1.gif\' border=\'0\' alt=\'user posted image\' /> (Lưu ý: để tiết kiệm hình ảnh tôi đã resize kích thước hình nhỏ lại) Ta sẽ bắt đầu tạo 1 ứng dụng dialog đơn giản với Application Wizard qua 4 bước. Bạn chọn menu File/New (hoặc nhấn Ctrl-N) để mở cửa sổ New Project. VC++ 6 cho phép bạn tạo rất nhiều kiểu ứng dụng, từ database, ATL COM, web, dll, đến các ứng dụng Win 32 Console (chạy dạng cửa sổ console), ở đây ta sẽ chọn MFC AppWizard (exe). MFC là một bộ thư viện lập trình hướng đối tượng mà VC++ hổ trợ nhằm giúp tạo cho lập trình viên khả năng lập trình thân thiện, dễ sử dụng. Loại bỏ bớt những dài dòng phức tạp khi phải viết toàn bộ mã nguồn của một chương trình Windows, MFC cung cấp cung cấp khả năng tự động sinh ra bộ khung (framework) cho ứng dụng của bạn thông qua một số lớp (class) có tính kế thừa. Dần dần các bạn sẽ hiểu và thấy MFC dùng AppWizard lợi ích như thế nào. Trở lại với ví dụ của chúng ta. Trong cửa sổ New Project, bạn tiếp tục nhập vào Tên Đồ án (Project name), ở đây ta nhập vào "sample1", ta để ý thấy trong hộp Platforms, VC++ chỉ hỗ trợ ứng dụng chạy trên nền Win 32, ta tiếp tục nhấn OK. Xem hình sau: <img src=\'http://www.whatvn.com/images/vc/sample1/2.gif\' border=\'0\' alt=\'user posted image\' /> Ở bước 1 của MFC AppWizard, có 3 kiểu ứng dụng trình Wizard hỗ trợ đó là: Single document (SDI-Single Document Interface, một ứng dụng chỉ mở một cửa sổ con cho 1 tài liệu. Notepad, Wordpad là một kiểu SDI - trong một cửa sổ Notepad bạn ko thể có 2 cửa sổ con), Multiple documents (MDI - Multiple Documents Interface - MS Word là MDI, cùng một thời điểm bạn có thể mở cùng lúc nhiều tài liệu), Dialog based (Ứng dụng dạng cửa sổ đơn dialog). Ta tiếp chọn Dialog based và nhấn Next. <img src=\'http://www.whatvn.com/images/vc/sample1/3.gif\' border=\'0\' alt=\'user posted image\' /> Tiếp tục bước 2, MFC AppWizard cung cấp mộ số thuộc tính cho bạn chọn cho ứng dụng dạng dialog. Thuộc tính About box nếu chọn sẽ cung cấp cho bạn 1 cửa sổ con About dạng dialog dành cho bạn khi muốn cung cấp một số thông tin về tác giả, ngày tháng tạo ứng dụng, sau này khi ứng dụng hoàn thành bạn có thể truy xuất đến nó thông qua System Menu (icon góc trên bên trái ứng dụng); Context-sensitive help sẽ tạo kèm theo ứng dụng một bộ help đơn giản; 3D controls hỗ trợ cách nhìn 3D có bóng cho các control, bạn check và uncheck vào nó và xem hình ví dụ bên cạnh; ActiveX controls cung cấp khả năng sử dụng các ActiveX control trong ứng dụng của bạn. Xem hình bên dưới, bạn tiếp tục nhấn Next. <img src=\'http://www.whatvn.com/images/vc/sample1/4.gif\' border=\'0\' alt=\'user posted image\' /> Ở bước 3, có một số thông tin khác như generate source comments, tức là tự động sinh chú thích cho các đoạn mã, giúp bạn dễ theo dõi hơn; use MFC library cho bạn chọn cách thức sử dụng các thư viện của MFC, tôi sẽ trở lại với vấn đề này sau. Xem hình bên dưới, bạn tiếp tục nhấn Next. <img src=\'http://www.whatvn.com/images/vc/sample1/5.gif\' border=\'0\' alt=\'user posted image\' /> Bước cuối cùng của MFC AppWizard, trình Wizard cho phép bạn chọn tên cho các lớp quan trọng đã được sinh tự động (class) cho ứng dụng của bạn. Ở đây ta giữ nguyên và chọn Finish. <img src=\'http://www.whatvn.com/images/vc/sample1/6.gif\' border=\'0\' alt=\'user posted image\' /> Nếu thực hiện nhanh, quá trình này chỉ mất khoảng vài giây để tạo ngay 1 ứng dụng đơn giản nhất dạng dialog. Bạn xem hình bên dưới: <img src=\'http://www.whatvn.com/images/vc/sample1/7.gif\' border=\'0\' alt=\'user posted image\' /> Cửa sổ VC++ 6 bao gồm hệ thống thực đơn, các thanh công cụ, cửa sổ Workspace bên trái, cửa sổ soạn thảo mã và thiết kế resource bên phải, cửa sổ trạng thái (status) dưới cùng. Trở lại với các loại ứng dụng MFC. Trình AppWizard sẽ tự động phát sinh một số lớp chính tạo nên bộ khung cho ứng dụng loại đó. Đối với SDI, sẽ bao gồm lớp Application (cấp cao nhất), kế đến là lớp MainFrame, lớp View và Document. Tên các lớp là kết hợp của project name và kiểu. Vd nếu ta đặt tên project là "sample1", ta sẽ thấy có các lớp CSample1App, CMainFrame, CSample1View, CSample1Doc. Đối với ứng dụng MDI sẽ gồm các lớp giống như của SDI và có thể lớp ChildFrame tên CChildFrm đại diện cho 1 cửa sổ con trong ứng dụng. Đối với dạng ứng dụng dialog, bao gồm CSample1App, CSample1Dlg (đại diện cho dialog chính), CAboutDlg (đại diện cho dialog About). Lớp Application sẽ là nơi nhận và phân phối các message từ hệ thống đến cho ứng dụng, kế đến là lớp MainFrame, ChildFrame, View và Document. Ứng dụng SDI chỉ cung cấp 1 document (vd: bạn chỉ mở được 1 file văn bản) và muốn thể hiện thông tin của document đó lên màn hình ta phải thông qua 1 view. Lớp View sẽ là nơi ta thực hiện các thao tác vẽ, xuất thông tin hay thể hiện văn bản lên màn hình. Mở rộng hơn, kiểu MDI cho phép mở cùng lúc nhiều document, mỗi document đại diện bởi 1 view. Ở kiểu dialog, các thao tác giao diện tập trung ở lớp dialog, không có lớp view. |
cam on legiang nha, nhung ma sao hom nay minh khong go dau duoc vay troi, po tay luọn MA legiang ne, chi hoc lap trinh da 2 nam roi nhung chang ranh duoc thu gi ca vi hoc tran lan het Pascal, DepC roi BC, gio lai phai hoc ca VC,hic hic met muon chet may ong thay nay bat tu hoc, moi mon viet 1 ngon ngu khac nhau riet roi lon tum lum, co cach nao do bi lon khong troi!!!!!!!!!!!
|
Vao dien dan da duoc 1 nam ruoi roi ma con "tap tanh viet lach" xau ho qua di vi khong chiu post bai, hinh nhu minh lam bieng qua thi phai!...............
|
BÀI 2: THU NHỎ ỨNG DỤNG XUỐNG KHAY HỆ THỐNG SYSTEM TRAY</span>
<a href=\'http://www.thuvientinhoc.com/forums/lofiversion/index.php/t1091.html\' target=\'_blank\'><span style=\'color:red\'>My Webpage</a> Chúng ta trở lại với ứng dụng dạng hộp thoại dialog đơn giản ở bài 1. Bài 2 này chúng ta sẽ bắt đầu đề cập 1 số kĩ thuật phức tạp hơn của việc lập trình trên môi trường Windows, đó là tạo 1 ứng dụng có thể thu nhỏ dạng icon ở system tray và tạo menu popup đáp ứng khi người dùng nhấn phải chuột lên icon ở system tray; đồng thời cũng đề cập đến kĩ năng viết code kết hợp với MFC của VC++ 6.0. 1. Thu nhỏ ứng dụng xuống system tray Ở ví dụ bài 1 chúng ta đã có 1 nút bấm "Hiện Messagebox", ta sẽ thêm 1 nút bấm khác để phục vụ khi người dùng nhấn vào nó để thu nhỏ ứng dụng xuống system tray. Bạn hãy làm tương tự như ở bài 1, ở khung WorkSpace bên trái, chọn tab Resource, sau đó chọn phần Dialog và nhấp đúp vào ID có tên IDD_SAMPLE1_DIALOG để vào chế độ soạn resource cho dialog ứng dụng của chúng ta. Sau đó bạn chọn hình nút bấm trên thanh công cụ bên phải và nhấp chuột vào giữa hình dialog, bạn nhấp chuột phải lên button vừa tạo và chọn Properties, kế tiếp chọn tab General, gõ vào ô Caption nội dung sau: "Minimize on tray". Lưu ý trước khi tạo button này, bạn dùng chuột kéo button trước đó (Hien Messagebox) sang trái để chúng ko đè lên nhau. Kết quả bạn có thể thấy như sau: <img src=\'http://www.whatvn.com/images/vc/sample1/31.gif\' border=\'0\' alt=\'user posted image\' /> Tương tự bài 1, ta tạo event handler cho sự kiện nhấp chuột lên button, bạn nhấp đúp chuột lên button vừa tạo để mở hộp thoại tạo mới hàm xử lý, gõ vào tên hàm xử lý sự kiện là OnMinimize và nhấn OK. Như vậy một hàm mới tên là OnMinimize() sẽ được tạo trong code của bạn nhưng chưa có lệnh xử lý, chúng ta sẽ thêm mã lệnh sau. Code:
Void CSample1Dlg::OnMinimize() Để phục vụ cho việc thu nhỏ, ta dùng hàm Shell API có tên Shell_NotifyIcon. API viết tắt của Application Programming Interface, hay gọi là Giao diện lập trình ứng dụng trên Windows. Nói một cách đơn giản API là tập hợp các hàm, các cấu trúc dữ liệu, thư viện mà hệ thống hỗ trợ cho các lập trình viên tạo nên các ứng dụng. Các API thường được đặt trong các tập tin thư viện như .dll nằm trong thư mục cài đặt Windows. Hàm Shell_NotifyIcon làm nhiệm vụ gửi thông điệp yêu cầu (message) có chức năng cụ thể nào đó tới system tray. Ví dụ yêu cầu tạo tray icon, xóa tray icon... Khai báo hàm như sau: Code:
BOOL Shell_NotifyIcon( Trong đó, dwMessage chỉ định kiểu yêu cầu. Ở đây ta quan tâm đến 2 loại message là: - NIM_ADD : Tạo 1 icon ở system tray hay còn gọi là khu vực trạng thái taskbar - NIM_DELETE : Xóa 1 icon khỏi system tray lpdata là 1 con trỏ đến 1 cấu trúc dữ liệu chứa các thông tin cần thiết cho icon hoạt động ở system tray, như hình icon, mã điều khiển, thông điệp hệ thống sẽ nhận được khi user kích hoạt vào icon... Ta xem cấu trúc NOTIFYICONDATA và chú thích sau dấu // Code:
typedef struct _NOTIFYICONDATA { Như vậy yêu cầu để thực hiện hàm Shell_NotifyIcon là ta điền đầy đủ các tham số và gọi hàm, ta sẽ đi từng tham số một. Với tham số đầu tiên, vì ta muốn tạo ứng dụng dạng trayicon, ta sẽ dùng NIM_ADD. Cấu trúc ở tham số thứ hai phức tạp hơn, chúng ta cần chuẩn bị 1 số thông tin cho cấu trúc này. Trước tiên ta cần vẽ 1 icon dùng để hiện ở system tray. Đây là dấu hiệu nhận biết ứng dụng đang ở system tray. Bạn trở lại Resource tab, chọn vào phần Icon, nhấn chuột phải và chọn Insert Icon, Resource Editor sẽ tự tạo cho bạn 1 icon có ID là IDI_ICON1, bạn nhấn chuột phải lên ID chọn Properties để thay đổi ID thành IDI_TRAY1. Sau đó ở phần vẽ icon bên phải, bạn dùng thanh công cụ vẽ 3 hình tròn như hình sau: <img src=\'http://www.whatvn.com/images/vc/sample1/32.gif\' border=\'0\' alt=\'user posted image\' /> Sau đó bạn nhấn nút Save để lưu lại icon mình vừa tạo. Đến đây ta tiếp tục với 1 vấn đề khác, đó là khi đã thu nhỏ dạng trayicon, icon này cần đáp ứng khi có sự kiện nhấp chuột lên nó. Tham số thứ 2 lpdata của hàm Shell_NotifyIcon yêu cầu truyền vào 1 cấu trúc NOTIFYICONDATA. Cấu trúc này cho phép ta định nghĩa thêm 1 windows message kiểu người dùng đặt vào 1 thuộc tính tên là uCallbackMessage. Như vậy ta sẽ định nghĩa 1 message như sau: Code:
#define WM_NOTIFYOFINCONONTRAY (WM_USER+1) //WM_USER và đặt dòng #define này ở đầu file .cpp Ta cũng cần chỉ định window handle của cửa sổ cần thu nhỏ, ta sẽ dùng biến m_hWnd là thuộc tính có sẵn của tất cả các ứng dụng dạng window dùng MFC. Kết quả ta sẽ khai báo cấu trúc như sau: Code:
NOTIFYICONDATA tnid; - NIF_MESSAGE: cho phép dùng window message với thuộc tính uCallbackMessage - NIF_ICON: cho phép chỉ icon vào thuộc tính hIcon - NIF_TIP: cho phép dùng tooltip với thuộc tính szTip. Ta dùng hàm _tcscpy để copy chuỗi vào biến szTip. Để biết thêm chi tiết các thuộc tính trên, bạn tham khảo MSDN. Như vậy, sau khi thiết lập các thông tin cần thiết cho cấu trúc NOTIFYICONDATA, ta chỉ việc gọi hàm Shell_NotifyIcon với tham số NIM_ADD để thu nhỏ xuống systray: Code:
Shell_NotifyIcon(NIM_ADD, &tnid); tnid với dấu & đằng trước. Khi ứng dụng đã xuất hiện ở system tray, ta ko cần hiện dạng dialog trên màn hình, do đó ta gọi hàm ShowWindow để ẩn ứng dụng (nếu ko ẩn thì ta sẽ có cả ứng dụng dialog hiện hành và trayicon). Code:
ShowWindow(SW_HIDE); Hãy xem hàm đầy đủ như sau kết hợp cả hai tính năng thêm và xóa icon ở system tray, với tham số truyền vào kiểu BOOLEAN. Code:
//Hàm thu nhỏ/xóa TrayIcon Như vậy ta đã thực hiện xong phần thu nhỏ và xóa trayicon. Phần kế tiếp ta sẽ viết hàm nhận thông điệp khi người dùng nhấp chuột phải lên trayicon và từ đó cho hiện menu lựa chọn. 2. Tạo menu popup cho biểu tượng system tray Như đã đề cập ở phần trên, ta đã định nghĩa 1 user defined message có tên là WM_NOTIFYOFINCONONTRAY. Khi người dùng thực hiện các thao tác nhấn phím, rê chuột lên trayicon hoặc nhấp chuột lên nó, Windows sẽ gửi đến ứng dụng chúng ta 1 message chính là message được gán vào thuộc tính tnid.uCallbackMessage ở trên. Vì đây là message tự định nghĩa nên ta phải tự viết hàm xử lý biến cố cho nó, ta sẽ phải tuân theo chuẩn của Windows khi viết hàm này. Với MFC, hàm xử lý message sẽ có dạng sau: Code:
afx_msg void MessageProc(WPARAM wParam, LPARAM lParam); Code:
afx_msg void OnNotifyOfIconOnTray(WPARAM wParam, LPARAM lParam) Ở đây afx_msg là macro được MFC định sẵn chỉ định hàm xử lý thông điệp. Thông số WPARAM sẽ cho biết giá trị uID đã được gán trước trong cấu trúc NOTIFYICONDATA, LPARAM sẽ là giá trị cụ thể thông điệp hệ thống (nhấn phím nào, chuột trái, phải...) Trong cửa sổ WorkSpace, bạn chọn tab ClassView và nhấp đúp và tên class CSample1Dlg để mở file header của class. Sau đó bạn gõ thêm dòng định nghĩa hàm ở trên, kết quả như hình vẽ sau: <img src=\'http://www.whatvn.com/images/vc/sample1/33.gif\' border=\'0\' alt=\'user posted image\' /> Kế đến ta cần viết thêm mã để hàm OnNotifyOfIconOnTray có hiệu lực. Trên cửa sổ ClassView bạn nhấp đúp vào 1 hàm nào đó của class CSample1Dlg để mở cửa sổ code của class này (nằm trong file sample1Dlg.cpp). Tìm đến phần BEGIN_MESSAGE_MAP(CSample1Dlg, CDialog) và thêm dòng ON_MESSAGE( WM_NOTIFYOFINCONONTRAY, OnNotifyOfIconOnTray) như hình vẽ: <img src=\'http://www.whatvn.com/images/vc/sample1/34.gif\' border=\'0\' alt=\'user posted image\' /> Đến đây ta sẽ cần tạo 1 menu popup cho trayicon, bạn trở lại phần Resource tab, nhấn chuột phải lên mục Menu và chọn Insert Menu. Resource Editor sẽ tự động tạo cho bạn 1 menu có id là IDR_MENU1 và 1 menu item rỗng có viền lấm chấm sẽ được tạo ở phần editor bên phải, bạn nhấn chuột phải lên nó và chọn Properties như hình bên dưới: <img src=\'http://www.whatvn.com/images/vc/sample1/35.gif\' border=\'0\' alt=\'user posted image\' /> Trong hộp thoại Properties, bạn nhập vào ô Caption chuỗi "test" và nhấn Enter. Sau khi nhấn Enter trình editor tự động chuỗi bạn vừa nhập vào menuitem và tạo thêm 1 menuitem rỗng ngay bên dưới. Bạn làm tương tự để tạo thêm 2 item sổ xuống lần lượt là "&Show" và "&Exit". Kết quả như hình sau: <img src=\'http://www.whatvn.com/images/vc/sample1/36.gif\' border=\'0\' alt=\'user posted image\' /> Vì menuitem đầu tiên có caption là "Test" nên trình Resource Editor của VC++ sẽ tự tạo cho các item của nó những số ID duy nhất có phần bắt đầu dạng ID_TEST_Caption. Ví dụ như ID_TEST_SHOW, ID_TEST_EXIT. Tương tự như các nút bấm trên dialog ở trên, mỗi menuitem cần 1 hàm xử lý sự kiện cho nó khi người dùng chọn item đó trên menu. Bước này ta sẽ dùng trình ClassWizard của VC++. Bạn nhấn chuột phải lên menuitem có tên "Show" và chọn ClassWizard...từ menu sổ xuống. Một hộp thoại hiện ra hỏi bạn "Adding a class", ta chưa dùng chức năng này nên bạn chọn Cancel để bỏ qua. Trong hộp thoại MFC ClassWizard, ở listbox Object IDs, bạn chọn ID có tên ID_TEST_SHOW và ô bên phải có tên "Messages", bạn nhấp đúng vào mục COMMAND. Hộp thoại Add Member Function sẽ hiện ra, bạn nhập tên hàm xử lý là OnTestShow (thường thì tên hàm được chọn sẵn cho bạn), bạn nhấn OK. Bạn làm tương tự với ID_TEST_EXIT. Như hình sau: <img src=\'http://www.whatvn.com/images/vc/sample1/37.gif\' border=\'0\' alt=\'user posted image\' /> Sau khi tạo xong 2 hàm, ở phần Member functions bạn nhấp đúp vào hàm OnTestShow và sẽ được đưa trở lại cửa sổ code, ở hàm OnTestShow bạn nhập thêm dòng MinimizeOnTray(FALSE);, tham số FALSE truyền vào hàm MinimizeOnTray ta đã tạo ở trên sẽ dùng để xóa icon khỏi systemtray và hiện lại cửa sổ dialog (bạn xem lại hàm MinimizeOnTray ở trên). Tương tự với hàm OnTestExit, bạn thêm dòng OnOK();, đây là hàm ngầm định của ứng dụng dạng dialog dùng để kết thúc ứng dụng. Code:
void CSample1Dlg::OnTestShow() Code:
void CSample1Dlg::OnMinimize() Code:
void CSample1Dlg::OnNotifyOfIconOnTray(WPARAM wParam, LPARAM lParam) Ở đây ta chỉ cho hiện menu khi người dùng nhấp chuột phải lên trayicon nên bạn sẽ thấy lệnh if với điều kiện uMouseMsg == WM_RBUTTONUP, WM_RBUTTONUP là windows message có sẵn, bạn xem MSDN để biết thêm các message khác và với ID là IDI_TRAY1 như ta đã thiết lập khi gọi hàm Shell_NotifyIcon ở trên, ta sẽ cho hiện menu popup. Cách thức sử dụng 1 menu dạng popup như ta đã tạo bên trên, bạn dùng lớp MFC có tên CMenu với phương thức LoadMenu và tham số truyền vào là ID của menu đã tạo, ở đây là IDR_MENU1. Lưu ý đây là dạng menubar có 1 item "Test" và sổ xuống 1 popup, nên ta cần dùng hàm GetSubMenu để lấy đúng menu popup, tham số 0 chỉ item đầu tiên của menubar (lưu ý trong C/C++, PHP, Java... các phần tử trong 1 mảng, list bắt đầu từ 0), hàm này sẽ trả về 1 con trỏ đến menupop up, nên bạn cần khai báo thêm 1 biến con trỏ để lưu giữ menu đó. Code:
CMenu* pMenu = lMenu.GetSubMenu(0); Code:
BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL ); int x, int y chỉ định vị trí nhấp chuột, ta sẽ dùng hàm GetCursorPos để lấy vị trí này CWnd* pWnd chỉ định con trỏ đến ứng dụng sẽ nhận thông điệp xử lý chuột, ta dùng con trỏ định trước this. Đây là dạng con trỏ chỉ đến cửa sổ hiện tại LPCRECT lpRect = NULL chỉ định phạm vi hiệu lực của menu. Giá trị ngầm định của tham số này là NULL, chỉ định nếu người nhấp chuột ngoài vùng này thì menu tự động đóng lại. Lưu ý bạn cần thêm hàm this->SetFocus(); để chỉ định điểm nhập focus cho ứng dụng trayicon hỗ trợ thêm cho việc nếu người nhấp chuột ngoài vùng này thì menu tự động đóng lại. Để tiết kiệm thời gian, bạn copy phần code của hàm OnNotifyOfIconOnTray tôi đã tạo sẵn ở trên và dán vào cuối vùng code của CSample1Dlg. Đến đây là hoàn thành phần tạo ứng dụng có khả năng thu nhỏ xuống system tray. Bạn nhấn Ctrl-F5 để biên dịch và chạy ứng dụng, nhấn lên nút "Minimize on tray" để thu nhỏ và nhấp chuột phải lên trayicon để sử dụng menu. Toàn bộ project VC++6.0 tôi đã tạo sẵn các bạn có thể download tại đây: <a href=\'http://www.whatvn.com/data/sample1.zip\' target=\'_blank\'>http://www.whatvn.com/data/sample1.zip</a> |
Múi giờ GMT +7. Hiện tại là 08:17 AM. |
Website sử dụng phần mềm vBulletin phiên bản 3.6.8
do Công ty TNHH Jelsoft giữ bản quyền từ 2000 - 2024.
Hội CHS Lê Quý Đôn-Long An giữ bản quyền nội dung của website này