Kiểu do người dùng định nghĩa
Từ khóa typedef
trong C++ cho phép tạo các kiểu dữ liệu do người dùng định nghĩa. Để làm điều này, chỉ cần chỉ định một tên kiểu dữ liệu mới cho một kiểu dữ liệu đã tồn tại. Kiểu dữ liệu mới không được tạo ra. Thay vào đó, một tên mới cho kiểu hiện có được định nghĩa. Các kiểu do người dùng định nghĩa làm cho ứng dụng linh hoạt hơn: đôi khi, chỉ cần thay đổi các hướng dẫn typedef
bằng cách sử dụng macro thay thế (#define
). Các kiểu do người dùng định nghĩa cũng cải thiện khả năng đọc mã vì có thể áp dụng tên tùy chỉnh cho các kiểu dữ liệu chuẩn bằng cách sử dụng typedef
. Định dạng chung của mục nhập để tạo một kiểu do người dùng định nghĩa:
typedef type new_name;
Ở đây, type
có nghĩa là bất kỳ kiểu dữ liệu nào được chấp nhận, trong khi new_name
là tên mới của kiểu. Tên mới chỉ được đặt như một bổ sung (không phải thay thế) cho tên kiểu hiện có. MQL5 cho phép tạo con trỏ đến các hàm bằng cách sử dụng typedef
.
Con trỏ đến hàm
Con trỏ đến một hàm thường được định nghĩa theo định dạng sau:
typedef function_result_type (*Function_name_type)(list_of_input_parameters_types);
Nơi mà sau typedef
, chữ ký hàm (số lượng và kiểu của các tham số đầu vào, cũng như kiểu của kết quả mà hàm trả về) được thiết lập. Dưới đây là một ví dụ đơn giản về việc tạo và áp dụng một con trỏ đến hàm:
//--- khai báo một con trỏ đến hàm chấp nhận hai tham số int
typedef int (*TFunc)(int,int);
//--- TFunc là một kiểu, và có thể khai báo biến con trỏ đến hàm
TFunc func_ptr; // con trỏ đến hàm
//--- khai báo các hàm tương ứng với mô tả TFunc
int sub(int x,int y) { return(x-y); } // trừ một số khỏi số khác
int add(int x,int y) { return(x+y); } // cộng hai số
int neg(int x) { return(~x); } // đảo bit trong biến
//--- biến func_ptr có thể lưu trữ địa chỉ hàm để khai báo nó sau này
func_ptr=sub;
Print(func_ptr(10,5));
func_ptr=add;
Print(func_ptr(10,5));
func_ptr=neg; // lỗi: neg không có kiểu int (int,int)
Print(func_ptr(10)); // lỗi: cần hai tham số
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Trong ví dụ này, biến func_ptr
có thể nhận các hàm sub
và add
vì chúng có hai đầu vào, mỗi đầu vào thuộc kiểu int
như được định nghĩa trong con trỏ đến hàm TFunc
. Ngược lại, hàm neg
không thể được gán cho con trỏ func_ptr
vì chữ ký của nó khác.
Sắp xếp các mô hình sự kiện trong giao diện người dùng
Con trỏ đến các hàm cho phép bạn dễ dàng tạo xử lý sự kiện khi tạo giao diện người dùng. Hãy sử dụng một ví dụ từ phần CButton
để cho thấy cách tạo các nút và thêm các hàm xử lý việc nhấn vào chúng. Đầu tiên, định nghĩa một con trỏ đến hàm TAction
sẽ được gọi khi nhấn nút và tạo ba hàm theo mô tả TAction
.
//--- tạo một kiểu hàm tùy chỉnh
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//| Mở tệp |
//+------------------------------------------------------------------+
int Open(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(1);
}
//+------------------------------------------------------------------+
//| Lưu tệp |
//+------------------------------------------------------------------+
int Save(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(2);
}
//+------------------------------------------------------------------+
//| Đóng tệp |
//+------------------------------------------------------------------+
int Close(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(3);
}
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
Sau đó, tạo lớp MyButton
từ CButton
, nơi chúng ta nên thêm con trỏ đến hàm TAction
.
//+------------------------------------------------------------------+
//| Tạo lớp nút với hàm xử lý sự kiện |
//+------------------------------------------------------------------+
class MyButton: public CButton
{
private:
TAction m_action; // trình xử lý sự kiện biểu đồ
public:
MyButton(void){}
~MyButton(void){}
//--- hàm khởi tạo chỉ định văn bản nút và con trỏ đến hàm xử lý sự kiện
MyButton(string text, TAction act)
{
Text(text);
m_action=act;
}
//--- thiết lập hàm tùy chỉnh được gọi từ trình xử lý sự kiện OnEvent()
void SetAction(TAction act){m_action=act;}
//--- trình xử lý sự kiện biểu đồ tiêu chuẩn
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
{
if(m_action!=NULL && lparam==Id())
{
//--- gọi trình xử lý m_action() tùy chỉnh
m_action(sparam,(int)lparam);
return(true);
}
else
//--- trả về kết quả của việc gọi trình xử lý từ lớp cha CButton
return(CButton::OnEvent(id,lparam,dparam,sparam));
}
};
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
Tạo lớp dẫn xuất CControlsDialog
từ CAppDialog
, thêm mảng m_buttons
vào đó để lưu trữ các nút thuộc kiểu MyButton
, cũng như các phương thức AddButton(MyButton &button)
và CreateButtons()
.
//+------------------------------------------------------------------+
//| Lớp CControlsDialog |
//| Mục tiêu: bảng điều khiển đồ họa để quản lý ứng dụng |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
{
private:
CArrayObj m_buttons; // mảng nút
public:
CControlsDialog(void){};
~CControlsDialog(void){};
//--- tạo
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
//--- thêm nút
bool AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
//--- tạo các nút
bool CreateButtons(void);
};
//+------------------------------------------------------------------+
//| Tạo đối tượng CControlsDialog trên biểu đồ |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
return(CreateButtons());
//---
}
//+------------------------------------------------------------------+
//| định nghĩa |
//+------------------------------------------------------------------+
//--- khoảng cách và khoảng trống
#define INDENT_LEFT (11) // khoảng cách từ trái (bao gồm chiều rộng viền)
#define INDENT_TOP (11) // khoảng cách từ trên (bao gồm chiều rộng viền)
#define CONTROLS_GAP_X (5) // khoảng cách theo tọa độ X
#define CONTROLS_GAP_Y (5) // khoảng cách theo tọa độ Y
//--- cho các nút
#define BUTTON_WIDTH (100) // kích thước theo tọa độ X
#define BUTTON_HEIGHT (20) // kích thước theo tọa độ Y
//--- cho vùng chỉ thị
#define EDIT_HEIGHT (20) // kích thước theo tọa độ Y
//+------------------------------------------------------------------+
//| Tạo và thêm các nút vào bảng CControlsDialog |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
{
//--- tính toán tọa độ các nút
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2;
int y2=y1+BUTTON_HEIGHT;
//--- thêm các đối tượng nút cùng với con trỏ đến các hàm
AddButton(new MyButton("Open",Open));
AddButton(new MyButton("Save",Save));
AddButton(new MyButton("Close",Close));
//--- tạo các nút đồ họa
for(int i=0;i<m_buttons.Total();i++)
{
MyButton *b=(MyButton*)m_buttons.At(i);
x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
x2=x1+BUTTON_WIDTH;
if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
{
PrintFormat("Failed to create button %s %d",b.Text(),i);
return(false);
}
//--- thêm mỗi nút vào vùng chứa CControlsDialog
if(!Add(b))
return(false);
}
//--- thành công
return(true);
}
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
Bây giờ, chúng ta có thể phát triển chương trình sử dụng bảng điều khiển CControlsDialog
với 3 nút: Open, Save và Close. Khi nhấp vào một nút, hàm thích hợp dưới dạng con trỏ TAction
sẽ được gọi.
//--- khai báo đối tượng ở cấp độ toàn cục để tự động tạo nó khi khởi động chương trình
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Hàm khởi tạo Expert |
//+------------------------------------------------------------------+
int OnInit()
{
//--- bây giờ, tạo đối tượng trên biểu đồ
if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
return(INIT_FAILED);
//--- khởi động ứng dụng
MyDialog.Run();
//--- ứng dụng được khởi tạo thành công
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Hàm hủy khởi tạo Expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- hủy hộp thoại
MyDialog.Destroy(reason);
}
//+------------------------------------------------------------------+
//| Hàm xử lý sự kiện biểu đồ Expert |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // ID sự kiện
const long& lparam, // tham số sự kiện kiểu long
const double& dparam, // tham số sự kiện kiểu double
const string& sparam) // tham số sự kiện kiểu string
{
//--- gọi trình xử lý từ lớp cha (ở đây là CAppDialog) cho các sự kiện biểu đồ
MyDialog.ChartEvent(id,lparam,dparam,sparam);
}
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
Giao diện của ứng dụng đã khởi chạy và kết quả khi nhấp vào các nút được cung cấp trên ảnh chụp màn hình.
Mã nguồn đầy đủ của chương trình:
//+------------------------------------------------------------------+
//| Panel_Buttons.mq5 |
//| Copyright 2017, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property description "The panel with several CButton buttons"
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
//+------------------------------------------------------------------+
//| định nghĩa |
//+------------------------------------------------------------------+
//--- khoảng cách và khoảng trống
#define INDENT_LEFT (11) // khoảng cách từ trái (bao gồm chiều rộng viền)
#define INDENT_TOP (11) // khoảng cách từ trên (bao gồm chiều rộng viền)
#define CONTROLS_GAP_X (5) // khoảng cách theo tọa độ X
#define CONTROLS_GAP_Y (5) // khoảng cách theo tọa độ Y
//--- cho các nút
#define BUTTON_WIDTH (100) // kích thước theo tọa độ X
#define BUTTON_HEIGHT (20) // kích thước theo tọa độ Y
//--- cho vùng chỉ thị
#define EDIT_HEIGHT (20) // kích thước theo tọa độ Y
//--- tạo kiểu hàm tùy chỉnh
typedef int(*TAction)(string,int);
//+------------------------------------------------------------------+
//| Mở tệp |
//+------------------------------------------------------------------+
int Open(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(1);
}
//+------------------------------------------------------------------+
//| Lưu tệp |
//+------------------------------------------------------------------+
int Save(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(2);
}
//+------------------------------------------------------------------+
//| Đóng tệp |
//+------------------------------------------------------------------+
int Close(string name,int id)
{
PrintFormat("%s function called (name=%s id=%d)",__FUNCTION__,name,id);
return(3);
}
//+------------------------------------------------------------------+
//| Tạo lớp nút với hàm xử lý sự kiện |
//+------------------------------------------------------------------+
class MyButton: public CButton
{
private:
TAction m_action; // trình xử lý sự kiện biểu đồ
public:
MyButton(void){}
~MyButton(void){}
//--- hàm khởi tạo chỉ định văn bản nút và con trỏ đến hàm xử lý sự kiện
MyButton(string text,TAction act)
{
Text(text);
m_action=act;
}
//--- thiết lập hàm tùy chỉnh được gọi từ trình xử lý sự kiện OnEvent()
void SetAction(TAction act){m_action=act;}
//--- trình xử lý sự kiện biểu đồ tiêu chuẩn
virtual bool OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) override
{
if(m_action!=NULL && lparam==Id())
{
//--- gọi trình xử lý tùy chỉnh
m_action(sparam,(int)lparam);
return(true);
}
else
//--- trả về kết quả của việc gọi trình xử lý từ lớp cha CButton
return(CButton::OnEvent(id,lparam,dparam,sparam));
}
};
//+------------------------------------------------------------------+
//| Lớp CControlsDialog |
//| Mục tiêu: bảng điều khiển đồ họa để quản lý ứng dụng |
//+------------------------------------------------------------------+
class CControlsDialog : public CAppDialog
{
private:
CArrayObj m_buttons; // mảng nút
public:
CControlsDialog(void){};
~CControlsDialog(void){};
//--- tạo
virtual bool Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2) override;
//--- thêm nút
bool AddButton(MyButton &button){return(m_buttons.Add(GetPointer(button)));m_buttons.Sort();};
protected:
//--- tạo các nút
bool CreateButtons(void);
};
//+------------------------------------------------------------------+
//| Tạo đối tượng CControlsDialog trên biểu đồ |
//+------------------------------------------------------------------+
bool CControlsDialog::Create(const long chart,const string name,const int subwin,const int x1,const int y1,const int x2,const int y2)
{
if(!CAppDialog::Create(chart,name,subwin,x1,y1,x2,y2))
return(false);
return(CreateButtons());
//---
}
//+------------------------------------------------------------------+
//| Tạo và thêm các nút vào bảng CControlsDialog |
//+------------------------------------------------------------------+
bool CControlsDialog::CreateButtons(void)
{
//--- tính toán tọa độ các nút
int x1=INDENT_LEFT;
int y1=INDENT_TOP+(EDIT_HEIGHT+CONTROLS_GAP_Y);
int x2;
int y2=y1+BUTTON_HEIGHT;
//--- thêm các đối tượng nút cùng với con trỏ đến các hàm
AddButton(new MyButton("Open",Open));
AddButton(new MyButton("Save",Save));
AddButton(new MyButton("Close",Close));
//--- tạo các nút đồ họa
for(int i=0;i<m_buttons.Total();i++)
{
MyButton *b=(MyButton*)m_buttons.At(i);
x1=INDENT_LEFT+i*(BUTTON_WIDTH+CONTROLS_GAP_X);
x2=x1+BUTTON_WIDTH;
if(!b.Create(m_chart_id,m_name+"bt"+b.Text(),m_subwin,x1,y1,x2,y2))
{
PrintFormat("Failed to create button %s %d",b.Text(),i);
return(false);
}
//--- thêm mỗi nút vào vùng chứa CControlsDialog
if(!Add(b))
return(false);
}
//--- thành công
return(true);
}
//--- khai báo đối tượng ở cấp độ toàn cục để tự động tạo nó khi khởi động chương trình
CControlsDialog MyDialog;
//+------------------------------------------------------------------+
//| Hàm khởi tạo Expert |
//+------------------------------------------------------------------+
int OnInit()
{
//--- bây giờ, tạo đối tượng trên biểu đồ
if(!MyDialog.Create(0,"Controls",0,40,40,380,344))
return(INIT_FAILED);
//--- khởi động ứng dụng
MyDialog.Run();
//--- ứng dụng được khởi tạo thành công
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Hàm hủy khởi tạo Expert |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- hủy hộp thoại
MyDialog.Destroy(reason);
}
//+------------------------------------------------------------------+
//| Hàm xử lý sự kiện biểu đồ Expert |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, // ID sự kiện
const long& lparam, // tham số sự kiện kiểu long
const double& dparam, // tham số sự kiện kiểu double
const string& sparam) // tham số sự kiện kiểu string
{
//--- gọi trình xử lý từ lớp cha (ở đây là CAppDialog) cho các sự kiện biểu đồ
MyDialog.ChartEvent(id,lparam,dparam,sparam);
}
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
Xem thêm