Phông chữ và xuất văn bản vào tài nguyên đồ họa
Ngoài việc vẽ từng pixel riêng lẻ trong một mảng của tài nguyên đồ họa, chúng ta có thể sử dụng các hàm tích hợp để hiển thị văn bản. Các hàm này cho phép thay đổi phông chữ hiện tại và các đặc tính của nó (TextSetFont
), lấy kích thước của hình chữ nhật mà chuỗi ký tự cho trước có thể được ghi vào (TextGetSize
), cũng như chèn trực tiếp chú thích vào hình ảnh được tạo ra (TextOut
).
bool TextSetFont(const string name, int size, uint flags, int orientation = 0)
Hàm này thiết lập phông chữ và các đặc tính của nó để vẽ văn bản tiếp theo trong bộ đệm hình ảnh bằng hàm TextOut
(xem thêm ở phần sau). Tham số name
có thể chứa tên của một phông chữ tích hợp trong Windows hoặc một tệp phông chữ ttf (TrueType Font) được kết nối bởi chỉ thị tài nguyên (nếu tên bắt đầu bằng ::
).
Kích thước (size
) có thể được chỉ định bằng điểm (một đơn vị đo kiểu chữ) hoặc pixel (điểm trên màn hình). Giá trị dương có nghĩa là đơn vị đo là pixel, còn giá trị âm được đo bằng phần mười của điểm. Chiều cao tính bằng pixel sẽ trông khác nhau đối với người dùng tùy thuộc vào khả năng kỹ thuật và cài đặt của màn hình của họ. Chiều cao tính bằng điểm sẽ gần giống nhau cho mọi người ("theo cảm nhận bằng mắt").
Một điểm kiểu chữ là một đơn vị chiều dài vật lý, theo truyền thống bằng 1/72 inch. Do đó, 1 điểm bằng 0.352778 milimet. Một pixel trên màn hình là một thước đo chiều dài ảo. Kích thước vật lý của nó phụ thuộc vào độ phân giải phần cứng của màn hình. Ví dụ, với mật độ màn hình 96 DPI (điểm trên mỗi inch), 1 pixel sẽ chiếm 0.264583 milimet hoặc 0.75 điểm. Tuy nhiên, hầu hết các màn hình hiện đại có giá trị DPI cao hơn nhiều và do đó pixel nhỏ hơn. Vì lý do này, các hệ điều hành, bao gồm Windows, từ lâu đã có cài đặt để tăng tỷ lệ hiển thị của các yếu tố giao diện. Do đó, nếu bạn chỉ định kích thước bằng điểm (giá trị âm), kích thước văn bản tính bằng pixel sẽ phụ thuộc vào màn hình và cài đặt tỷ lệ trong hệ điều hành (ví dụ, "tiêu chuẩn" 100%, "trung bình" 125%, hoặc "lớn" 150%).
Việc phóng to khiến các pixel hiển thị được hệ thống mở rộng một cách nhân tạo. Điều này tương đương với việc giảm kích thước màn hình tính bằng pixel, và hệ thống áp dụng DPI hiệu quả để đạt được kích thước vật lý tương tự. Nếu tỷ lệ được bật, thì đó là DPI hiệu quả được báo cáo cho các chương trình, bao gồm cả terminal và sau đó là các chương trình MQL. Nếu cần, bạn có thể tìm hiểu DPI của màn hình từ thuộc tínhTERMINAL_SCREEN_DPI
(xem Thông số màn hình). Tuy nhiên, trong thực tế, bằng cách đặt kích thước phông chữ bằng điểm, chúng ta không cần phải tính toán lại kích thước của nó tùy thuộc vào DPI, vì hệ thống sẽ thực hiện việc đó cho chúng ta.
Phông chữ mặc định là Arial và kích thước mặc định là -120 (12 pt). Các điều khiển, đặc biệt là các đối tượng tích hợp trên biểu đồ, cũng hoạt động với kích thước phông chữ tính bằng điểm. Ví dụ, nếu trong một chương trình MQL, bạn muốn vẽ văn bản có kích thước giống như văn bản trong đối tượng OBJ_LABEL
, vốn có kích thước 10 điểm, bạn nên sử dụng tham số size
bằng -100.
Tham số flags
thiết lập một tổ hợp các cờ mô tả kiểu của phông chữ. Tổ hợp này được tạo thành từ một mặt nạ bit bằng toán tử bitwise OR (|
). Các cờ được chia thành hai nhóm: cờ kiểu và cờ độ đậm.
Bảng sau liệt kê các cờ kiểu. Chúng có thể được trộn lẫn.
Cờ | Mô tả |
---|---|
FONT_ITALIC | Nghiêng |
FONT_UNDERLINE | Gạch chân |
FONT_STRIKEOUT | Gạch ngang |
Các cờ độ đậm có các trọng số tương đối tương ứng (được đưa ra để so sánh hiệu ứng mong đợi).
Cờ | Mô tả |
---|---|
FW_DONTCARE | 0 (mặc định hệ thống sẽ được áp dụng) |
FW_THIN | 100 |
FW_EXTRALIGHT , FW_ULTRALIGHT | 200 |
FW_LIGHT | 300 |
FW_NORMAL , FW_REGULAR | 400 |
FW_MEDIUM | 500 |
FW_SEMIBOLD , FW_DEMIBOLD | 600 |
FW_BOLD | 700 |
FW_EXTRABOLD , FW_ULTRABOLD | 800 |
FW_HEAVY , FW_BLACK | 900 |
Chỉ sử dụng một trong những giá trị này trong tổ hợp các cờ.
Tham số orientation
chỉ định góc của văn bản so với chiều ngang, tính bằng phần mười của độ. Ví dụ, orientation = 0
có nghĩa là xuất văn bản bình thường, trong khi orientation = 450
sẽ dẫn đến độ nghiêng 45 độ (ngược chiều kim đồng hồ).
Lưu ý rằng các cài đặt được thực hiện trong một lần gọi TextSetFont
sẽ ảnh hưởng đến tất cả các lần gọi TextOut
tiếp theo cho đến khi chúng được thay đổi.
Hàm trả về true
nếu thành công hoặc false
nếu xảy ra vấn đề (ví dụ, nếu phông chữ không được tìm thấy).
Chúng ta sẽ xem xét một ví dụ sử dụng hàm này, cũng như hai hàm khác sau khi mô tả tất cả chúng.
bool TextGetSize(const string text, uint &width, uint &height)
Hàm này trả về chiều rộng và chiều cao của dòng tại cài đặt phông chữ hiện tại (đây có thể là phông chữ mặc định hoặc phông chữ được chỉ định trong lần gọi trước đó tới TextSetFont
).
Tham số text
truyền một chuỗi mà chiều dài và chiều rộng tính bằng pixel được yêu cầu. Giá trị kích thước được hàm ghi vào dựa trên tham chiếu trong các tham số width
và height
.
Cần lưu ý rằng độ xoay (độ nghiêng) của văn bản hiển thị được chỉ định bởi tham số orientation
khi gọi TextSetFont
không ảnh hưởng đến việc định cỡ theo bất kỳ cách nào. Nói cách khác, nếu văn bản được cho là xoay 45 độ, thì chính chương trình MQL phải tính toán hình vuông tối thiểu mà văn bản có thể vừa với nó. Hàm TextGetSize
tính toán kích thước văn bản ở vị trí tiêu chuẩn (ngang).
bool TextOut(const string text, int x, int y, uint anchor, uint &data[], uint width, uint height, uint color, ENUM_COLOR_FORMAT color_format)
Hàm này vẽ văn bản trong bộ đệm đồ họa tại tọa độ được chỉ định, có tính đến màu sắc, định dạng và các cài đặt trước đó (phông chữ, kiểu và hướng).
Văn bản được truyền trong tham số text
và phải ở dạng một dòng.
Tọa độ x
và y
được chỉ định bằng pixel xác định điểm trong bộ đệm đồ họa nơi văn bản được hiển thị. Vị trí nào của chú thích được tạo ra sẽ nằm tại điểm (x, y) phụ thuộc vào phương thức neo trong tham số anchor
(xem thêm ở phần sau).
Bộ đệm được đại diện bởi mảng data
, và mặc dù mảng này là một chiều, nó lưu trữ một "canvas" hai chiều với kích thước width
x height
điểm. Mảng này có thể được lấy từ hàm ResourceReadImage
, hoặc được phân bổ bởi một chương trình MQL. Sau khi tất cả các thao tác chỉnh sửa hoàn tất, bao gồm xuất văn bản, bạn nên tạo một tài nguyên mới dựa trên bộ đệm này hoặc áp dụng nó vào một tài nguyên đã tồn tại. Trong cả hai trường hợp, bạn nên gọi ResourceCreate
.
Màu sắc của văn bản và cách xử lý màu được thiết lập bởi các tham số color
và color_format
(xem ENUM_COLOR_FORMAT
). Lưu ý rằng kiểu được sử dụng cho màu là uint
, tức là để truyền màu color
, nó nên được chuyển đổi bằng ColorToARGB
.
Phương thức neo được chỉ định bởi tham số anchor
là sự kết hợp của hai cờ định vị văn bản: dọc và ngang.
Các cờ định vị văn bản ngang là:
TA_LEFT
— neo vào phía bên trái của hộp giới hạnTA_CENTER
— neo vào giữa bên trái và phải của hình chữ nhậtTA_RIGHT
— neo vào phía bên phải của hộp giới hạn
Các cờ định vị văn bản dọc là:
TA_TOP
— neo vào phía trên của hộp giới hạnTA_VCENTER
— neo vào giữa phía trên và dưới của hình chữ nhậtTA_BOTTOM
— neo vào phía dưới của hộp giới hạn
Tổng cộng, có 9 tổ hợp cờ hợp lệ để mô tả phương thức neo.
Vị trí của văn bản xuất ra so với điểm neo
Ở đây, trung tâm của hình ảnh chứa một điểm lớn được phóng đại cố ý trong hình ảnh được tạo ra với tọa độ (x, y). Tùy thuộc vào các cờ, văn bản xuất hiện so với điểm này tại các vị trí được chỉ định (nội dung của văn bản tương ứng với phương thức neo được áp dụng).
Để dễ tham khảo, tất cả các chú thích được thực hiện ở vị trí ngang tiêu chuẩn. Tuy nhiên, lưu ý rằng một góc cũng có thể được áp dụng cho bất kỳ chú thích nào trong số chúng (orientation
), và sau đó chú thích tương ứng sẽ được xoay quanh điểm đó. Trong hình ảnh này, chỉ nhãn được căn giữa trên cả hai chiều là được xoay.
Những cờ này không nên bị nhầm lẫn với căn chỉnh văn bản. Hộp giới hạn luôn được định cỡ để vừa với văn bản, và vị trí của nó so với điểm neo, theo một cách nào đó, ngược lại với tên của các cờ.
Hãy xem xét một số ví dụ sử dụng ba hàm này.
Để bắt đầu, hãy kiểm tra các tùy chọn đơn giản nhất của việc thiết lập độ đậm và kiểu phông chữ. Script ResourceText.mq5
cho phép bạn chọn tên phông chữ, kích thước của nó, cũng như màu sắc của nền và văn bản trong các biến đầu vào. Các nhãn sẽ được hiển thị trên biểu đồ trong số giây được chỉ định.
input string Font = "Arial"; // Tên phông chữ
input int Size = -240; // Kích thước
input color Color = clrBlue; // Màu phông chữ
input color Background = clrNONE; // Màu nền
input uint Seconds = 10; // Thời gian demo (giây)
2
3
4
5
Tên của mỗi mức độ đậm sẽ được hiển thị trong văn bản nhãn, vì vậy để đơn giản hóa quy trình (bằng cách sử dụng EnumToString
), liệt kê ENUM_FONT_WEIGHTS
được khai báo.
enum ENUM_FONT_WEIGHTS
{
_DONTCARE = FW_DONTCARE,
_THIN = FW_THIN,
_EXTRALIGHT = FW_EXTRALIGHT,
_LIGHT = FW_LIGHT,
_NORMAL = FW_NORMAL,
_MEDIUM = FW_MEDIUM,
_SEMIBOLD = FW_SEMIBOLD,
_BOLD = FW_BOLD,
_EXTRABOLD = FW_EXTRABOLD,
_HEAVY = FW_HEAVY,
};
const int nw = 10; // số lượng các mức độ đậm khác nhau
2
3
4
5
6
7
8
9
10
11
12
13
14
Các cờ chú thích được thu thập trong mảng rendering
và các tổ hợp ngẫu nhiên được chọn từ đó.
const uint rendering[] =
{
FONT_ITALIC,
FONT_UNDERLINE,
FONT_STRIKEOUT
};
const int nr = sizeof(rendering) / sizeof(uint);
2
3
4
5
6
7
Để lấy một số ngẫu nhiên trong một phạm vi, có một hàm hỗ trợ Random
.
int Random(const int limit)
{
return rand() % limit;
}
2
3
4
Trong hàm chính của script, chúng ta tìm kích thước của biểu đồ và tạo một đối tượng OBJ_BITMAP_LABEL
bao phủ toàn bộ không gian.
void OnStart()
{
...
const string name = "FONT";
const int w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
const int h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
// đối tượng cho một tài nguyên với hình ảnh lấp đầy toàn bộ cửa sổ
ObjectCreate(0, name, OBJ_BITMAP_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XSIZE, w);
ObjectSetInteger(0, name, OBJPROP_YSIZE, h);
...
}
2
3
4
5
6
7
8
9
10
11
12
13
Tiếp theo, chúng ta cấp phát bộ nhớ cho bộ đệm hình ảnh, lấp đầy nó với màu nền được chỉ định (hoặc để nó trong suốt, theo mặc định), tạo một tài nguyên dựa trên bộ đệm và liên kết nó với đối tượng.
uint data[];
ArrayResize(data, w * h);
ArrayInitialize(data, Background == clrNONE ? 0 : ColorToARGB(Background));
ResourceCreate(name, data, w, h, 0, 0, w, COLOR_FORMAT_ARGB_RAW);
ObjectSetString(0, name, OBJPROP_BMPFILE, "::" + name);
...
2
3
4
5
6
Trong trường hợp cần thiết, lưu ý rằng chúng ta có thể đặt thuộc tính OBJPROP_BMPFILE
mà không cần sửa đổi (0 hoặc 1) trong lệnh gọi ObjectSetString
trừ khi đối tượng được cho là chuyển đổi giữa hai trạng thái.
Tất cả các mức độ đậm của phông chữ được liệt kê trong mảng weights
.
const uint weights[] =
{
FW_DONTCARE,
FW_THIN,
FW_EXTRALIGHT, // FW_ULTRALIGHT,
FW_LIGHT,
FW_NORMAL, // FW_REGULAR,
FW_MEDIUM,
FW_SEMIBOLD, // FW_DEMIBOLD,
FW_BOLD,
FW_EXTRABOLD, // FW_ULTRABOLD,
FW_HEAVY, // FW_BLACK
};
const int nw = sizeof(weights) / sizeof(uint);
2
3
4
5
6
7
8
9
10
11
12
13
14
Trong vòng lặp, theo thứ tự, chúng ta thiết lập mức độ đậm tiếp theo cho mỗi dòng bằng cách sử dụng TextSetFont
, chọn trước một kiểu ngẫu nhiên. Mô tả về phông chữ, bao gồm tên và độ đậm, được vẽ trong bộ đệm bằng cách sử dụng TextOut
.
const int step = h / (nw + 2);
int cursor = 0; // Tọa độ Y của "dòng văn bản" hiện tại
for(int weight = 0; weight < nw; ++weight)
{
// áp dụng kiểu ngẫu nhiên
const int r = Random(8);
uint render = 0;
for(int j = 0; j < 3; ++j)
{
if((bool)(r & (1 << j))) render |= rendering[j];
}
TextSetFont(Font, Size, weights[weight] | render);
// tạo mô tả phông chữ
const string text = Font + EnumToString((ENUM_FONT_WEIGHTS)weights[weight]);
// vẽ văn bản trên một "dòng" riêng biệt
cursor += step;
TextOut(text, w / 2, cursor, TA_CENTER | TA_TOP, data, w, h,
ColorToARGB(Color), COLOR_FORMAT_ARGB_RAW);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Bây giờ cập nhật tài nguyên và biểu đồ.
ResourceCreate(name, data, w, h, 0, 0, w, COLOR_FORMAT_ARGB_RAW);
ChartRedraw();
...
2
3
Người dùng có thể dừng bản demo trước thời hạn.
const uint timeout = GetTickCount() + Seconds * 1000;
while(!IsStopped() && GetTickCount() < timeout)
{
Sleep(1000);
}
2
3
4
5
Cuối cùng, script xóa tài nguyên và đối tượng.
ObjectDelete(0, name);
ResourceFree("::" + name);
}
2
3
Kết quả của script được hiển thị trong hình ảnh sau.
Vẽ văn bản với các độ đậm và kiểu khác nhau
Trong ví dụ thứ hai của ResourceFont.mq5
, chúng ta sẽ làm phức tạp nhiệm vụ bằng cách thêm một phông chữ tùy chỉnh làm tài nguyên và sử dụng xoay văn bản theo gia số 90 độ.
Tệp phông chữ nằm cạnh script.
#resource "a_LCDNova3DCmObl.ttf"
Thông điệp có thể được thay đổi trong tham số đầu vào.
input string Message = "Hello world!"; // Thông điệp
Lần này, OBJ_BITMAP_LABEL
sẽ không chiếm toàn bộ cửa sổ và do đó được căn giữa theo cả chiều ngang và chiều dọc.
void OnStart()
{
const string name = "FONT";
const int w = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS);
const int h = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS);
// đối tượng cho một tài nguyên với hình ảnh
ObjectCreate(0, name, OBJ_BITMAP_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, w / 2);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, h / 2);
ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_CENTER);
...
2
3
4
5
6
7
8
9
10
11
12
Để bắt đầu, bộ đệm có kích thước tối thiểu được cấp phát, chỉ để hoàn thành việc tạo tài nguyên. Sau đó, chúng ta sẽ mở rộng nó để phù hợp với kích thước của dòng chữ, với các biến dự trữ width
và height
.
uint data[], width, height;
ArrayResize(data, 1);
ResourceCreate(name, data, 1, 1, 0, 0, 1, COLOR_FORMAT_ARGB_RAW);
ObjectSetString(0, name, OBJPROP_BMPFILE, "::" + name);
...
2
3
4
5
Trong một vòng lặp với đếm ngược thời gian thử nghiệm, chúng ta cần thay đổi hướng của dòng chữ, với biến angle
(độ sẽ được cuộn trong đó). Hướng sẽ thay đổi mỗi giây một lần, số đếm nằm trong biến remain
.
const uint timeout = GetTickCount() + Seconds * 1000;
int angle = 0;
int remain = 10;
...
2
3
4
Trong vòng lặp, chúng ta liên tục thay đổi góc xoay của văn bản, và trong chính văn bản, chúng ta hiển thị bộ đếm ngược số giây. Với mỗi dòng chữ mới, kích thước của nó được tính toán bằng TextGetSize
, dựa trên đó bộ đệm được cấp phát lại.
while(!IsStopped() && GetTickCount() < timeout)
{
// áp dụng góc mới
TextSetFont("::a_LCDNova3DCmObl.ttf", -240, 0, angle * 10);
// tạo văn bản
const string text = Message + " (" + (string)remain-- + ")";
// lấy kích thước văn bản, cấp phát mảng
TextGetSize(text, width, height);
ArrayResize(data, width * height);
ArrayInitialize(data, 0); // độ trong suốt
// với hướng dọc, hoán đổi kích thước
if((bool)(angle / 90 & 1))
{
const uint t = width;
width = height;
height = t;
}
// điều chỉnh kích thước của đối tượng
ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
// vẽ văn bản
TextOut(text, width / 2, height / 2, TA_CENTER | TA_VCENTER, data, width, height,
ColorToARGB(clrBlue), COLOR_FORMAT_ARGB_RAW);
// cập nhật tài nguyên và biểu đồ
ResourceCreate(name, data, width, height, 0, 0, width, COLOR_FORMAT_ARGB_RAW);
ChartRedraw();
// thay đổi góc
angle += 90;
Sleep(100);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Lưu ý rằng nếu văn bản nằm dọc, kích thước cần được hoán đổi. Nói chung hơn, với văn bản xoay ở một góc bất kỳ, cần nhiều phép toán hơn để có được kích thước bộ đệm phù hợp với toàn bộ văn bản.
Cuối cùng, chúng ta cũng xóa đối tượng và tài nguyên.
ObjectDelete(0, name);
ResourceFree("::" + name);
}
2
3
Một khoảnh khắc trong quá trình thực thi script được hiển thị trong ảnh chụp màn hình sau.
Dòng chữ với phông chữ tùy chỉnh
Ví dụ cuối cùng, hãy xem xét script ResourceTextAnchOrientation.mq5
hiển thị các góc xoay và điểm neo khác nhau của văn bản.
Script tạo ra số lượng nhãn được chỉ định (ExampleCount
) bằng phông chữ được chỉ định.
input string Font = "Arial"; // Tên phông chữ
input int Size = -150; // Kích thước
input int ExampleCount = 11; // Số lượng ví dụ
2
3
Điểm neo và góc xoay được chọn ngẫu nhiên.
Để chỉ định tên của các điểm neo trong nhãn, có liệt kê ENUM_TEXT_ANCHOR
với tất cả các tùy chọn hợp lệ được khai báo. Vì vậy, chúng ta có thể gọi EnumToString
cho bất kỳ phần tử nào được chọn ngẫu nhiên.
enum ENUM_TEXT_ANCHOR
{
LEFT_TOP = TA_LEFT | TA_TOP,
LEFT_VCENTER = TA_LEFT | TA_VCENTER,
LEFT_BOTTOM = TA_LEFT | TA_BOTTOM,
CENTER_TOP = TA_CENTER | TA_TOP,
CENTER_VCENTER = TA_CENTER | TA_VCENTER,
CENTER_BOTTOM = TA_CENTER | TA_BOTTOM,
RIGHT_TOP = TA_RIGHT | TA_TOP,
RIGHT_VCENTER = TA_RIGHT | TA_VCENTER,
RIGHT_BOTTOM = TA_RIGHT | TA_BOTTOM,
};
2
3
4
5
6
7
8
9
10
11
12
Một mảng của các hằng số mới này được khai báo trong trình xử lý OnStart
.
void OnStart()
{
const ENUM_TEXT_ANCHOR anchors[] =
{
LEFT_TOP,
LEFT_VCENTER,
LEFT_BOTTOM,
CENTER_TOP,
CENTER_VCENTER,
CENTER_BOTTOM,
RIGHT_TOP,
RIGHT_VCENTER,
RIGHT_BOTTOM,
};
const int na = sizeof(anchors) / sizeof(uint);
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Việc tạo đối tượng và tài nguyên ban đầu tương tự như ví dụ với ResourceText.mq5
, vì vậy chúng ta sẽ bỏ qua ở đây. Điều thú vị nhất xảy ra trong vòng lặp.
for(int i = 0; i < ExampleCount; ++i)
{
// áp dụng một góc ngẫu nhiên
const int angle = Random(360);
TextSetFont(Font, Size, 0, angle * 10);
// lấy tọa độ ngẫu nhiên và một điểm neo
const ENUM_TEXT_ANCHOR anchor = anchors[Random(na)];
const int x = Random(w / 2) + w / 4;
const int y = Random(h / 2) + h / 4;
const color clr = ColorMix::HSVtoRGB(angle);
// vẽ một vòng tròn trực tiếp tại vị trí đó của hình ảnh,
// nơi điểm neo xuất hiện
TextOut(ShortToString(0x2022), x, y, TA_CENTER | TA_VCENTER, data, w, h,
ColorToARGB(clr), COLOR_FORMAT_ARGB_NORMALIZE);
// tạo văn bản mô tả loại neo và góc
const string text = EnumToString(anchor) +
"(" + (string)angle + CharToString(0xB0) + ")";
// vẽ văn bản
TextOut(text, x, y, anchor, data, w, h,
ColorToARGB(clr), COLOR_FORMAT_ARGB_NORMALIZE);
}
...
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Chỉ còn lại việc cập nhật hình ảnh và biểu đồ, sau đó chờ lệnh của người dùng và giải phóng tài nguyên.
ResourceCreate(name, data, w, h, 0, 0, w, COLOR_FORMAT_ARGB_NORMALIZE);
ChartRedraw();
const uint timeout = GetTickCount() + Seconds * 1000;
while(!IsStopped() && GetTickCount() < timeout)
{
Sleep(1000);
}
ObjectDelete(0, name);
ResourceFree("::" + name);
}
2
3
4
5
6
7
8
9
10
11
12
Đây là kết quả chúng ta nhận được.
Xuất văn bản với tọa độ, điểm neo và góc ngẫu nhiên
Ngoài ra, để tự học, cuốn sách cung cấp một trình chỉnh sửa đồ họa đơn giản SimpleDrawing.mq5
. Nó được thiết kế như một chỉ báo không bộ đệm và sử dụng trong công việc của nó các lớp hình dạng đã được xem xét trước đó (xem ví dụ với ResourceShapesDraw.mq5
). Chúng được đặt trong tệp tiêu đề ShapesDrawing.mqh
gần như không thay đổi. Trước đây, các hình dạng được tạo ngẫu nhiên bởi script. Bây giờ người dùng có thể chọn và vẽ chúng trên biểu đồ. Vì mục đích này, một giao diện với bảng màu và thanh nút đã được triển khai theo số lượng lớp hình dạng đã đăng ký. Giao diện được thực hiện bởi lớp SimpleDrawing
(SimpleDrawing.mqh
).
Trình chỉnh sửa đồ họa đơn giản
Bảng điều khiển và bảng màu có thể được đặt dọc theo bất kỳ biên nào của biểu đồ, thể hiện khả năng xoay nhãn.
Việc chọn hình dạng tiếp theo để vẽ được thực hiện bằng cách nhấn nút trong bảng: nút "dính" ở trạng thái được nhấn, và màu nền của nó cho biết màu vẽ đã chọn. Để thay đổi màu, nhấp vào bất kỳ đâu trên bảng màu.
Khi một trong những loại hình dạng được chọn trong bảng (một trong các nút "hoạt động"), nhấp vào khu vực vẽ (phần còn lại của biểu đồ, được biểu thị bằng bóng mờ) sẽ vẽ một hình dạng có kích thước định sẵn tại vị trí đó. Tại thời điểm này, nút "tắt". Trong trạng thái này, khi tất cả các nút không hoạt động, bạn có thể di chuyển các hình dạng quanh không gian làm việc bằng chuột. Nếu giữ phím Ctrl
được nhấn, thay vì di chuyển, hình dạng sẽ được thay đổi kích thước. "Điểm nóng" nằm ở trung tâm của mỗi hình dạng (kích thước của vùng nhạy được đặt bởi một macro trong mã nguồn và có thể cần được tăng lên cho các màn hình DPI rất cao).
Lưu ý rằng trình chỉnh sửa bao gồm ID biểu đồ (ChartID
) trong tên của các tài nguyên được tạo ra. Điều này cho phép chạy trình chỉnh sửa song song trên nhiều biểu đồ.