注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

jasonyang9的博客

随便写写

 
 
 

日志

 
 

(怀旧系列)VC程序设计(孙鑫老师)听课笔记:07 对话框 1  

2013-01-13 20:24:35|  分类: programming |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
(怀旧系列)VC程序设计(孙鑫老师)听课笔记:07 对话框 1 - jasonyang9 - jasonyang9的博客
 
======
对话框
======

通过在资源管理器中插入对话框资源来建立对话框,对话框也是一个窗口,对应的是CDialog类,从CWnd派生,分为Modal(模态)和Modeless(非模态)两种类型,Modal对话框必须在用户关闭对话框后才能返回应用程序,Modeless可以在显示对话框的同时交互操作应用程序。
MFC中需要创建对话框类去和对话框资源相关联,双击对话框资源,创建对话框类。选择基类和对应的对话框资源ID号,为对话框类取名,同时可以更改源代码文件名(如果类名太长的话,改用较短的文件名)。
ClassWizard生成的源代码类似:

// 头文件
class CXXXDlg : public CDialog
{
// Construction
public:
CXXXDlg(CWnd* pParent = NULL); // standard constructor

// Dialog Data
//{{AFX_DATA(CXXXDlg)
enum ( IDD = IDD_DIALOG1 );
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CXXXDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDY support
//}}AFX_VIRTUAL

// Implementation
protected:

// Generated message map functions
//{{AFX_MSG(CXXXDlg)
// NOTE: the ClassWizard will add member functions here
//}}AFX_MSG
...
};

// 源文件
CXXXDlg::CXXXDlg(CWnd* pParent /*=NULL*/) // CXXXDlg的构造函数
: CDialog(CXXXDlg::IDD, pParent) // 这里的CXXXDlg::IDD定义在头文件中,是对话框资源的ID号(如IDD_DIALOG1)
{
//{{AFX_DATA_INIT(CXXXDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
}

void CXXXDlg::DoDataExchange(CDataExchange* pDX) // 完成对话框数据的交换和校验
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CXXXDlg)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CXXXDlg, CDialog)
//{{AFX_MSG_MAP(CXXXDlg)
// NOTE: the ClassWizard will add message map macros here
//}}AFX_MSG_MAP
END_MESSAGE_MAP()


在工程中增加菜单项,设定ID为IDM_DIALOG,用ClassWizard增加消息处理函数OnDialog(),编辑代码:

#include "CXXXDlg.h" // 包含该对话框的头文件

void CXXXView::OnDialog() // 在View类中处理该消息
{
CXXXDlg dlg; // 生成dlg对象
dlg.DoModal(); // 调用DoModal()函数产生模态对话框(直到该对话框结束后此函数才会返回)
}


非模态对话框:

Class CXXXView : public CView
{
...
CXXXDlg m_dlg; // 定义为成员变量
}

void CXXXView::OnDialog()
{
// CXXXDlg dlg; // 注意:非模态对话框不能定义成局部变量,因为ShowWindow()函数会立即返回,当局部变量生命周期结束时,对象被销毁,对话框无法显示
// 要将对象定义为成员变量;或者定义为指针,在堆上分配内存,和整个程序的生命周期一致,但也必须将此指针定义为成员变量,并在析构函数中删除(释放内存)

CXXXDlg *pDlg = new CXXXDlg(); // 定义为指针
dlg->Create(IDD_DIALOG1, this); // 用Create()函数创建非模态对话框
dlg->ShowWindow(SW_SHOW); // 用ShowWindow()函数显示对话框 
}


对于模态对话框,退出后对话框被销毁;对于非模态对话框,退出后对话框只是被隐藏(覆盖CDialog::OnOK()虚函数,调用DestroyWindow()函数销毁对话框;否则只会隐藏对话框)

在对话框上增加命令按钮:用资源编辑器实现增加按钮,赋予ID号,用ClassWizard增加通告消息响应函数,编辑代码。

// 点击ADD按钮时动态增加一个按钮,再按一次删除按钮

