Biến tài nguyên
Chỉ thị #resource
có một dạng đặc biệt cho phép khai báo các tệp bên ngoài dưới dạng biến tài nguyên và truy cập chúng trong chương trình như các biến thông thường thuộc loại tương ứng. Định dạng khai báo là:
#resource "path_file_name" as resource_variable_type resource_variable_name
Dưới đây là một số ví dụ về khai báo:
#resource "data.bin" as int Data[] //array of int type with data from the file data.bin
#resource "rates.dat" as MqlRates Rates[] // array of MqlRates structures from the file rates.dat
#resource "data.txt" as string Message // line with the contents of the file data.txt
#resource "image.bmp" as bitmap Bitmap1[] // one-dimensional array with image pixels
// from file image.bmp
#resource "image.bmp" as bitmap Bitmap2[][] // two-dimensional array with the same image
2
3
4
5
6
Hãy đưa ra một số giải thích. Các biến tài nguyên là hằng số (chúng không thể được sửa đổi trong mã MQL5). Ví dụ, để chỉnh sửa hình ảnh trước khi hiển thị trên màn hình, bạn nên tạo bản sao của các biến mảng tài nguyên.
Đối với các tệp văn bản (tài nguyên kiểu string
), mã hóa được xác định tự động nhờ sự hiện diện của tiêu đề BOM. Nếu không có BOM, mã hóa được xác định dựa trên nội dung của tệp. Các mã hóa ANSI, UTF-8 và UTF-16 được hỗ trợ. Khi đọc dữ liệu từ tệp, tất cả chuỗi được chuyển đổi sang Unicode.
Việc sử dụng các biến chuỗi tài nguyên có thể đơn giản hóa đáng kể việc viết chương trình không chỉ dựa trên MQL5 thuần túy mà còn dựa trên các công nghệ bổ sung. Ví dụ, bạn có thể viết mã OpenCL (được hỗ trợ trong MQL5 như một phần mở rộng) trong một tệp riêng và sau đó bao gồm nó dưới dạng chuỗi trong tài nguyên của một chương trình MQL. Trong ví dụ Expert Advisor lớn, chúng ta đã sử dụng chuỗi tài nguyên để bao gồm các mẫu HTML.
Đối với hình ảnh, một kiểu bitmap
đặc biệt đã được giới thiệu; kiểu này có một số đặc điểm.
Kiểu bitmap
mô tả một điểm hoặc pixel trong hình ảnh và được biểu diễn bằng một số nguyên không dấu 4 byte (uint
). Pixel chứa 4 byte tương ứng với các thành phần màu trong định dạng ARGB hoặc XRGB (một chữ cái = một byte), trong đó R là đỏ, G là xanh lá, B là xanh dương, A là độ trong suốt (kênh alpha), X là byte bị bỏ qua (không có độ trong suốt). Độ trong suốt có thể được sử dụng cho các hiệu ứng khác nhau khi chồng hình ảnh lên biểu đồ và lên nhau.
Chúng ta sẽ nghiên cứu định nghĩa của định dạng ARGB và XRGB trong phần về tạo tài nguyên đồ họa động (xem ResourceCreate
). Ví dụ, với ARGB, số thập lục phân 0xFFFF0000 chỉ định một pixel hoàn toàn không trong suốt (byte cao nhất là 0xFF) màu đỏ (byte tiếp theo cũng là 0xFF), và các byte tiếp theo cho thành phần xanh lá và xanh dương là số không.
Điều quan trọng cần lưu ý là mã hóa màu pixel khác với biểu diễn byte của kiểu color. Hãy nhớ rằng giá trị của kiểu color
có thể được ghi dưới dạng thập lục phân như sau: 0x00BBGGRR, trong đó BB, GG, RR lần lượt là các thành phần xanh dương, xanh lá và đỏ (trong mỗi byte, giá trị 255 cho cường độ tối đa của thành phần). Với cách ghi tương tự của một pixel, có thứ tự byte ngược lại: 0xAARRGGBB. Độ trong suốt hoàn toàn đạt được khi byte cao (ở đây được ký hiệu là AA) là 0 và giá trị 255 là màu đặc. Hàm ColorToARGB có thể được sử dụng để chuyển đổi color
sang ARGB.
Các tệp BMP có thể có nhiều phương pháp mã hóa khác nhau (nếu bạn tạo hoặc chỉnh sửa chúng trong bất kỳ trình chỉnh sửa nào, hãy kiểm tra vấn đề này trong tài liệu của chương trình đó). Tài nguyên MQL5 không hỗ trợ tất cả các phương pháp mã hóa hiện có. Bạn có thể kiểm tra xem một tệp cụ thể có được hỗ trợ hay không bằng cách sử dụng hàm ResourceCreate
. Việc chỉ định một tệp định dạng BMP không được hỗ trợ trong chỉ thị sẽ dẫn đến lỗi biên dịch.
Khi tải một tệp với mã hóa màu 24-bit, tất cả các pixel của thành phần kênh alpha được đặt thành 255 (không trong suốt). Khi tải một tệp với mã hóa màu 32-bit không có kênh alpha, nó cũng ngụ ý không có độ trong suốt, tức là đối với tất cả các pixel hình ảnh, thành phần kênh alpha được đặt thành 255. Khi tải một tệp mã hóa màu 32-bit có kênh alpha, không có thao tác pixel nào diễn ra.
Hình ảnh có thể được mô tả bởi cả mảng một chiều và hai chiều. Điều này chỉ ảnh hưởng đến phương thức định địa chỉ, trong khi lượng bộ nhớ chiếm dụng sẽ giống nhau. Trong cả hai trường hợp, kích thước mảng được đặt tự động dựa trên dữ liệu từ tệp BMP. Kích thước của mảng một chiều sẽ bằng tích của chiều cao và chiều rộng của hình ảnh (height * width)
, và mảng hai chiều sẽ nhận các kích thước riêng [height][width]
: chỉ số đầu tiên là số dòng, chỉ số thứ hai là điểm trong dòng.
Chú ý! Khi khai báo một tài nguyên liên kết với một biến tài nguyên, cách duy nhất để truy cập tài nguyên là thông qua biến đó, và cách đọc tiêu chuẩn qua tên "::resource_name" (hoặc tổng quát hơn "path_file_name.ex5::resource_name") không còn hoạt động. Điều này cũng có nghĩa là các tài nguyên như vậy không thể được sử dụng như tài nguyên dùng chung từ các chương trình khác.
Hãy xem xét hai chỉ báo làm ví dụ; cả hai đều không có bộ đệm. Loại chương trình MQL này được chọn chỉ vì lý do tiện lợi bởi vì nó có thể được áp dụng lên biểu đồ mà không gây xung đột với các chỉ báo khác trong khi một Expert Advisor sẽ yêu cầu một biểu đồ không có Expert Advisor khác. Ngoài ra, chúng vẫn ở trên biểu đồ và có sẵn để thay đổi cài đặt sau đó, không giống như các script.
Chỉ báo BmpOwner.mq5
chứa mô tả của ba tài nguyên:
- Hình ảnh "search1.bmp" với chỉ thị
#resource
đơn giản, có thể truy cập từ các chương trình khác - Hình ảnh "search2.bmp" dưới dạng biến mảng tài nguyên kiểu
bitmap
, không thể truy cập từ bên ngoài - Tệp văn bản "message.txt" dưới dạng chuỗi tài nguyên để hiển thị cảnh báo cho người dùng
Cả hai hình ảnh không được sử dụng theo bất kỳ cách nào trong chỉ báo này. Dòng cảnh báo được yêu cầu trong hàm OnInit
để gọi Alert
vì chỉ báo không nhằm mục đích sử dụng độc lập mà chỉ đóng vai trò là nhà cung cấp tài nguyên hình ảnh.
Nếu biến tài nguyên không được sử dụng trong mã nguồn, trình biên dịch có thể không bao gồm tài nguyên đó trong mã nhị phân của chương trình, nhưng điều này không áp dụng cho hình ảnh.
#resource "search1.bmp"
#resource "search2.bmp" as bitmap image[]
#resource "message.txt" as string Message
2
3
Cả ba tệp đều nằm trong cùng thư mục nơi chứa mã nguồn của chỉ báo: MQL5/Indicators/MQL5Book/p7/
.
Nếu người dùng cố gắng chạy chỉ báo, nó sẽ hiển thị một cảnh báo và ngay lập tức ngừng hoạt động. Cảnh báo được chứa trong biến chuỗi tài nguyên Message.
int OnInit()
{
Alert(Message); // equivalent to the following line of the code
// Alert("This indicator is not intended to run, it holds a bitmap resource");
// remove the indicator explicitly, because otherwise it remains "hanging" on the chart uninitialized
ChartIndicatorDelete(0, 0, MQLInfoString(MQL_PROGRAM_NAME));
return INIT_FAILED;
}
2
3
4
5
6
7
8
9
Trong chỉ báo thứ hai BmpUser.mq5
, chúng ta sẽ cố gắng sử dụng các tài nguyên bên ngoài được chỉ định trong các biến đầu vào ResourceOff
và ResourceOn
, để hiển thị trong đối tượng OBJ_BITMAP_LABEL.
input string ResourceOff = "BmpOwner.ex5::search1.bmp";
input string ResourceOn = "BmpOwner.ex5::search2.bmp";
2
Theo mặc định, trạng thái của đối tượng là tắt/thả ("Off"), và hình ảnh cho nó được lấy từ chỉ báo trước "BmpOwner.ex5::search1.bmp". Đường dẫn và tên tài nguyên này tương tự với ký hiệu đầy đủ "\Indicators\MQL5Book\p7\BmpOwner.ex5::search1.bmp". Dạng ngắn được chấp nhận ở đây, vì các chỉ báo nằm cạnh nhau. Nếu sau đó bạn mở hộp thoại thuộc tính đối tượng, bạn sẽ thấy ký hiệu đầy đủ trong các trường Bitmap file (On/Off)
.
Đối với trạng thái được nhấn, trong ResourceOn
, chúng ta nên đọc tài nguyên "BmpOwner.ex5::search2.bmp" (hãy xem điều gì sẽ xảy ra).
Trong các biến đầu vào khác, bạn có thể chọn góc của biểu đồ, dựa trên đó vị trí của hình ảnh được đặt, và các khoảng cách ngang và dọc.
input int X = 25;
input int Y = 25;
input ENUM_BASE_CORNER Corner = CORNER_RIGHT_LOWER;
2
3
Việc tạo đối tượng OBJ_BITMAP_LABEL và cài đặt các thuộc tính của nó, bao gồm tên tài nguyên làm hình ảnh cho OBJPROP_BMPFILE, được thực hiện trong OnInit
.
const string Prefix = "BMP_";
const ENUM_ANCHOR_POINT Anchors[] =
{
ANCHOR_LEFT_UPPER,
ANCHOR_LEFT_LOWER,
ANCHOR_RIGHT_LOWER,
ANCHOR_RIGHT_UPPER
};
void OnInit()
{
const string name = Prefix + "search";
ObjectCreate(0, name, OBJ_BITMAP_LABEL, 0, 0, 0);
ObjectSetString(0, name, OBJPROP_BMPFILE, 0, ResourceOn);
ObjectSetString(0, name, OBJPROP_BMPFILE, 1, ResourceOff);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, X);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, Y);
ObjectSetInteger(0, name, OBJPROP_CORNER, Corner);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, Anchors[(int)Corner]);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Hãy nhớ rằng khi chỉ định hình ảnh trong OBJPROP_BMPFILE, trạng thái nhấn được biểu thị bằng số sửa đổi 0, và trạng thái thả (không nhấn) (mặc định) được biểu thị bằng số sửa đổi 1, điều này có phần bất ngờ.
Trình xử lý OnDeinit
xóa đối tượng khi tháo chỉ báo.
void OnDeinit(const int)
{
ObjectsDeleteAll(0, Prefix);
}
2
3
4
Hãy biên dịch cả hai chỉ báo và chạy BmpUser.ex5
với cài đặt mặc định. Hình ảnh của tệp đồ họa search1.bmp
sẽ xuất hiện trên biểu đồ (xem bên trái).
Hiển thị bình thường (trái) và sai (phải) của tài nguyên đồ họa trong một đối tượng trên biểu đồ
Nếu bạn nhấp vào hình ảnh, tức là chuyển nó sang trạng thái nhấn, chương trình sẽ cố gắng truy cập tài nguyên "BmpOwner.ex5::search2.bmp" (không khả dụng do mảng tài nguyên bitmap
gắn liền với nó). Kết quả là, chúng ta sẽ thấy một hình vuông màu đỏ, biểu thị một đối tượng trống không có hình ảnh (xem trên, bên phải). Tình huống tương tự sẽ luôn xảy ra nếu tham số đầu vào chỉ định một đường dẫn hoặc tên với một tài nguyên rõ ràng không tồn tại hoặc không được chia sẻ. Bạn có thể tạo chương trình của riêng mình, mô tả trong đó một tài nguyên tham chiếu đến một tệp bmp hiện có, sau đó chỉ định trong các tham số đầu vào của chỉ báo BmpUser
. Trong trường hợp này, chỉ báo sẽ có thể hiển thị hình ảnh trên biểu đồ.