Tạo tài nguyên động: ResourceCreate
Các chỉ thị #resource
nhúng tài nguyên vào chương trình ở giai đoạn biên dịch, do đó chúng có thể được gọi là tĩnh. Tuy nhiên, thường xuyên cần thiết phải tạo tài nguyên (tạo hoàn toàn mới hoặc sửa đổi các tài nguyên hiện có) ở giai đoạn thực thi chương trình. Để phục vụ những mục đích này, MQL5 cung cấp hàm ResourceCreate
. Các tài nguyên được tạo bằng hàm này sẽ được gọi là động.
Hàm này có hai dạng: dạng đầu tiên cho phép tải ảnh và âm thanh từ các tệp, còn dạng thứ hai được thiết kế để tạo ảnh bitmap dựa trên một mảng các pixel được chuẩn bị trong bộ nhớ.
bool ResourceCreate(const string resource, const string filepath)
Hàm này tải tài nguyên có tên resource
từ một tệp nằm tại filepath
. Nếu đường dẫn bắt đầu bằng dấu gạch chéo ngược \
(trong các chuỗi hằng, nó cần được nhân đôi: \\path\\name.ext
), thì tệp sẽ được tìm kiếm tại đường dẫn này tương đối với thư mục MQL5 trong thư mục dữ liệu của terminal (ví dụ, \\Files\\CustomSounds\\Hello.wav
ám chỉ MQL5/Files/CustomSounds/Hello.wav
). Nếu không có dấu gạch chéo ngược, thì tài nguyên sẽ được tìm kiếm bắt đầu từ thư mục chứa tệp thực thi mà từ đó chúng ta gọi hàm.
Đường dẫn có thể trỏ đến một tài nguyên tĩnh được gắn cứng vào chương trình MQL của bên thứ ba hoặc chương trình hiện tại. Ví dụ, một kịch bản nhất định có thể tạo một tài nguyên dựa trên ảnh từ chỉ báo BmpOwner.mq5
được thảo luận trong phần Biến tài nguyên.
ResourceCreate("::MyImage", "\\Indicators\\MQL5Book\\p7\\BmpOwner.ex5::search1.bmp");
Tên tài nguyên trong tham số resource
có thể chứa dấu hai chấm đầu tiên (mặc dù điều này không bắt buộc, vì nếu không có, tiền tố ::
sẽ được tự động thêm vào tên). Điều này đảm bảo sự thống nhất khi sử dụng một dòng để khai báo tài nguyên trong lệnh gọi ResourceCreate
, cũng như để truy cập sau đó (ví dụ, khi thiết lập thuộc tính OBJPROP_BMPFILE
).
Tất nhiên, câu lệnh trên để tạo tài nguyên động là thừa nếu chúng ta chỉ muốn tải một tài nguyên ảnh của bên thứ ba vào đối tượng của chúng ta trên biểu đồ, vì chỉ cần gán trực tiếp chuỗi \\Indicators\\MQL5Book\\p7\\BmpOwner.ex5::search1.bmp
vào thuộc tính OBJPROP_BMPFILE
là đủ. Tuy nhiên, nếu bạn cần chỉnh sửa một ảnh, tài nguyên động là không thể thiếu. Tiếp theo, chúng ta sẽ trình bày một ví dụ trong phần Đọc và sửa đổi dữ liệu tài nguyên.
Các tài nguyên động có thể được truy cập công khai từ các chương trình MQL khác bằng tên đầy đủ của chúng, bao gồm đường dẫn và tên của chương trình đã tạo ra tài nguyên. Ví dụ, nếu lệnh gọi ResourceCreate
trước đó được thực hiện bởi kịch bản MQL5/Scripts/MyExample.ex5
, thì một chương trình MQL khác có thể truy cập tài nguyên đó bằng liên kết đầy đủ \\Scripts\\MyExample.ex5::MyImage
, và bất kỳ kịch bản nào khác trong cùng thư mục có thể truy cập bằng cách viết tắt MyExample.ex5::MyImage
(ở đây đường dẫn tương đối đơn giản là suy biến). Quy tắc viết đường dẫn đầy đủ (từ thư mục gốc MQL5) và đường dẫn tương đối đã được đề cập ở trên.
Hàm ResourceCreate
trả về một chỉ báo kiểu boolean về thành công (true
) hoặc lỗi (false
) như là kết quả của việc thực thi. Mã lỗi, như thường lệ, có thể được tìm thấy trong biến _LastError
. Cụ thể, bạn có thể gặp phải các lỗi sau:
- ERR_RESOURCE_NAME_DUPLICATED (4015) — tên trùng khớp giữa tài nguyên động và tĩnh
- ERR_RESOURCE_NOT_FOUND (4016) — tài nguyên/tệp được chỉ định từ tham số
filepath
không được tìm thấy - ERR_RESOURCE_UNSUPPOTED_TYPE (4017) — loại tài nguyên không được hỗ trợ hoặc kích thước vượt quá 2 GB
- ERR_RESOURCE_NAME_IS_TOO_LONG (4018) — tên tài nguyên vượt quá 63 ký tự
Tất cả những điều này không chỉ áp dụng cho dạng đầu tiên của hàm mà còn cho dạng thứ hai.
bool ResourceCreate(const string resource, const uint &data[], uint img_width, uint img_height, uint data_xoffset, uint data_yoffset, uint data_width, ENUM_COLOR_FORMAT color_format)
Tham số resource
vẫn có nghĩa là tên của tài nguyên mới, và nội dung của ảnh được xác định bởi các tham số còn lại.
Mảng data
có thể là một chiều (data[]
) hoặc hai chiều (data[][]
): nó truyền các điểm (pixel) của raster. Các tham số img_width
và img_height
đặt kích thước của ảnh hiển thị (tính bằng pixel). Các kích thước này có thể nhỏ hơn kích thước vật lý của ảnh trong mảng data
, nhờ đó đạt được hiệu ứng khung khi chỉ một phần của ảnh gốc được xuất ra. Các tham số data_xoffset
và data_yoffset
xác định tọa độ của góc trên bên trái của "khung".
Tham số data_width
có nghĩa là chiều rộng đầy đủ của ảnh gốc (trong mảng data
). Giá trị 0 ngụ ý rằng chiều rộng này giống như img_width
. Tham số data_width
chỉ có ý nghĩa khi chỉ định một mảng một chiều trong tham số data
, vì đối với mảng hai chiều, kích thước của nó đã được biết ở cả hai chiều (trong trường hợp này, tham số data_width
bị bỏ qua và được giả định bằng với chiều thứ hai của mảng data[][]
).
Trong trường hợp phổ biến nhất, khi bạn muốn hiển thị toàn bộ ảnh ("nguyên bản"), hãy sử dụng cú pháp sau:
ResourceCreate(name, data, width, height, 0, 0, 0, ...);
Ví dụ, nếu chương trình có một tài nguyên tĩnh được mô tả dưới dạng mảng bitmap
hai chiều:
#resource "static.bmp" as bitmap data[][]
Thì việc tạo một tài nguyên động dựa trên nó có thể được thực hiện theo cách sau:
ResourceCreate("dynamic", data, ArrayRange(data, 1), ArrayRange(data, 0), 0, 0, 0, ...);
Việc tạo tài nguyên động dựa trên tài nguyên tĩnh không chỉ được yêu cầu khi cần chỉnh sửa trực tiếp, mà còn để kiểm soát cách xử lý màu sắc khi hiển thị tài nguyên. Chế độ này được chọn bằng tham số cuối cùng của hàm: color_format
. Nó sử dụng liệt kê ENUM_COLOR_FORMAT
.
Định danh | Mô tả |
---|---|
COLOR_FORMAT_XRGB_NOALPHA | Thành phần kênh alpha (độ trong suốt) bị bỏ qua |
COLOR_FORMAT_ARGB_RAW | Các thành phần màu không được terminal xử lý |
COLOR_FORMAT_ARGB_NORMALIZE | Các thành phần màu được terminal xử lý (xem bên dưới) |
Trong chế độ COLOR_FORMAT_XRGB_NOALPHA
, ảnh được hiển thị mà không có hiệu ứng: mỗi điểm được hiển thị bằng màu đặc (đây là cách vẽ nhanh nhất). Hai chế độ còn lại hiển thị pixel có tính đến độ trong suốt trong byte cao của mỗi pixel nhưng có hiệu ứng khác nhau. Trong trường hợp COLOR_FORMAT_ARGB_NORMALIZE
, terminal thực hiện các phép biến đổi sau đối với các thành phần màu của mỗi điểm khi chuẩn bị raster tại thời điểm gọi ResourceCreate
:
R = R * A / 255
G = G * A / 255
B = B * A / 255
A = A
2
3
4
Các tài nguyên ảnh tĩnh trong chỉ thị #resource
được kết nối bằng COLOR_FORMAT_ARGB_NORMALIZE
.
Trong tài nguyên động, kích thước mảng bị giới hạn bởi giá trị INT_MAX
byte (2147483647, 2 Gb), vượt xa giới hạn do trình biên dịch áp đặt khi xử lý chỉ thị tĩnh #resource
: kích thước tệp không được vượt quá 128 Mb.
Nếu phiên bản thứ hai của hàm được gọi để tạo một tài nguyên với cùng tên, nhưng với các tham số khác thay đổi (nội dung của mảng pixel, chiều rộng, chiều cao, hoặc độ lệch), thì tài nguyên mới không được tạo lại, mà tài nguyên hiện có chỉ đơn giản được cập nhật. Chỉ chương trình sở hữu tài nguyên (chương trình đã tạo ra nó ban đầu) mới có thể sửa đổi tài nguyên theo cách này.
Nếu khi tạo tài nguyên động từ các bản sao khác nhau của chương trình chạy trên các biểu đồ khác nhau, bạn cần tài nguyên riêng cho mỗi bản sao, bạn nên thêm
ChartID
vào tên của tài nguyên.
Để thể hiện việc tạo ảnh động trong các bảng màu khác nhau, chúng ta đề xuất phân tích kịch bản ARGBbitmap.mq5
.
Ảnh "argb.bmp" được gắn tĩnh vào nó.
#resource "argb.bmp" as bitmap Data[][]
Người dùng chọn phương thức định dạng màu bằng tham số ColorFormat
.
input ENUM_COLOR_FORMAT ColorFormat = COLOR_FORMAT_XRGB_NOALPHA;
Tên của đối tượng mà ảnh sẽ được hiển thị và tên của tài nguyên động được mô tả bởi các biến BitmapObject
và ResName
.
const string BitmapObject = "BitmapObject";
const string ResName = "::image";
2
Dưới đây là hàm chính của kịch bản.
void OnStart()
{
ResourceCreate(ResName, Data, ArrayRange(Data, 1), ArrayRange(Data, 0),
0, 0, 0, ColorFormat);
ObjectCreate(0, BitmapObject, OBJ_BITMAP_LABEL, 0, 0, 0);
ObjectSetInteger(0, BitmapObject, OBJPROP_XDISTANCE, 50);
ObjectSetInteger(0, BitmapObject, OBJPROP_YDISTANCE, 50);
ObjectSetString(0, BitmapObject, OBJPROP_BMPFILE, ResName);
Comment("Press ESC to stop the demo");
const ulong start = TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE);
while(!IsStopped() // waiting for the user's command to end the demo
&& TerminalInfoInteger(TERMINAL_KEYSTATE_ESCAPE) == start)
{
Sleep(1000);
}
Comment("");
ObjectDelete(0, BitmapObject);
ResourceFree(ResName);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Kịch bản tạo một tài nguyên mới trong chế độ màu được chỉ định và gán nó vào thuộc tính OBJPROP_BMPFILE
của một đối tượng loại OBJ_BITMAP_LABEL
. Tiếp theo, kịch bản đợi người dùng dừng kịch bản một cách rõ ràng hoặc nhấn Esc
rồi xóa đối tượng (bằng cách gọi ObjectDelete
) và tài nguyên bằng hàm ResourceFree
. Lưu ý rằng việc xóa một đối tượng không tự động xóa tài nguyên. Đó là lý do tại sao chúng ta cần hàm ResourceFree
mà chúng ta sẽ thảo luận trong phần tiếp theo.
Nếu chúng ta không gọi ResourceFree
, thì các tài nguyên động vẫn còn trong bộ nhớ của terminal ngay cả sau khi chương trình MQL kết thúc, cho đến khi terminal được đóng lại. Điều này cho phép sử dụng chúng như kho lưu trữ hoặc phương tiện để trao đổi thông tin giữa các chương trình MQL.
Tài nguyên động được tạo bằng dạng thứ hai của ResourceCreate
không nhất thiết phải mang hình ảnh. Mảng data
có thể chứa dữ liệu bất kỳ nếu chúng ta không sử dụng nó để hiển thị. Trong trường hợp này, điều quan trọng là đặt lược đồ COLOR_FORMAT_XRGB_NOALPHA
. Chúng ta sẽ trình bày một ví dụ như vậy tại một thời điểm nào đó.
Trong khi đó, hãy kiểm tra cách kịch bản ARGBbitmap.mq5
hoạt động.
Ảnh "argb.bmp" nói trên chứa thông tin về độ trong suốt: góc trên bên trái có nền hoàn toàn trong suốt, và độ trong suốt giảm dần theo đường chéo về phía góc dưới bên phải.
Các hình ảnh sau đây cho thấy kết quả của việc chạy kịch bản trong ba chế độ khác nhau.
Hiển thị ảnh trong định dạng màu COLOR_FORMAT_XRGB_NOALPHA
Hiển thị ảnh trong định dạng màu COLOR_FORMAT_ARGB_RAW
Hiển thị ảnh trong định dạng màu COLOR_FORMAT_ARGB_NORMALIZE