// 增加成员变量
CButton m_btn; // 创建成员变量(CButton类对象m_btn)

CXXXDlg::CXXXDlg()
{
...
m_bIsCreated = FALSE; // 初始化m_bIsCreated为FALSE
}

void CXXXDlg::OnBtnAdd()
{
if (!m_btn.m_hWnd) // 如果不进行判断(通过m_btn的m_hWnd句柄),则在第二次按下ADD按钮后产生错误(重复创建)
{
m_btn.Create("维新", // 创建按钮,名称“维新”
BS_DEFPUSHBUTTON | WS_VISIBLE | WS_CHILD, // 按钮类型BS_DEFPUSHBUTTON(默认按钮)、窗口类型WS_VISIBLE(创建后立即显示)、WS_CHILD(子窗口)
CRect(0, 0, 100, 100), // 按钮位置和尺寸
this, // 按钮的父窗口
123); // 按钮的ID号
}
else
{
m_btn.DestroyWindow(); // 销毁按钮(通过DestroyWindow函数)
}

}


静态控件(Static)、编辑框控件(EditBox)以及控件的对齐等操作。
静态控件默认的ID号为IDC_STATIC,不能增加消息处理函数,除非自定义为其他ID,再用ClassWizard增加BN_CLICKED消息。

void CXXXDlg::OnNumber1()
{
// GetWindowText()返回的是对话框的文本,不符合要求
// 为了获取静态控件的文本,首先要获取静态控件的指针(用GetDlgItem函数)
CString str;
if (GetDlgItem(IDC_NUMBER1)->GetWindowText(str), str == "Number1:") // 注意:这里采用逗号表达式,整个表达式的值是逗号后的值,即判断str是否等于“Number1:”
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("数值1:"); // 如果是“Number1:”,则将该静态控件的文本改为“数值1:”
}
else
{
GetDlgItem(IDC_NUMBER1)->SetWindowText("Number1:"); // 否则改回“Number1:”
}
}

但是,该静态控件必须具有Notify属性,以便响应命令点击事件,可用资源编辑器设置。
(一般,静态控件不应响应命令点击事件和改变文本)

在对话框上添加3个编辑控件IDC_EDIT1、IDC_EDIT2和IDC_EDIT3,在ADD按钮按下后,将IDC_EDIT1和IDC_EDIT2中的数值相加,放到IDC_EDIT3中显示。

第1种访问控件的方式:用GetDlgItem和GetWindowText、SetWindowText函数

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3; // 定义3个整形变量
char ch1[10], ch2[10], ch3[10]; // 定义3个字符数组

GetDlgItem(IDC_EDIT1)->GetWindowText(ch1, 10); // 获取IDC_EDIT1中的文本到ch1,最多取10位
GetDlgItem(IDC_EDIT2)->GetWindowText(ch2, 10); // IDC_EDIT2
num1 = atoi(ch1); // 转换ch1为数值
num2 = atoi(ch2); // ch2
num3 = num1 + num2; // 相加
itoa(num3, ch3, 10); // 转换num3为字符串,以10进制转换
GetDlgItem(IDC_EDIT3)->SetWindowText(ch3); // 设置IDC_EDIT3的文本
}


第2种访问控件的方式:用GetDlgItemText和SetDlgItemText函数

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];

GetDlgItemText(IDC_EDIT1, ch1, 10); // 获取IDC_EDIT1的文字到ch1,最多10位
GetDlgItemText(IDC_EDIT2, ch2, 10); // IDC_EDIT2
num1 = atoi(ch1); // 转换ch1为数值
num2 = atoi(ch2); // ch2
num3 = num1 + num2; // 相加
itoa(num3, ch3, 10); // 转换num3为字符串,以10进制转换
SetDlgItemText(IDC_EDIT3, ch3); // 设置IDC_EDIT3的文本
}


第3种访问控件的方式:用GetDlgItemInt和SetDlgItemInt函数

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3;

