Sự kiện đối tượng đồ họa
Đối với các đối tượng đồ họa nằm trên biểu đồ, thiết bị đầu cuối tạo ra một số sự kiện chuyên biệt. Hầu hết chúng áp dụng cho các đối tượng thuộc bất kỳ loại nào. Sự kiện kết thúc chỉnh sửa văn bản trong trường nhập liệu — CHARTEVENT_OBJECT_ENDEDIT
— chỉ được tạo ra cho các đối tượng loại OBJ_EDIT
.
Sự kiện nhấp chuột vào đối tượng (CHARTEVENT_OBJECT_CLICK
), kéo chuột (CHARTEVENT_OBJECT_DRAG
) và thay đổi thuộc tính đối tượng (CHARTEVENT_OBJECT_CHANGE
) luôn hoạt động, trong khi sự kiện tạo đối tượng CHARTEVENT_OBJECT_CREATE
và xóa đối tượng CHARTEVENT_OBJECT_DELETE
yêu cầu kích hoạt rõ ràng bằng cách thiết lập các thuộc tính biểu đồ liên quan: CHART_EVENT_OBJECT_CREATE
và CHART_EVENT_OBJECT_DELETE
.
Khi đổi tên một đối tượng thủ công (từ hộp thoại thuộc tính), thiết bị đầu cuối tạo ra một chuỗi sự kiện CHARTEVENT_OBJECT_DELETE
, CHARTEVENT_OBJECT_CREATE
, CHARTEVENT_OBJECT_CHANGE
. Khi bạn đổi tên một đối tượng bằng lập trình, các sự kiện này không được tạo ra.
Tất cả các sự kiện trong đối tượng mang tên của đối tượng liên quan trong tham số sparam
của hàm OnChartEvent
.
Ngoài ra, tọa độ nhấp chuột được truyền cho CHARTEVENT_OBJECT_CLICK
: X trong tham số lparam
và Y trong tham số dparam
. Tọa độ là chung cho toàn bộ biểu đồ, bao gồm cả các cửa sổ phụ.
Việc nhấp vào các đối tượng hoạt động khác nhau tùy thuộc vào loại đối tượng. Đối với một số, như hình elip, con trỏ phải nằm trên bất kỳ điểm neo nào. Đối với những cái khác (tam giác, hình chữ nhật, đường thẳng), con trỏ có thể nằm trên chu vi của đối tượng, không chỉ trên một điểm. Trong tất cả các trường hợp như vậy, việc di chuột qua khu vực tương tác của đối tượng sẽ hiển thị một tooltip với tên của đối tượng.
Các đối tượng liên kết với tọa độ màn hình, cho phép hình thành giao diện đồ họa của chương trình, cụ thể là nút, trường nhập liệu và bảng hình chữ nhật, tạo ra sự kiện khi chuột được nhấp vào bất kỳ đâu bên trong đối tượng.
Nếu có nhiều đối tượng dưới con trỏ, một sự kiện được tạo ra cho đối tượng có độ ưu tiên Z lớn nhất. Nếu độ ưu tiên của các đối tượng bằng nhau, sự kiện được gán cho đối tượng được tạo sau (điều này tương ứng với hiển thị trực quan của chúng, tức là cái sau chồng lên cái trước).
Phiên bản mới của chỉ báo sẽ giúp bạn kiểm tra các sự kiện trong đối tượng EventAllObjects.mq5
. Chúng ta sẽ tạo và cấu hình nó bằng lớp đã biết ObjectSelector
của một số đối tượng, sau đó chặn trong trình xử lý OnChartEvent
các sự kiện đặc trưng của chúng.
#include <MQL5Book/ObjectMonitor.mqh>
class ObjectBuilder: public ObjectSelector
{
protected:
const ENUM_OBJECT type;
const int window;
public:
ObjectBuilder(const string _id, const ENUM_OBJECT _type,
const long _chart = 0, const int _win = 0):
ObjectSelector(_id, _chart), type(_type), window(_win)
{
ObjectCreate(host, id, type, window, 0, 0);
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Ban đầu, trong OnInit
, chúng ta tạo một đối tượng nút và một đường thẳng đứng. Đối với đường thẳng, chúng ta sẽ theo dõi sự kiện di chuyển (kéo), và khi nhấn nút, chúng ta sẽ tạo một trường nhập liệu để kiểm tra văn bản đã nhập.
const string ObjNamePrefix = "EventShow-";
const string ButtonName = ObjNamePrefix + "Button";
const string EditBoxName = ObjNamePrefix + "EditBox";
const string VLineName = ObjNamePrefix + "VLine";
bool objectCreate, objectDelete;
void OnInit()
{
// remember the original settings to restore in OnDeinit
objectCreate = ChartGetInteger(0, CHART_EVENT_OBJECT_CREATE);
objectDelete = ChartGetInteger(0, CHART_EVENT_OBJECT_DELETE);
// set new properties
ChartSetInteger(0, CHART_EVENT_OBJECT_CREATE, true);
ChartSetInteger(0, CHART_EVENT_OBJECT_DELETE, true);
ObjectBuilder button(ButtonName, OBJ_BUTTON);
button.set(OBJPROP_XDISTANCE, 100).set(OBJPROP_YDISTANCE, 100)
.set(OBJPROP_XSIZE, 200).set(OBJPROP_TEXT, "Click Me");
ObjectBuilder line(VLineName, OBJ_VLINE);
line.set(OBJPROP_TIME, iTime(NULL, 0, 0))
.set(OBJPROP_SELECTABLE, true).set(OBJPROP_SELECTED, true)
.set(OBJPROP_TEXT, "Drag Me").set(OBJPROP_TOOLTIP, "Drag Me");
ChartRedraw();
}
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
Dọc đường, đừng quên đặt các thuộc tính biểu đồ CHART_EVENT_OBJECT_CREATE
và CHART_EVENT_OBJECT_DELETE
thành true
để được thông báo khi tập hợp các đối tượng thay đổi.
Trong hàm OnChartEvent
, chúng ta sẽ cung cấp phản hồi bổ sung cho các sự kiện cần thiết: sau khi hoàn tất việc kéo, chúng ta sẽ hiển thị vị trí mới của đường thẳng trong nhật ký và, sau khi chỉnh sửa văn bản trong trường nhập liệu, nội dung của nó.
void OnChartEvent(const int id,
const long &lparam, const double &dparam, const string &sparam)
{
ENUM_CHART_EVENT evt = (ENUM_CHART_EVENT)id;
PrintFormat("%s %lld %f '%s'", EnumToString(evt), lparam, dparam, sparam);
if(id == CHARTEVENT_OBJECT_CLICK && sparam == ButtonName)
{
if(ObjectGetInteger(0, ButtonName, OBJPROP_STATE))
{
ObjectBuilder edit(EditBoxName, OBJ_EDIT);
edit.set(OBJPROP_XDISTANCE, 100).set(OBJPROP_YDISTANCE, 150)
.set(OBJPROP_BGCOLOR, clrWhite)
.set(OBJPROP_XSIZE, 200).set(OBJPROP_TEXT, "Edit Me");
}
else
{
ObjectDelete(0, EditBoxName);
}
ChartRedraw();
}
else if(id == CHARTEVENT_OBJECT_ENDEDIT && sparam == EditBoxName)
{
Print(ObjectGetString(0, EditBoxName, OBJPROP_TEXT));
}
else if(id == CHARTEVENT_OBJECT_DRAG && sparam == VLineName)
{
Print(TimeToString((datetime)ObjectGetInteger(0, VLineName, OBJPROP_TIME)));
}
}
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
Lưu ý rằng khi nút được nhấn lần đầu tiên, trạng thái của nó thay đổi từ thả sang nhấn, và để đáp lại điều này, chúng ta tạo một trường nhập liệu. Nếu bạn nhấp lại vào nút, nó sẽ thay đổi trạng thái trở lại, kết quả là trường nhập liệu sẽ bị xóa khỏi biểu đồ.
Dưới đây là hình ảnh của biểu đồ trong quá trình hoạt động của chỉ báo.
Các đối tượng được điều khiển bởi trình xử lý sự kiện OnChartEvent
Ngay sau khi chỉ báo được khởi chạy, các dòng sau xuất hiện trong nhật ký:
CHARTEVENT_OBJECT_CREATE 0 0.000000 'EventShow-Button'
CHARTEVENT_OBJECT_CREATE 0 0.000000 'EventShow-VLine'
CHARTEVENT_CHART_CHANGE 0 0.000000 ''
2
3
Nếu sau đó chúng ta kéo đường thẳng bằng chuột, chúng ta sẽ thấy điều gì đó như thế này:
CHARTEVENT_OBJECT_DRAG 0 0.000000 'EventShow-VLine'
2022.01.05 10:00
2
Tiếp theo, bạn có thể nhấp vào nút và chỉnh sửa văn bản trong trường nhập liệu mới tạo (khi chỉnh sửa xong, nhấp Enter
hoặc nhấp ra ngoài trường nhập liệu). Điều này sẽ dẫn đến các mục sau trong nhật ký (tọa độ và văn bản thông điệp có thể khác; văn bản "new message" đã được nhập ở đây):
CHARTEVENT_OBJECT_CLICK 181 113.000000 'EventShow-Button'
CHARTEVENT_CLICK 181 113.000000 ''
CHARTEVENT_OBJECT_CREATE 0 0.000000 'EventShow-EditBox'
CHARTEVENT_OBJECT_CLICK 152 160.000000 'EventShow-EditBox'
CHARTEVENT_CLICK 152 160.000000 ''
CHARTEVENT_OBJECT_ENDEDIT 0 0.000000 'EventShow-EditBox'
new message
2
3
4
5
6
7
Nếu sau đó bạn thả nút, trường nhập liệu sẽ bị xóa.
CHARTEVENT_OBJECT_CLICK 162 109.000000 'EventShow-Button'
CHARTEVENT_CLICK 162 109.000000 ''
CHARTEVENT_OBJECT_DELETE 0 0.000000 'EventShow-EditBox'
2
3
Đáng chú ý rằng nút hoạt động mặc định như một công tắc hai vị trí, tức là nó dính xen kẽ ở trạng thái nhấn hoặc thả do nhấp chuột. Đối với một nút thông thường, hành vi này là dư thừa: để chỉ đơn giản theo dõi các lần nhấn nút, bạn nên đưa nó về trạng thái thả khi xử lý sự kiện bằng cách gọi ObjectSetInteger(0, ButtonName, OBJPROP_STATE, false)
.