num1 = GetDlgItemInt(IDC_EDIT1); // 获取IDC_EDIT1的文字并直接转换为数值
num2 = GetDlgItemInt(IDC_EDIT2); // IDC_EDIT2
num3 = num1 + num2; // 相加
SetDlgItemInt(IDC_EDIT3, num3); // 设置为IDC_EDIT3的文字
}

用ClassWizard为IDC_EDIT1、IDC_EDIT2和IDC_EDIT3增加变量(关联)。

// 在ClassWizard的Member Variables标签页中操作,代码中增加内容有:

// CXXXDlg.h
class CXXXDlg : public CDialog
{
...
//Dialog Data
//{{AFX_DATA(CXXXDlg)
...
int m_num1; // 在AFX_DATA注释宏之间增加成员变量
int m_num2;
int m_num3;
//}}AFX_DATA
...
};

// CXXXDlg.cpp
CXXXDlg::CXXXDlg(CWnd* pParent /*=NULL*/)
:CDialog(CXXXDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CXXXDlg)
m_num1 = 0; // 在构造函数的AFX_DATA_INIT注释宏之间增加初始化操作
m_num2 = 0;
m_num3 = 0;
//}}AFX_DATA_INIT
...
}

void CXXXDlg::DoDataExchange(CDataExchange* pDX) // 被框架调用(具体来说是CWnd::UpdateData函数,而不要直接调用DoDataExchange),交换和校验对话框的数据
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CXXXDlg)
DDX_Text(pDX, IDC_EDIT1, m_num1); // 用DDX_Text将控件和成员变量关联
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDX_Text(pDX, IDC_EDIT3, m_num3);
//}}AFX_DATA_MAP
}

// DDX_?????函数很多,针对不同的控件有不同的DDX函数,将控件和成员变量关联


第4种访问控件的方式:将控件和整形变量相关联,然后用UpdateData()函数初始化和获取对话框控件的数据

void CXXXDlg::OnBtnAdd()
{
UpdateData(TRUE); // 用UpdateData(TRUE)来获取对话框控件的数据,系统会在模态对话框初始化时自动调用UpdateData(FALSE)来初始化对话框控件
m_num3 = m_num1 + m_num2; // 相加
UpdateData(FALSE); // 将成员变量的值赋给对话框控件
}


在IDC_EDIT1编辑框中输入字母,程序会弹出警告,让用户输入整数,这种功能是由DDV(对话框数据校验)实现的。DDV还可以限制输入数据的范围(最小值和最大值)。
用ClassWizard增加DDV功能(在Member Variables标签页中点击控件ID后在Minimum Value:和Maximum Value:中填写最小值和最大值)。

// VC增加的代码
void CXXXDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CXXXDlg)
DDX_Text(pDX, IDC_EDIT1, m_num1);
DDV_MinMaxInt(pDX, m_num1, 0, 100); // DDV函数,和DDX函数一样,有很多,其中的DDV_MinMaxInt用来限制输入整形数的范围
DDX_Text(pDX, IDC_EDIT2, m_num2);
DDV_MinMaxInt(pDX, m_num2, 0, 100);
DDX_Text(pDX, IDC_EDIT3, m_num3);
//}}AFX_DATA_MAP
}


关联控件和某个控件变量:在ClassWizard的Member Variables标签页中,选择IDC_EDIT1控件,单击Add Variable...按钮,填写控件名称,选择Category为Control,Variable Type只能是CEdit。对IDC_EDIT2和IDC_EDIT3同样操作。

// VC增加的代码
// CXXXDlg.h
class CXXXDlg : public CDialog
{
...
CEdit m_edit3; // 增加的3个控件类型成员变量
CEdit m_edit2;
CEdit m_edit1;
...
};

// CXXXDlg.cpp
void CXXXDlg::DoDataExchange(CDataExchange* pDX)
{
...
DDX_Control(pDX, IDC_EDIT3, m_edit3); // 增加的3个DDX_Control函数,关联控件和控件变量
DDX_Control(pDX, IDC_EDIT2, m_edit2);
DDX_Control(pDX, IDC_EDIT1, m_edit1);
...
}

第5种访问控件的方式:将控件和控件变量相关联,再用控件变量的GetWindowText和SetWindowText成员函数

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];

m_edit1.GetWindowText(ch1, 10); // 直接调用控件变量的GetWindowText函数获取文本
m_edit2.GetWindowText(ch2, 10);

num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
itoa(num3, ch3, 10);

m_edit3.SetWindowText(ch3); // 直接调用控件变量的SetWindowText函数设置文本
}


第6种访问控件的方式:通过SendMessage函数发送消息

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];

::SendMessage(GetDlgItem(IDC_EDIT1)->m_hWnd, // 调用API函数SendMessage发送消息给IDC_EDIT1控件的m_nWnd窗口句柄
WM_GETTEXT, // 发送WM_GETTEXT消息
10, // 获取10位文本
(LPARAM)ch1); // 获取到ch1(需要强制类型转换)

::SendMessage(m_edit2.m_hWnd, // 用关联的控件m_edit2来获取其窗口句柄
WM_GETTEXT,
10,
(LPARAM)ch2);

// GetDlgItem(IDC_EDIT1)->SendMessage(WM_GETTEXT, // 或者用控件的SendMessage函数来发送消息
10,
(LPARAM)ch1);

// m_edit2.SendMessage(WM_GETTEXT, 10, (LPARAM)ch2); // 或者用关联的控件来直接调用SendMessage函数发送消息

num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
itoa(num3, ch3, 10);

m_edit3.SendMessage(WM_SETTEXT, 0, (LPARAM)ch3); // 用消息WM_SETTEXT来设置文本(WPARAM参数必须为0)
}

第7种访问控件的方式:通过SendDlgItemMessage函数给对话框子控件发送消息

void CXXXDlg::OnBtnAdd()
{
int num1, num2, num3;
char ch1[10], ch2[10], ch3[10];

SendDlgItemMessage(IDC_EDIT1, // SendDlgItemMessage将GetDlgItem和SendMessage两个函数组合在一起,指定控件ID
WM_GETTEXT, // 发送WM_GETTEXT消息
10, // 获取10位文本
(LPARAM)ch1); // 获取到ch1(需要强制类型转换)

// 注意SendDlgItemMessage是由对话框调用,发送消息给子控件,不可先用GetDlgItem获取控件指针后调用

SendDlgItemMessage(IDC_EDIT2,
WM_GETTEXT,
10,
(LPARAM)ch2);

num1 = atoi(ch1);
num2 = atoi(ch2);
num3 = num1 + num2;
itoa(num3, ch3, 10);

SendDlgItemMessage(IDC_EDIT3,
WM_SETTEXT,
0,
(LPARAM)ch3);
}


关于CEdit控件的EM_GETSEL和EM_SETSEL消息:

// 可以用EM_SETSEL消息来复选需要的内容
SendDlgItemMessage(IDC_EDIT3, EM_SETSEL, 1, 3); // 复选IDC_EDIT3控件的第1个到第3个字符
// SendDlgItemMessage(IDC_EDIT3, EM_SETSEL, 0, -1); // 表示将IDC_EDIT3控件的全部文本复选
m_edit3.SetFocus(); // 将输入焦点设置到IDC_EDIT3控件上,否则复选效果无法看到


对话框的收缩与扩展:

// 增加一个图像控件,将其ID改为ID_SEPARATOR(分割器),类型选中Sunken,拉成一横条,其下部会在收缩时切除,扩展时还原

// 增加一个按钮,取名“收缩<<”,ID为IDC_BUTTON2,双击按钮,增加消息(BN_CLICKED)的处理函数
void CXXXDlg::OnButton2()
{
CString str;
if (GetDlgItemText(IDC_BUTTON2, str), str == "收缩<<") // 获取IDC_BUTTON2的文字并判断是否为“收缩<<”(注意逗号表达式)
{
SetDlgItemText(IDC_BUTTON2, "扩展>>"); // 如果是,则改为“扩展>>”
}
else
{
SetDlgItemText(IDC_BUTTON2, "收缩<<"); // 否则改回“收缩<<”
}

static CRect rectLarge; // 扩展后对话框的尺寸(需要定义为成员变量或静态变量)
static CRect rectSmall; // 收缩后对话框的尺寸

if (rectLarge.IsRectNull()) // 判断矩形是否为空(NULL),据以确定是否第一次调用(static变量初始化为0?)
{
CRect rectSeparator;
GetWindowRect(&rectLarge); // 获取对话框原始矩形区域
GetDlgItem(IDC_SEPARATOR)->GetWindowRect(&rectSeparator); // 获取“分割器”的矩形区域

rectSmall.left = rectLarge.left; // 收缩后的矩形区域和同扩展后的矩形区域left相同
rectSmall.top = rectLarge.top; // top相同
rectSmall.right = rectLarge.right; // right相同
rectSmall.bottom = rectSeparator.bottom; // bottom取“分割器”的bottom
}

if (str == "收缩<<")
{
SetWindowPos(NULL, // 不设置给定窗口的句柄,不改变Z次序
0, // X坐标为0,由于之后的SWP_NOMOVE会忽略此参数
0, // Y坐标为0,同上
rectSmall.Width(), // 用CRect::Width()获取矩形区域的宽度
rectSmall.Height(), // 用CRect::Height()获取矩形区域的高度
SWP_NOMOVE | SWP_NOZORDER); // SWP_NOMOVE忽略X和Y坐标,SWP_NOZORDER忽略给定的窗口句柄,即不改变Z次序
}
else
{
SetWindowPos(NULL,
0,
0,
rectLarge.Width(), // 同上,但这里取rectLarge的矩形区域
rectLarge.Height(),
SWP_NOMOVE | SWP_NOZORDER);
}
}


关于窗口的Z-order(Z次序):
窗口的Z次序表明了重叠窗口堆中窗口的位置,这个窗口堆是按一个假想的轴定位的,这个轴就是从屏幕向外伸展的Z轴。Z次序最上面的窗口覆盖所有其他的窗口,Z次序最下面的窗口被所有其他的窗口覆盖。应用程序设置窗口在Z次序中的位置是通过把它放在一个给定窗口的后面,或是放在窗口堆的顶部或底部。
Windows系统管理3个独立的Z次序——一个用于顶层窗口、一个用于兄弟窗口,还有一个用于最顶层窗口。最顶层窗口覆盖所有其他非最顶层窗口,而不论它是不是活动窗口或前台窗口。应用程序通过设置WS_EX_TOPMOST风格创建最顶层窗口。
一般情况下,Windows系统把刚刚创建的窗口放在Z次序的顶部,用户可通过激活另外一个窗口来改变Z次序;Windows系统总是把活动窗口放在Z次序的顶部,应用程序可用函数BringWindowToTop把一个窗口放置到Z次序的顶部。函数SetWindowPos和DeferWindowPos用来重排Z次序。

兄弟窗口:共享同一个父窗口的多个子窗口。
活动窗口:是应用程序的顶层窗口,也就是当前使用的窗口。只有一个顶层窗口可以是活动窗口,如果用户使用的是一个子窗口,Windows系统就激活和这个子窗口相应的顶层窗口。任何时候系统中只能有一个顶层窗口是活动的。用户通过单击窗口(或其中的一个子窗口)、使用ALT+TAB或ALT+ESC组合键来激活一个顶层窗口,应用程序则调用函数SetActiveWindow来激活一个顶层窗口。
前台窗口和后台窗口:在Windows系统中,每一个进程可运行多个线程,每个线程都能创建窗口。创建正在使用窗口的线程称为前台线程,这个窗口就称为前台窗口。所有其他线程都是后台线程,由后台线程所创建的窗口称为后台窗口。用户通过单击一个窗口、使用ALT+TAB或ALT+ESC组合键来设置前台窗口,应用程序则用函数SetForegroundWindow设置前台窗口。如果新的前台窗口是一个顶层窗口,那么Windows系统就激活它,即Windows系统激活相应的顶层窗口。

关于“缺省”按钮:按钮控件可以设置为Default button样式,当用户按下回车,就由缺省按钮响应。

// 在CXXXDlg中覆盖基类的OnOK函数(用ClassWizard等操作)
void CXXXDlg::OnOK()
{
// CDialog::OnOK(); // 注释掉基类的OnOK(但如此一来,按下OK按钮也无法退出对话框)
}


在控件之间移动输入焦点,通过修改控件的窗口过程来实现:(不推荐这种修改方式!和用户对界面控件的动作预期不符!)

// 首先在资源编辑器中将IDC_EDIT1的Multiline属性勾选,否则该控件不处理回车消息

LRESULT CALLBACK WinSunProc( // WindowProc的写法可以通过MSDN查找
HWND hwnd; // handle to window
UINT uMsg; // message identifier
WPARAM wParam; // first message parameter
LPARAM lParam; // second message parameter
}
{
if (uMsg == WM_CHAR && wParam == 0x0d) // 如果输入的是回车
{
::SetFocus(::GetNextWindow(hwnd, GW_HWNDNEXT)); // 将焦点设置到下一个控件(注意:在全局函数中只能调用全局的Win32 API函数,而不是CWnd成员函数)
// SetFocus(::GetWindow(hwnd, GW_HWNDNEXT)); // 用GetWindow函数
SetFocus(::GetNextDlgTabItem(::GetParent(hwnd), hwnd, FALSE)); // 用GetNextDlgTabItem函数,注意:第一个参数是对话框的hwnd句柄,要用GetParent获取控件的父窗口(即对话框)
return 1; // 返回1,表示已处理消息
}
else
{
return prevProc(hwnd, uMsg, wParam, lParam); // 让该控件原来的窗口过程来处理
}
}

// 定义窗口过程类型,用于保存被替换的窗口过程函数指针
WNDPROC prevProc;

// 处理WM_INITDIALOG消息,WM_INITDIALOG消息在对话框显示之前被发送到该对话框(注意:在OnCreate函数中对话框控件还没有产生,当时的窗口指针为空)
BOOL CXXXDlg::OnInitDialog()
{
CDialog::OnInitDialog();

prevProc = (WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_nWnd, // 调用SetWindowLong来设置新的IDC_EDIT1控件的窗口过程函数,SetWindowLong返回一个LONG型,需要用(WNDPROC)强制转换
GWL_WNDPROC, // 表示要设置的是窗口过程函数
(LONG)WinSunProc); // 新的窗口过程函数(函数名代表函数首地址、函数指针,SetWindowLong函数的第3个参数是LONG型,这里需要用(LONG)强制转换)
}


以上这种用修改控件窗口过程来切换焦点的方法很不方便,需要对每个控件操作,可以通过修改OnOK函数来实现按回车后移动焦点:

void CXXXDlg::OnOK()
{
// 获取当前具有焦点的控件,获取下一个控件,并设置焦点
// GetFocus()->GetNextWindow()->SetFocus(); // 注意:GetNextWindow和GetWindow(GW_HWNDNEXT)在遇到最后一个控件时返回NULL
GetNextDlgTabItem(GetFocus())->SetFocus(); // 只有GetNextDlgTabItem能够在具有Tab Stop属性的控件之间按顺序依次循环
}


Tab顺序可通过资源编辑器的Layout菜单下的Tab Order命令来显示和调整。

无论OK按钮是否存在,只要有OnOK函数(并且消息路由正常),其都会处理消息(?)。注意:默认的OK按钮ID号为IDOK,而不是IDC_OK。如果要自行增加OK按钮,ID号应写为IDOK。

  评论这张
 
阅读(273)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017