精华内容
下载资源
问答
  • 在Dev-C++ 5.11上创建并正常运行,操作系统32位、64位Win7均可。首先在文件菜单里新建项目,选择Windows Application,命名完成后得到程序框架。最后在代码中添加上控件和对应的事件即可。

    先看一下程序的效果图:

     在Dev-C++ 5.11上创建并正常运行,操作系统32位、64位的Win7都可以。

    首先在文件菜单里新建项目,选择Windows Application:

    命名完成后得到如下程序框架:

    #include <windows.h>
    
    /* This is where all the input to the window goes to */
    LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
    	switch(Message) {
    		
    		/* Upon destruction, tell the main thread to stop */
    		case WM_DESTROY: {
    			PostQuitMessage(0);
    			break;
    		}
    		
    		/* All other messages (a lot of them) are processed using default procedures */
    		default:
    			return DefWindowProc(hwnd, Message, wParam, lParam);
    	}
    	return 0;
    }
    
    /* The 'main' function of Win32 GUI programs: this is where execution starts */
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    	WNDCLASSEX wc; /* A properties struct of our window */
    	HWND hwnd; /* A 'HANDLE', hence the H, or a pointer to our window */
    	MSG msg; /* A temporary location for all messages */
    
    	/* zero out the struct and set the stuff we want to modify */
    	memset(&wc,0,sizeof(wc));
    	wc.cbSize		 = sizeof(WNDCLASSEX);
    	wc.lpfnWndProc	 = WndProc; /* This is where we will send messages to */
    	wc.hInstance	 = hInstance;
    	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
    	
    	/* White, COLOR_WINDOW is just a #define for a system color, try Ctrl+Clicking it */
    	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    	wc.lpszClassName = "WindowClass";
    	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION); /* Load a standard icon */
    	wc.hIconSm		 = LoadIcon(NULL, IDI_APPLICATION); /* use the name "A" to use the project icon */
    
    	if(!RegisterClassEx(&wc)) {
    		MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    		return 0;
    	}
    
    	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,"WindowClass","Caption",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
    		CW_USEDEFAULT, /* x */
    		CW_USEDEFAULT, /* y */
    		640, /* width */
    		480, /* height */
    		NULL,NULL,hInstance,NULL);
    
    	if(hwnd == NULL) {
    		MessageBox(NULL, "Window Creation Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    		return 0;
    	}
    
    	/*
    		This is the heart of our program where all input is processed and 
    		sent to WndProc. Note that GetMessage blocks code flow until it receives something, so
    		this loop will not produce unreasonably high CPU usage
    	*/
    	while(GetMessage(&msg, NULL, 0, 0) > 0) { /* If no error is received... */
    		TranslateMessage(&msg); /* Translate key codes to chars if present */
    		DispatchMessage(&msg); /* Send it to WndProc */
    	}
    	return msg.wParam;
    }

     在此基础上,随便找些WINAPI函数插进源码框架,正好来练一练:

    #include <windows.h>
    #include <cstring>
    #include <string>
    using namespace std;
     
    LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
     
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    	WNDCLASSEX wc;
    	HWND hwnd, hwndDT;
    	MSG msg;
    	RECT rect;
    	int dtWidth,dtHeight;
     
    	memset(&wc,0,sizeof(wc));
    	wc.cbSize		 = sizeof(WNDCLASSEX);
    	wc.lpfnWndProc	 = WndProc;
    	wc.hInstance	 = hInstance;
    	wc.hCursor		 = LoadCursor(NULL, IDC_ARROW);
    	
    	wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    	wc.lpszClassName = "WindowClass";
    	wc.hIcon		 = LoadIcon(NULL, IDI_APPLICATION);
    	wc.hIconSm		 = LoadIcon(NULL, IDI_APPLICATION);
     
    	if(!RegisterClassEx(&wc)) {
    		MessageBox(NULL, "Window Registration Failed!","Error!",MB_ICONEXCLAMATION|MB_OK);
    		return 0;
    	}
     
    	hwndDT=GetDesktopWindow(); //取桌面句柄 
    	GetWindowRect(hwndDT,&rect); //取桌面范围 
    	dtWidth=rect.right-rect.left; //桌面宽度 
    	dtHeight=rect.bottom-rect.top; //桌面高度 
    	
    	hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,wc.lpszClassName,
    		"First Windows Appliction",WS_VISIBLE|WS_OVERLAPPEDWINDOW,
    		(dtWidth-640)/2,   /*窗体居中*/ 
    		(dtHeight-480)/2,
    		640,
    		480,
    		NULL,NULL,hInstance,NULL);
    	//MoveWindow(hwnd, (width-640)/2, (height-480)/2, 640, 480, FALSE);
         
    	if(hwnd == NULL) {
    		MessageBox(NULL, "Window Creation Failed!","Error!", MB_ICONEXCLAMATION|MB_OK);
    		return 0;
    	}
     
    	while(GetMessage(&msg, NULL, 0, 0) > 0) { 
    		TranslateMessage(&msg);
    		DispatchMessage(&msg);
    	}
     
    	return msg.wParam;
    }
     
    LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
    	HDC         	hdc;
    	PAINTSTRUCT 	ps;
    	RECT			rect;
    	POINT			mouse;
    	static int  	cxChar, cyChar;
    	static int  	mX, mY;
    	static HWND 	hwndButton;
    	static HWND 	hwndEditbox;
    	string			strXy;
    	char			x[5], y[5];
    	char			buff[4096] = {0};
    	const int		IDcmdButton = 1;
    	const int		IDeditBox = 2;
    	
    	cxChar = LOWORD(GetDialogBaseUnits());
    	cyChar = HIWORD(GetDialogBaseUnits());
         
    	switch (message) {
    		case WM_CREATE:
    			hwndButton = CreateWindow ( TEXT("button"), TEXT("Command Button"),
                                			WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
                                       		cxChar * 6, cyChar * 15,
                                       		30 * cxChar, 2.5 * cyChar,
                                       		hwnd, (HMENU)IDcmdButton, ((LPCREATESTRUCT) lParam)->hInstance, NULL);
    			if (!hwndButton) MessageBox(NULL,"创建按钮失败","Message",MB_OK|MB_ICONERROR);
    			ShowWindow(hwndButton,SW_SHOW);
                UpdateWindow(hwndButton);
    				
                hwndEditbox = CreateWindow( TEXT("edit"),NULL,
    										WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE,
                                       		cxChar * 31, cyChar * 0.5,
                                       		30 * cxChar, 9.5 * cyChar,
    										hwnd,(HMENU)IDeditBox,NULL,NULL);
    										
    			if (!hwndEditbox) MessageBox(NULL,"创建文本框失败","Message",MB_OK|MB_ICONERROR);
    			ShowWindow(hwndEditbox,SW_SHOW);
                UpdateWindow(hwndEditbox);
            	return 0 ;
    	          
    	    case WM_PAINT:
    			hdc = BeginPaint (hwnd, &ps);
    	    	SetRect(&rect, 10, 10, 300, 200);
        	    FrameRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
    			GetClientRect (hwnd, &rect);
    			rect.left += 20;
                rect.top += 2;
                //SetTextColor(hdc, RGB(255,0,0)); //可以用RGB三原色设置文本颜色
    			DrawText(hdc, TEXT(" Hello, Dev-C++! "), -1, &rect, DT_SINGLELINE | DT_TOP | DT_LEFT);
    			EndPaint(hwnd, &ps);
    			return 0;
     
    	    case WM_SIZE:
    			//GetWindowRect(hwnd, &rect);
    			//MoveWindow(hwndButton, (rect.right-rect.left)/2 - 15*cxChar ,\
    			//(rect.bottom-rect.top)/2 - 1.25*cxChar, 30*cxChar, 2.5*cyChar, FALSE);
    			return 0;
    			
    		case WM_COMMAND:
    			//各控件的_click()事件 
    			switch (LOWORD(wParam)) {
    			case 0:
    				PostQuitMessage(0);
    				break;
    			case IDcmdButton: 
    				GetWindowText(hwndEditbox,buff,100);
    				if (buff[0])
    					MessageBox(NULL, buff, "ComandButton_Click()", MB_OK);
    				else
    					MessageBox(NULL, "激发ComandButton_Click()事件", "命令按钮", MB_ICONASTERISK);
    				break;
    			case IDeditBox:
    				GetWindowText(hwndEditbox,buff,4096);
    				break;
    			}
    			return 0; 
    
    		case WM_LBUTTONDOWN: // WM_LBUTTONDOWN是鼠标左键按下的事件
    			GetCursorPos(&mouse);
    			GetWindowRect(hwnd, &rect);
    			mX=mouse.x-rect.left;
    			mY=mouse.y-rect.top;
    			itoa(mX,x,10);
    			itoa(mY,y,10);
    			strXy="鼠标点击的窗体内坐标:("+string(x)+","+string(y)+")";
    			SetWindowText(hwndEditbox,strXy.c_str());
    			//MessageBox(NULL, strXy.c_str(), "", MB_ICONASTERISK);
    			return 0;
    
    		case WM_CLOSE:
    			if (IDYES==MessageBox(hwnd, "是否真的要退出?", "确认", MB_ICONQUESTION | MB_YESNO))
    				DestroyWindow(hwnd);  //销毁窗口
    			return 0;
    		  
    		case WM_DESTROY:
    			ShellAbout(hwnd, "第一个窗口程序", "再见,期待您在评论区留言!", NULL);
    			PostQuitMessage(0);
    			return 0;
    	}
    	
    	return DefWindowProc(hwnd, message, wParam, lParam);
    }

    运行效果见文首图片,现在有了BUTTON和EDIT两种控件,要把这个程序改造成一个简单的计算器程序应该很轻松的,你可以自己试试看(本文完)

    计算器例程见下一篇:《非可视化编程的windows窗口C++代码设计:附例程并多多知识点

    注:如遇 undefined reference to `__imp_GetStockObject' 报错,请在编译器选项中增加参数:

    -std=c++1y -mwindows

     

    附录

    回调函数中使用的windows消息:

    WM_NULL = &H0000;
    WM_CREATE = &H0001;             //应用程序创建一个窗口
    WM_DESTROY = &H0002;            //一个窗口被销毁
    WM_MOVE = &H0003;               //移动一个窗口
    WM_SIZE = &H0005;               //改变一个窗口的大小
    WM_ACTIVATE = &H0006;           //一个窗口被激活或失去激活状态
    WM_SETFOCUS = &H0007;           //获得焦点后
    WM_KILLFOCUS = &H0008;          //失去焦点
    WM_ENABLE = &H000A;             //改变enable状态
    WM_SETREDRAW = &H000B;          //设置窗口是否能重画
    WM_SETTEXT = &H000C;            //应用程序发送此消息来设置一个窗口的文本
    WM_GETTEXT = &H000D;            //应用程序发送此消息来复制对应窗口的文本到缓冲区
    WM_GETTEXTLENGTH = &H000E;      //得到与一个窗口有关的文本的长度(不包含空字符)
    WM_PAINT = &H000F;              //要求一个窗口重画自己
    WM_CLOSE = &H0010;              //当一个窗口或应用程序要关闭时发送一个信号
    WM_QUERYENDSESSION = &H0011;    //当用户选择结束对话框或程序自己调用ExitWindows函数
    WM_QUIT = &H0012;               //用来结束程序运行或当程序调用postquitmessage函数
    WM_QUERYOPEN = &H0013;          //当用户窗口恢复以前的大小位置时,把此消息发送给某个图标 
    WM_ERASEBKGND = &H0014;         //当窗口背景必须被擦除时(例在窗口改变大小时)
    WM_SYSCOLORCHANGE = &H0015;     //当系统颜色改变时,发送此消息给所有顶级窗口
    WM_ENDSESSION = &H0016;         //当系统进程发出WM_QUERYENDSESSION消息后,此消息发送给应用程序,通知它对话是否结束
    WM_SYSTEMERROR = &H0017;
    WM_SHOWWINDOW = &H0018;         //当隐藏或显示窗口是发送此消息给这个窗口
    WM_ACTIVATEAPP = &H001C;        //发此消息给应用程序哪个窗口是激活的,哪个是非激活的
    WM_FONTCHANGE = &H001D;         //当系统的字体资源库变化时发送此消息给所有顶级窗口
    WM_TIMECHANGE = &H001E;         //当系统的时间变化时发送此消息给所有顶级窗口
    WM_CANCELMODE = &H001F;         //发送此消息来取消某种正在进行的摸态(操作)
    WM_SETCURSOR = &H0020;          //如果鼠标引起光标在某个窗口中移动且鼠标输入没有被捕获时,就发消息给某个窗口
    WM_MOUSEACTIVATE = &H0021;      //当光标在某个非激活的窗口中而用户正按着鼠标的某个键发送此消息给当前窗口
    WM_CHILDACTIVATE = &H0022;      //发送此消息给MDI子窗口当用户点击此窗口的标题栏,或当窗口被激活,移动,改变大小 
    WM_QUEUESYNC = &H0023;          //此消息由基于计算机的训练程序发送,通过WH_JOURNALPALYBACK的hook程序分离出用户输入消息
    WM_GETMINMAXINFO = &H0024;      //此消息发送给窗口当它将要改变大小或位置
    WM_PAINTICON = &H0026;          //发送给最小化窗口当它图标将要被重画
    WM_ICONERASEBKGND = &H0027;     //此消息发送给某个最小化窗口,仅当它在画图标前它的背景必须被重画
    WM_NEXTDLGCTL = &H0028;         //发送此消息给一个对话框程序去更改焦点位置
    WM_SPOOLERSTATUS = &H002A;      //每当打印管理列队增加或减少一条作业时发出此消息
    WM_DRAWITEM = &H002B;           //当button,combobox,listbox,menu的可视外观改变时发送此消息给这些控件的所有者
    WM_MEASUREITEM = &H002C;        //当button, combo box, list box, listView control, or menu item 被创建时发送此消息给控件的所有者
    WM_DELETEITEM = &H002D;         //当the list box 或 combo box 被销毁 或 当 某些项被删除通过LB_DELETESTRING, LB_RESETCONTENT, CB_DELETESTRING, or CB_RESETCONTENT 消息
    WM_VKEYTOITEM = &H002E;         //此消息有一个LBS_WANTKEYBOARDINPUT风格的发出给它的所有者来响应WM_KEYDOWN消息  
    WM_CHARTOITEM = &H002F;         //此消息由一个LBS_WANTKEYBOARDINPUT风格的列表框发送给他的所有者来响应WM_CHAR消息
    WM_SETFONT = &H0030;            //当绘制文本时程序发送此消息得到控件要用的颜色
    WM_GETFONT = &H0031;            //应用程序发送此消息得到当前控件绘制文本的字体
    WM_SETHOTKEY = &H0032;          //应用程序发送此消息让一个窗口与一个热键相关连
    WM_GETHOTKEY = &H0033;          //应用程序发送此消息来判断热键与某个窗口是否有关联
    WM_QUERYDRAGICON = &H0037;      //此消息发送给最小化窗口,当此窗口将要被拖放而它的类中没有定义图标,应用程序能返回一个图标或光标的句柄,当用户拖放图标时系统显示这个图标或光标
    WM_COMPAREITEM = &H0039;        //发送此消息来判定combobox或listbox新增加的项的相对位置
    WM_GETOBJECT = &H003D;
    WM_COMPACTING = &H0041;               //显示内存已经很少了
    WM_WINDOWPOSCHANGING = &H0046;        //发送此消息给那个窗口的大小和位置将要被改变时,来调用setwindowpos函数或其它窗口管理函数
    WM_WINDOWPOSCHANGED = &H0047;         //发送此消息给那个窗口的大小和位置已经被改变时,来调用setwindowpos函数或其它窗口管理函数 
    WM_POWER = &H0048;                    //当系统(适用于16位的windows)将要进入暂停状态时发送此消息
    WM_COPYDATA = &H004A;                 //当一个应用程序传递数据给另一个应用程序时发送此消息
    WM_CANCELJOURNAL = &H004B;            //当某个用户取消程序日志激活状态,提交此消息给程序
    WM_NOTIFY = &H004E;                   //当某个控件的某个事件已经发生或这个控件需要得到一些信息时,发送此消息给它的父窗口
    WM_INPUTLANGCHANGEREQUEST = &H0050;   //当用户选择某种输入语言,或输入语言的热键改变
    WM_INPUTLANGCHANGE = &H0051;          //当平台现场已经被改变后发送此消息给受影响的最顶级窗口
    WM_TCARD = &H0052;                    //当程序已经初始化windows帮助例程时发送此消息给应用程序
    WM_HELP = &H0053;                     //此消息显示用户按下了F1,如果某个菜单是激活的,就发送此消息个此窗口关联的菜单,否则就发送给有焦点的窗口,如果当前都没有焦点,就把此消息发送给当前激活的窗口
    WM_USERCHANGED = &H0054;              //当用户已经登入或退出后发送此消息给所有的窗口,当用户登入或退出时系统更新用户的具体设置信息,在用户//更新设置时系统马上发送此消息;
    WM_NOTIFYFORMAT = &H0055;             //公用控件,自定义控件和他们的父窗口通过此消息来判断控件是使用ANSI还是UNICODE结构在WM_NOTIFY消息,使用此控件能使某个控件与它的父控件之间进行相互通信 
    
    WM_CONTEXTMENU = &H007B;              //当用户某个窗口中点击了一下右键就发送此消息给这个窗口
    WM_STYLECHANGING = &H007C;            //当调用SETWINDOWLONG函数将要改变一个或多个窗口的风格时发送此消息给那个窗口
    WM_STYLECHANGED = &H007D;             //当调用SETWINDOWLONG函数一个或多个 窗口的风格后发送此消息给那个窗口
    WM_DISPLAYCHANGE = &H007E;            //当显示器的分辨率改变后发送此消息给所有的窗口
    WM_GETICON = &H007F;                  //此消息发送给某个窗口来返回与某个窗口有关连的大图标或小图标的句柄;
    WM_SETICON = &H0080;                  //程序发送此消息让一个新的大图标或小图标与某个窗口关联
    WM_NCCREATE = &H0081;                 //当某个窗口第一次被创建时,此消息在WM_CREATE消息发送前发送;
    WM_NCDESTROY = &H0082;                //此消息通知某个窗口,非客户区正在销毁
    WM_NCCALCSIZE = &H0083;               //当某个窗口的客户区域必须被核算时发送此消息
    WM_NCHITTEST = &H0084;                //移动鼠标,按住或释放鼠标时发生
    WM_NCPAINT = &H0085;                  //程序发送此消息给某个窗口当它(窗口)的框架必须被绘制时
    WM_NCACTIVATE = &H0086;               //此消息发送给某个窗口 仅当它的非客户区需要被改变来显示是激活还是非激活状态
    WM_GETDLGCODE = &H0087;               //发送此消息给某个与对话框程序关联的控件,widdows控制方位键和TAB键使输入进入此控件通过响应WM_GETDLGCODE消息,应用程序可以把他当成一个特殊的输入控件并能处理它
    WM_NCMOUSEMOVE = &H00A0;              //当光标在一个窗口的非客户区内移动时发送此消息给这个窗口,非客户区为:窗体的标题栏及窗的边框体
    WM_NCLBUTTONDOWN = &H00A1;            //当光标在一个窗口的非客户区同时按下鼠标左键时提交此消息
    WM_NCLBUTTONUP = &H00A2;              //当用户释放鼠标左键同时光标某个窗口在非客户区十发送此消息;
    WM_NCLBUTTONDBLCLK = &H00A3;          //当用户双击鼠标左键同时光标某个窗口在非客户区十发送此消息
    WM_NCRBUTTONDOWN = &H00A4;            //当用户按下鼠标右键同时光标又在窗口的非客户区时发送此消息
    WM_NCRBUTTONUP = &H00A5;              //当用户释放鼠标右键同时光标又在窗口的非客户区时发送此消息
    WM_NCRBUTTONDBLCLK = &H00A6;          //当用户双击鼠标右键同时光标某个窗口在非客户区十发送此消息
    WM_NCMBUTTONDOWN = &H00A7;            //当用户按下鼠标中键同时光标又在窗口的非客户区时发送此消息
    WM_NCMBUTTONUP = &H00A8;              //当用户释放鼠标中键同时光标又在窗口的非客户区时发送此消息  
    WM_NCMBUTTONDBLCLK = &H00A9;          //当用户双击鼠标中键同时光标又在窗口的非客户区时发送此消息
    
    WM_KEYFIRST = &H0100;
    WM_KEYDOWN = &H0100;                  //按下一个键
    WM_KEYUP = &H0101;                    //释放一个键
    WM_CHAR = &H0102;                     //按下某键,并已发出WM_KEYDOWN,WM_KEYUP消息
    WM_DEADCHAR = &H0103;                 //当用translatemessage函数翻译WM_KEYUP消息时发送此消息给拥有焦点的窗口
    WM_SYSKEYDOWN = &H0104;               //当用户按住ALT键同时按下其它键时提交此消息给拥有焦点的窗口
    WM_SYSKEYUP = &H0105;                 //当用户释放一个键同时ALT 键还按着时提交此消息给拥有焦点的窗口
    WM_SYSCHAR = &H0106;                  //当WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函数翻译后提交此消息给拥有焦点的窗口
    WM_SYSDEADCHAR = &H0107;              //当WM_SYSKEYDOWN消息被TRANSLATEMESSAGE函数翻译后发送此消息给拥有焦点的窗口
    WM_KEYLAST = &H0108;
    WM_INITDIALOG = &H0110;               //在一个对话框程序被显示前发送此消息给它,通常用此消息初始化控件和执行其它任务
    WM_COMMAND = &H0111;                  //当用户选择一条菜单命令项或当某个控件发送一条消息给它的父窗口,一个快捷键被翻译  
    WM_SYSCOMMAND = &H0112;               //当用户选择窗口菜单的一条命令或当用户选择最大化或最小化时那个窗口会收到此消息
    WM_TIMER = &H0113;                    //发生了定时器事件
    WM_HSCROLL = &H0114;                  //当一个窗口标准水平滚动条产生一个滚动事件时发送此消息给那个窗口,也发送给拥有它的控件
    WM_VSCROLL = &H0115;                  //当一个窗口标准垂直滚动条产生一个滚动事件时发送此消息给那个窗口也,发送给拥有它的控件
    WM_INITMENU = &H0116;                 //当一个菜单将要被激活时发送此消息,它发生在用户菜单条中的某项或按下某个菜单键,它允许程序在显示前更改菜单
    WM_INITMENUPOPUP = &H0117;            //当一个下拉菜单或子菜单将要被激活时发送此消息,它允许程序在它显示前更改菜单,而不要改变全部
    WM_MENUSELECT = &H011F;               //当用户选择一条菜单项时发送此消息给菜单的所有者(一般是窗口)
    WM_MENUCHAR = &H0120;                 //当菜单已被激活用户按下了某个键(不同于加速键),发送此消息给菜单的所有者;
    WM_ENTERIDLE = &H0121;                //当一个模态对话框或菜单进入空载状态时发送此消息给它的所有者,一个模态对话框或菜单进入空载状态就是在处理完一条或几条先前的消息后没有消息
    WM_MENURBUTTONUP = &H0122;
    WM_MENUDRAG = &H0123;
    WM_MENUGETOBJECT = &H0124;
    WM_UNINITMENUPOPUP = &H0125;
    WM_MENUCOMMAND = &H0126;
    WM_CHANGEUISTATE = &H0127;
    WM_UPDATEUISTATE = &H0128;
    WM_QUERYUISTATE = &H0129;
    WM_CTLCOLORMSGBOX = &H0132;    //在windows绘制消息框前发送此消息给消息框的所有者窗口,通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置消息框的文本和背景颜色
    WM_CTLCOLOREDIT = &H0133;      //当一个编辑型控件将要被绘制时发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置编辑框的文本和背景颜色
    WM_CTLCOLORLISTBOX = &H0134;   //当一个列表框控件将要被绘制前发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置列表框的文本和背景颜色
    WM_CTLCOLORBTN = &H0135;       //当一个按钮控件将要被绘制时发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置按纽的文本和背景颜色 
    WM_CTLCOLORDLG = &H0136;       //当一个对话框控件将要被绘制前发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置对话框的文本背景颜色
    WM_CTLCOLORSCROLLBAR = &H0137; //当一个滚动条控件将要被绘制时发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置滚动条的背景颜色
    WM_CTLCOLORSTATIC= &H0138;     //当一个静态控件将要被绘制时发送此消息给它的父窗口;通过响应这条消息,所有者窗口可以通过使用给定的相关显示设备的句柄来设置静态控件的文本和背景颜色
    
    WM_MOUSEFIRST = &H0200;
    WM_MOUSEMOVE = &H0200;         //移动鼠标
    WM_LBUTTONDOWN = &H0201;       //按下鼠标左键
    WM_LBUTTONUP = &H0202;         //释放鼠标左键
    WM_LBUTTONDBLCLK = &H0203;     //双击鼠标左键
    WM_RBUTTONDOWN = &H0204;       //按下鼠标右键
    WM_RBUTTONUP = &H0205;         //释放鼠标右键
    WM_RBUTTONDBLCLK = &H0206;     //双击鼠标右键
    WM_MBUTTONDOWN = &H0207;       //按下鼠标中键
    WM_MBUTTONUP = &H0208;         //释放鼠标中键
    WM_MBUTTONDBLCLK = &H0209;     //双击鼠标中键  
    WM_MOUSEWHEEL = &H020A;        //当鼠标轮子转动时发送此消息个当前有焦点的控件
    WM_MOUSELAST = &H020A;
    WM_PARENTNOTIFY = &H0210;      //当MDI子窗口被创建或被销毁,或用户按了一下鼠标键而光标在子窗口上时发送此消息给它的父窗口
    WM_ENTERMENULOOP = &H0211;     //发送此消息通知应用程序的主窗口that已经进入了菜单循环模式
    WM_EXITMENULOOP = &H0212;      //发送此消息通知应用程序的主窗口that已退出了菜单循环模式
    WM_NEXTMENU = &H0213;
    WM_SIZING = &H0214;            //当用户正在调整窗口大小时发送此消息给窗口;通过此消息应用程序可以监视窗口大小和位置也可以修改他们
    WM_CAPTURECHANGED = &H0215;    //发送此消息 给窗口当它失去捕获的鼠标时
    WM_MOVING = &H0216;            //当用户在移动窗口时发送此消息,通过此消息应用程序可以监视窗口大小和位置 也可以修改他们
    WM_POWERBROADCAST = &H0218;    //此消息发送给应用程序来通知它有关电源管理事件
    WM_DEVICECHANGE = &H0219;      //当设备的硬件配置改变时发送此消息给应用程序或设备驱动程序
    
    WM_IME_STARTCOMPOSITION = &H010D;
    WM_IME_ENDCOMPOSITION = &H010E; 
    WM_IME_COMPOSITION = &H010F;
    WM_IME_KEYLAST = &H010F;
    WM_IME_SETCONTEXT = &H0281;
    WM_IME_NOTIFY = &H0282;
    WM_IME_CONTROL = &H0283;
    WM_IME_COMPOSITIONFULL = &H0284;
    WM_IME_SELECT = &H0285;
    WM_IME_CHAR = &H0286;
    WM_IME_REQUEST = &H0288;
    WM_IME_KEYDOWN = &H0290;
    WM_IME_KEYUP = &H0291;
    WM_MDICREATE = &H0220;           //应用程序发送此消息给多文档的客户窗口来创建一个MDI子窗口
    WM_MDIDESTROY = &H0221;          //应用程序发送此消息给多文档的客户窗口来关闭一个MDI子窗口
    WM_MDIACTIVATE = &H0222;         //应用程序发送此消息给多文档的客户窗口通知客户窗口激活另一个MDI子窗口,当客户窗口收到此消息后,它发出WM_MDIACTIVE消息给MDI子窗口(未激活)激活它
    WM_MDIRESTORE = &H0223;          //程序发送此消息给MDI客户窗口让子窗口从最大最小化恢复到原来大小
    WM_MDINEXT = &H0224;             //程序发送此消息给MDI客户窗口激活下一个或前一个窗口
    WM_MDIMAXIMIZE = &H0225;         //程序发送此消息给MDI客户窗口来最大化一个MDI子窗口
    WM_MDITILE = &H0226;             //程序发送此消息给MDI客户窗口以平铺方式重新排列所有MDI子窗口
    WM_MDICASCADE = &H0227;          //程序发送此消息给MDI客户窗口以层叠方式重新排列所有MDI子窗口
    WM_MDIICONARRANGE = &H0228;      //程序发送此消息给MDI客户窗口重新排列所有最小化的MDI子窗口
    WM_MDIGETACTIVE = &H0229;        //程序发送此消息给MDI客户窗口来找到激活的子窗口的句柄
    WM_MDISETMENU = &H0230;          //程序发送此消息给MDI客户窗口用MDI菜单代替子窗口的菜单
    WM_ENTERSIZEMOVE = &H0231;
    WM_EXITSIZEMOVE = &H0232;
    WM_DROPFILES = &H0233;
    WM_MDIREFRESHMENU = &H0234;
    WM_MOUSEHOVER = &H02A1;
    WM_MOUSELEAVE = &H02A3;
    WM_CUT = &H0300;                 //程序发送此消息给一个编辑框或combobox来删除当前选择的文本
    WM_COPY = &H0301;                //程序发送此消息给一个编辑框或combobox来复制当前选择的文本到剪贴板
    WM_PASTE = &H0302;               //程序发送此消息给editcontrol或combobox从剪贴板中得到数据
    WM_CLEAR = &H0303;               //程序发送此消息给editcontrol或combobox清除当前选择的内容
    WM_UNDO = &H0304;                //程序发送此消息给editcontrol或combobox撤消最后一次操作
    WM_RENDERFORMAT = &H0305;
    WM_RENDERALLFORMATS = &H0306;
    WM_DESTROYCLIPBOARD = &H0307;    //当调用ENPTYCLIPBOARD函数时 发送此消息给剪贴板的所有者
    WM_DRAWCLIPBOARD = &H0308;       //当剪贴板的内容变化时发送此消息给剪贴板观察链的第一个窗口;它允许用剪贴板观察窗口来显示剪贴板的新内容
    WM_PAINTCLIPBOARD = &H0309;      //当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区需要重画
    WM_VSCROLLCLIPBOARD = &H030A;
    WM_SIZECLIPBOARD = &H030B;       //当剪贴板包含CF_OWNERDIPLAY格式的数据并且剪贴板观察窗口的客户区域的大小已经改变是此消息通过剪贴板观察窗口发送给剪贴板的所有者
    WM_ASKCBFORMATNAME = &H030C;     //通过剪贴板观察窗口发送此消息给剪贴板的所有者来请求一个CF_OWNERDISPLAY格式的剪贴板的名字
    WM_CHANGECBCHAIN = &H030D;       //当一个窗口从剪贴板观察链中移去时发送此消息给剪贴板观察链的第一个窗口
    WM_HSCROLLCLIPBOARD = &H030E;    //此消息通过一个剪贴板观察窗口发送给剪贴板的所有者 ;它发生在当剪贴板包含CFOWNERDISPALY格式的数据并且有个事件在剪贴板观察窗的水平滚动条上;所有者应滚动剪贴板图象并更新滚动条的值
    WM_QUERYNEWPALETTE = &H030F;     //此消息发送给将要收到焦点的窗口,此消息能使窗口在收到焦点时同时有机会实现他的逻辑调色板
    WM_PALETTEISCHANGING = &H0310;   //当一个应用程序正要实现它的逻辑调色板时发此消息通知所有的应用程序
    WM_PALETTECHANGED = &H0311;      //此消息在一个拥有焦点的窗口实现它的逻辑调色板后发送此消息给所有顶级并重叠的窗口,以此来改变系统调色板
    WM_HOTKEY = &H0312;              //当用户按下由REGISTERHOTKEY函数注册的热键时提交此消息
    WM_PRINT = &H0317;               //应用程序发送此消息仅当WINDOWS或其它应用程序发出一个请求要求绘制一个应用程序的一部分
    WM_PRINTCLIENT = &H0318;
    
    WM_HANDHELDFIRST = &H0358;
    WM_HANDHELDLAST = &H035F;
    WM_PENWINFIRST = &H0380;
    WM_PENWINLAST = &H038F;
    WM_COALESCE_FIRST = &H0390;
    WM_COALESCE_LAST = &H039F;
    WM_DDE_FIRST = &H03E0;
    WM_DDE_INITIATE = WM_DDE_FIRST + 0;    //一个DDE客户程序提交此消息开始一个与服务器程序的会话来响应那个指定的程序和主题名
    WM_DDE_TERMINATE = WM_DDE_FIRST + 1;   //一个DDE应用程序(无论是客户还是服务器)提交此消息来终止一个会话
    WM_DDE_ADVISE = WM_DDE_FIRST + 2;      //一个DDE客户程序提交此消息给一个DDE服务程序来请求服务器每当数据项改变时更新它
    WM_DDE_UNADVISE = WM_DDE_FIRST + 3;    //一个DDE客户程序通过此消息通知一个DDE服务程序不更新指定的项或一个特殊的剪贴板格式的项
    WM_DDE_ACK = WM_DDE_FIRST + 4;         //此消息通知一个DDE(动态数据交换)程序已收到并正在处理WM_DDE_POKE,WM_DDE_EXECUTE,WM_DDE_DATA,WM_DDE_ADVISE,WM_DDE_UNADVISE, orWM_DDE_INITIAT消息
    WM_DDE_DATA = WM_DDE_FIRST + 5;        //一个DDE服务程序提交此消息给DDE客户程序来传递个一数据项给客户或通知客户的一条可用数据项
    WM_DDE_REQUEST = WM_DDE_FIRST + 6;     //一个DDE客户程序提交此消息给一个DDE服务程序来请求一个数据项的值
    WM_DDE_POKE = WM_DDE_FIRST + 7;        //一个DDE客户程序提交此消息给一个DDE服务程序,客户使用此消息来请求服务器接收一个未经同意的数据项;服务器通过答复WM_DDE_ACK消息提示是否它接收这个数据项;
    WM_DDE_EXECUTE = WM_DDE_FIRST + 8;     //一个DDE客户程序提交此消息给一个DDE服务程序来发送一个字符串给服务器让它象串行命令一样被处理,服务器通过提交WM_DDE_ACK消息来作回应
    WM_DDE_LAST = WM_DDE_FIRST + 8;
    WM_APP = &H8000;
    WM_USER = &H0400;                      //此消息能帮助应用程序自定义私有消息

    其他常数:

      //按扭
      BN_CLICKED           //用户单击了按钮
      BN_DISABLE           //按钮被禁止
      BN_DOUBLECLICKED     //用户双击了按钮
      BN_HILITE            //用户加亮了按钮
      BN_PAINT             //按钮应当重画
      BN_UNHILITE          //加亮应当去掉
      
      //编辑框
      EN_CHANGE            //编辑框中的文本己更新
      EN_ERRSPACE          //编辑框内存不足
      EN_HSCROLL           //用户点击了水平滚动条
      EN_KILLFOCUS         //编辑框正在失去输入焦点
      EN_MAXTEXT           //插入的内容被截断
      EN_SETFOCUS          //编辑框获得输入焦点
      EN_UPDATE            //编辑框中的文本将要更新
      EN_VSCROLL           //用户点击了垂直滚动条消息含义
      
      //列表框
      LBN_DBLCLK           //用户双击了一项
      LBN_ERRSPACE         //列表框内存不够
      LBN_KILLFOCUS        //列表框正在失去输入焦点
      LBN_SELCANCEL        //选择被取消
      LBN_SELCHANGE        //选择了另一项
      LBN_SETFOCUS         //列表框获得输入焦点
    
      //组合框
      CBN_CLOSEUP          //组合框的列表框被关闭
      CBN_DBLCLK           //用户双击了一个字符串
      CBN_DROPDOWN         //组合框的列表框被拉出
      CBN_EDITCHANGE       //用户修改了编辑框中的文本
      CBN_EDITUPDATE       //编辑框内的文本即将更新
      CBN_ERRSPACE         //组合框内存不足
      CBN_KILLFOCUS        //组合框失去输入焦点
      CBN_SELCHANGE        //在组合框中选择了一项
      CBN_SELENDCANCEL     //用户的选择应当被取消
      CBN_SELENDOK         //用户的选择是合法的
      CBN_SETFOCUS         //组合框获得输入焦点

    CreateWindow函数原型:

    函数原型:
    HWND WINAPI CreateWindow(
      _In_opt_  LPCTSTR lpClassName,    // 窗口类名称
      _In_opt_  LPCTSTR lpWindowName,   // 窗口标题
      _In_      DWORD dwStyle,          // 窗口风格,或称窗口格式
      _In_      int x,                  // 初始 x 坐标
      _In_      int y,                  // 初始 y 坐标
      _In_      int nWidth,             // 初始 x 方向尺寸
      _In_      int nHeight,            // 初始 y 方向尺寸
      _In_opt_  HWND hWndParent,        // 父窗口句柄
      _In_opt_  HMENU hMenu,            // 窗口菜单句柄
      _In_opt_  HINSTANCE hInstance,    // 程序实例句柄
      _In_opt_  LPVOID lpParam          // 创建参数
    );
    注释:_In_ 说明该参数是输入的,_opt_ 说明该参数是可选参数
    
    参数解析:
    
    参数	含义
    lpClassName	
            1. 窗口类名称,可以是一个指向 NULL 结束的字符串或一个整型数值
            2. 如果是字符串,它指定了窗口的类名。这个类名可以是任何用函数 RegisterClass 注册的类名,或    是任何预定义的控制类名
            3. 如是一个整型量,它是由此前调用 theGlobalAddAtom 函数产生的全局量。这个小于 0xC000 的 16 位数必须是 lpClassName 参数字的低 16 位,该参数的高位必须是 0
    lpWindowName
            1. 窗口标题,一个指向 NULL 结束的字符串指针
            2. 如果窗口风格指定了标题条,由 lpWindowName 指向的窗口标题将显示在标题条上
            3. 当使用 Createwindow 函数来创建控制例如按钮,选择框和静态控制时,可使用 lpWindowName 来指定控制文本
    dwStyle
            指定创建窗口的风格(详见下方↓)
    x	
            1. 指定窗口的初始水平位置(x 坐标)
            2. 对一个层叠或弹出式窗口,x 参数是屏幕坐标系的窗口的左上角的初始 x 坐标
            3. 对于子窗口,x 是子窗口左上角相对父窗口客户区左上角的初始 x 坐标
            4. 如果该参数被设为 CW_USEDEFAULT 则系统为窗口选择缺省的左上角坐标并忽略 y 参数,CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则 x 和 y 参数被设为零
    y	
            1. 指定窗口的初始垂直位置(y 坐标)
            2. 对一个层叠或弹出式窗口,y 参数是屏幕坐标系的窗口的左上角的初始 y 坐标
            3. 对于子窗口,y 是子窗口左上角相对父窗口客户区左上角的初始 y 坐标
            4. 对于列表框,y 是列表框客户区左上角相对父窗口客户区左上角的初始 y 坐标
            5. 如果层叠窗口是使用 WS_VISIBLE 风格位创建的并且 x 参数被设为 CW_USEDEFAULT,则系统将忽略 y 参数
    nWidth	
            1. 以设备单元指明窗口的宽度
            2. 对于层叠窗口,nWidth 的值或是屏幕坐标的窗口宽度或是 CW_USEDEFAULT
            3. 若 nWidth 是 CW_USEDEFAULT,则系统为窗口选择一个默认的高度和宽度(默认宽度为从初始 x 坐标开始到屏幕的右边界,缺省高度为从初始 y 坐标开始到目标区域的顶部。),CW_USEDEFAULT 只对层叠窗口有效,如果为弹出式窗口和子窗口设定 CW_USEDEFAULT 标志则 nWidth 和 nHeight 被设为零
    nHeight	
            1. 以设备单元指明窗口的高度
            2. 对于层叠窗口,nHeight 是屏幕坐标的窗口宽度
            3. 若 nWidth 被设为 CW_USEDEFAULT,则系统忽略 nHeight 参数,自动为 nWidth 和 nHeight 设置默认参数
    hWndParent	
            1. 指向被创建窗口的父窗口或所有者窗口的句柄
            2. 若要创建一个子窗口或一个从属窗口,需提供一个有效的窗口句柄
            3. 创建一个单纯的消息窗口,可以提供 HWND_MESSAGE 或提供一个己存在的消息窗口的句柄
    hMenu	
            1. 指向窗口菜单句柄,或依据窗口风格指明一个子窗口标识
            2. 对于层叠或弹出式窗口,hMenu 指定窗口使用的菜单:如果使用了菜单类,则 hMenu 可以为 NULL
            3. 对于子窗口,hMenu 指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的
    hInstance	
            与窗口相关联的模块实例的句柄
    lpParam	
            1. 指向一个值的指针,该值传递给窗口 WM_CREATE 消息。该值通过在 IParam 参数中的 CREATESTRUCT 结构传递
            2. 如果应用程序调用 CreateWindow 创建一个 MDI 客户窗口,则 lpParam 必须指向一个 CLIENTCREATESTRUCT 结构
    
    
    dwStyle 窗口风格解析
    
    窗口风格	含义
    WS_BORDER	
            创建一个带边框的窗口
    WS_CAPTION	
            创建一个有标题框的窗口(包含了 WS_BODER 风格)
    WS_CHILD	
            创建一个子窗口,这个风格的窗口不能拥有菜单也不能与 WS_POPUP 风格合用
    WS_CHILDWINDOW	
            与 WS_CHILD 相同
    WS_CLIPCHILDREN	
            当在父窗口内绘图时,排除子窗口区域,在创建父窗口时使用这个风格
    WS_CLIPSIBLINGS	
            1. 排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到 WM_PAINT 消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口
            2. 如果未指定该风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口
    WS_DISABLED	
            1. 创建一个初始状态为禁止的子窗口,一个禁止状态的窗口不能接受来自用户的输入信息
            2. 在窗口创建之后,可以调用 EnableWindow 函数来启用该窗口
    WS_DLGFRAME	
            创建一个带对话框边框风格的窗口,这种风格的窗口不能带标题条
    WS_GROUP	
            1. 指定一组“控制窗口”的第一个“控制窗口”
            2. 这个“控制窗口”组由第一个“控制窗口”和随后定义的“控制窗口”组成,自第二个“控制窗口”开始每个“控制窗口”具有 WS_GROUP 风格
            3. 每个组的第一个“控制窗口”带有 WS_TABSTOP 风格,从而使用户可以在组间移动
            4. 用户随后可以使用光标在组内的控制间改变键盘焦点
    WS_HSCROLL	
            创建一个有水平滚动条的窗口
    WS_ICONIC	
            创建一个初始状态为最小化状态的窗口,与 WS_MINIMIZE 风格相同
    WS_MAXIMIZE	
            创建一个初始状态为最大化状态的窗口
    WS_MAXIMIZEBOX	
            创建一个具有最大化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格
    WS_MINIMIZE	
            创建一个初始状态为最小化状态的窗口,与 WS_ICONIC 风格相同
    WS_MINIMIZEBOX	
            创建一个具有最小化按钮的窗口,该风格不能与 WS_EX_CONTEXTHELP 风格同时出现,同时必须指定 WS_SYSMENU 风格
    WS_OVERLAPPED	
            产生一个层叠的窗口,一个层叠的窗口有一个标题条和一个边框,与 WS_TILED 风格相同
    WS_OVERLAPPEDWINDOW	
            相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_TILEDWINDOW 风格相同
    WS_POPUP	
            创建一个弹出式窗口,该风格不能与 WS_CHILD 风格同时使用。
    WS_POPUPWINDOW	
            相当于(WS_POPUP | WS_BORDER | WS_SYSMENU),但 WS_CAPTION 和 WS_POPUPWINDOW 必须同时设定才能使窗口某单可见
    WS_SIZEBOX	
            创建一个可调边框的窗口,与 WS_THICKFRAME 风格相同
    WS_SYSMENU	
            创建一个在标题条上带有窗口菜单的窗口,必须同时设定 WS_CAPTION 风格
    WS_TABSTOP	
            1. 创建一个“控制窗口”,在用户按下 Tab 键时可以获得键盘焦点
            2. 按下 Tab 键后使键盘焦点转移到下一具有 WS_TABSTOP 风格的“控制窗口”
    WS_THICKFRAME	
            创建一个具有可调边框的窗口,与 WS_SIZEBOX 风格相同
    WS_TILED	
            产生一个层叠的窗口,一个层叠的窗口有一个标题和一个边框,与 WS_OVERLAPPED 风格相同
    WS_TILEDWINDOW	
            相当于(WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX),与 WS_OVERLAPPEDWINDOW 风格相同
    WS_VISIBLE	
            创建一个初始状态为可见的窗口
    WS_VSCROLL	
            创建一个有垂直滚动条的窗口
    
    返回值:
            1. 如果函数成功,返回值为新窗口的句柄;
            2. 如果函数失败,返回值为 NULL。
    

     

    展开全文
  • 上一篇博客写了如何搭建CKEditor与CKFinder环境,并将其与SpringMVC...该界面的皮肤是bootstrap的皮肤事件操作图获取界面上保存按钮点击事件效果用js操作ckeditor控制的textarea自定义界面ckeditor默认使用moono皮肤

    上一篇博客写了如何搭建CKEditor与CKFinder环境,并将其与SpringMVC进行整合,现在学习如何进行界面的定义,以及界面元素的操作。

    效果图

    界面操作图

    原始界面
    这里写图片描述

    调整后的界面(删除了flush,表单元素等)
    这里写图片描述
    该界面的皮肤是bootstrap的皮肤

    事件操作图

    获取界面上保存按钮点击事件效果

    这里写图片描述

    用js操作ckeditor控制的textarea

    这里写图片描述

    自定义界面

    ckeditor默认使用moono皮肤
    如果想更改ckeditor的皮肤,去ckeditor的网站下载相应的皮肤。

    皮肤更换

    去ckeditor的关网选一个你喜欢的皮肤,然后下载下来。
    http://ckeditor.com/addons/skins/all
    以bootstrap为例,点击Download进行下载
    这里写图片描述
    这里写图片描述
    根据提示信息,将下载的文件进行解压,并放在项目中ckeditor目录的skins目录下
    这里写图片描述
    然后配置config.js,使其引用bootstrap的皮肤

    config.js

    /**
     * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
     * For licensing, see LICENSE.md or http://ckeditor.com/license
     */
    
    CKEDITOR.editorConfig = function( config ) {
        // Define changes to default configuration here. For example:
        // config.language = 'fr';
        // config.uiColor = '#AADC6E';
        config.skin = 'bootstrapck';
    };

    如果想使用其他的皮肤,跟上面的操作一样,只需把

    config.skin = 'bootstrapck';
    

    换成下载的那个即可

    界面选择

    ckeditor的samples目录下提供了一个示例,点击TOOLBAR CONFIGURATOR就可以自定义界面了

    这里写图片描述

    进入界面选择和排序页面

    这里写图片描述

    定制好自己的界面后,点击右侧的Get toolbar config
    这里写图片描述
    得到自定义界面的js
    这里写图片描述
    将其拷贝到config.js中,注意保存自己之前的配置(皮肤,高度等)
    这里写图片描述

    隐藏按钮

    ckeditor与ckfinder整合之后再进行图文混排的时候选择图片时可以浏览服务器上的图片资源
    这里写图片描述
    用户可以删除,重命名,这也会影响到其他页面对该图片的引用,不安全。
    可以将浏览服务器按钮隐藏了。
    在选择图片的时候有两处有浏览服务器的按钮
    这里写图片描述
    这里写图片描述
    所以需要修改两处
    打开ckeditor/plugins/image/dialogs/下的image.js
    这里写图片描述
    查找browseServer,找到第一次出现的位置

    label:d.lang.common.browseServer,hidden:!0,
    

    修改其为

    label:d.lang.common.browseServer,style:"display:none",hidden:!0,
    

    这里写图片描述
    第一个浏览服务器按钮就被隐藏了

    再搜索image.js,搜索filebrowser

    url:d.config.filebrowserImageBrowseLinkUrl},style:"float:right",hidden:!0,
    

    将其改为

    url:d.config.filebrowserImageBrowseLinkUrl},style:"float:right;display:none",hidden:!0,
    

    这里写图片描述

    这样两个浏览服务器的按钮就被隐藏了,用户只能每次上传图片来进行图文混排。

    参考文献

    http://blog.163.com/zjc_8886/blog/static/2408175201011222590967/

    界面元素操作

    ckeditor为界面提供了许多按钮,有源代码,保存,新建,打印等等。
    有时候我们需要自己操作这些按钮的事件。ckeditor也为我们提供了相应的api
    api网址
    http://docs.cksource.com/ckeditor_api/index.html

    获取元素

    以保存按钮为例

    /**
     * index.jsp的js
     */
    
    // When the CKEDITOR instance is created, fully initialized and ready for interaction. 
    // 当id为content的那个ckeditor被创建,并初始化完成之后
    CKEDITOR.instances["content"].on("instanceReady", function() {
            // 保存按钮
            this.addCommand("save", {
                modes : {
                    wysiwyg : 1,
                    source : 1
                },
                exec : function(editor) {
                    save();
                }
            });
        });
    });
    
    // 保存方法
    function save() {
        // 获取到editor中的内容
        var content = editor.document.getBody().getHtml();
        alert(content);
    }

    这里写图片描述

    打印按钮的事件

        this.addCommand("print", {
            modes : {
                wysiwyg : 1,
                source : 1
            },
            exec : function(editor) {
                alert("print button");
            }
        });

    操作事件

    除了可以获取按钮的事件外,还能获取整个editor的点击,失去焦点等事件。

    案例

    用户进入编辑页面,ckeditor显示提示信息,当用户点击进行输入的时候提示信息消失,如果用户什么也没有输入,失去焦点时提示信息重新出现,如果用户输入了,不出现提示信息。

    效果

    这里写图片描述

    代码

    // 失去焦点
    this.on('blur', addTips);
    // 获得焦点
    this.on('focus', deleteTips);
    /*
    * 点击时清除提示信息
    */
    function deleteTips() {
        console.log("focus");
        var tips = editor.document.getBody().getText().trim();
        //console.log("tips: " + tips);
        var mytip = "如果想让图片居中,请先选择居中,然后再插入图片!".trim();
        //console.log("mytip: " + mytip);
        //console.log(tips == mytip);
        if (tips == mytip) {
            CKEDITOR.instances['content'].setData('');
        }
    }
    
    /*
    * 如果没有输入,失去焦点时给出提示信息
    */
    function addTips() {
        console.log("blur");
        var tips = editor.document.getBody().getText().trim();
        //console.log("tips: " + tips);
        var mytip = "如果想让图片居中,请先选择居中,然后再插入图片!".trim();
        //console.log("mytip: " + mytip);
        //console.log(tips == mytip);
        if (tips.length==0) {
        CKEDITOR.instances['content'].setData(mytip);
        }
    }

    参考文献

    http://blog.csdn.net/woshirongshaolin/article/details/8240542

    参考文献

    一篇博客

    一篇博客

    一篇博客

    CKEditor_API

    展开全文
  • 了解 WPF 中的路由事件命令

    千次阅读 2013-07-31 11:34:02
    了解 WPF 中的路由事件命令 Brian Noyes 代码下载位置: RoutedWPF2008_09a.exe (175 KB)  在线浏览代码 本文将介绍以下内容: 事件路由和可视树 命令路由 避免命令焦点项出错 ...
    了解 WPF 中的路由事件和命令
    Brian Noyes
    代码下载位置:  RoutedWPF2008_09a.exe  (175 KB) 
    在线浏览代码

    本文将介绍以下内容:
    • 事件路由和可视树
    • 命令路由
    • 避免命令焦点项出错
    • 超越路由命令
    本文使用了以下技术: 
    WPF
    要想尽快熟悉 Windows ® Presentation Foundation (WPF),必须要面对的 一个难题是有许多需要掌握的新结构。甚至 Microsoft ® .NET Framework 属性和事件这类简单的事物,在 WPF 中也有新的对应项,功能有所更新且更为复杂——尤其是依赖关系属性和路由事件,这一特点更为显著。还有就是那些全新的内容,如动画、样式设定、控制模板和路由命令等。要学习的东西太多了。
    在本文中,我将重点介绍两个极为重要的 WPF 新元素项。这两个元素项就是相互关联的路由事件和路由命令。它们是用户界面上不同部件进行通信的基础——这些部件可以是一个大的 Window 类的单个控件,也可以是用户界面上单独分离部件的控件及其支持代码。在本文中,我假定您已经对 WPF 有了一定的了解,比如说,知晓如何使用内置 WPF 控件并通过以 XAML 声明 UI 布局来构建 UI。

    路由事件概述
    刚开始接触 WPF 时,您可能会在自己并不知晓的情况下就用到了路由事件。例如,当您在 Visual Studio ®设计器中向窗口添加一个按钮,并将其命名为 myButton,然后双击该按钮时,Click 事件将挂接在您的 XAML 标记之内,它的事件处理程序会添加到 Window 类的代码隐藏中。这种感觉与在 Windows 窗体和 ASP.NET 中挂接事件并无二致。实际上,它比较接近 ASP.NET 的代码编写模型,但更类似 Windows 窗体的运行时模型。具体来说,在按钮的 XAML 标记中,代码的结尾类似如下所示:
    <Button Name="myButton" Click="myButton_Click">Click Me</Button>
    
    挂接事件的 XAML 声明就象 XAML 中的属性分配,但结果是针对指定事件处理程序的对象产生一个正常的事件挂接。此挂接实际上出现在编译时生成的窗口局部类中。要查看这一挂接,转到类的构造函数,右键单击 InitializeComponent 方法调用,然后从上下文菜单中选择“转到定义”。编辑器将显示生成的代码文件(其命名约定为 .i.g.cs 或 .i.g.vb),其中包括在编译时正常生成的代码。在显示的局部类中向下滚动到 Connect 方法,您会看到下面的内容:
    #line 6 "..\..\Window1.xaml"
    this.myButton.Click += 
      new System.Windows.RoutedEventHandler(
      this.myButton_Click);
    
    这一局部类是在编译时从 XAML 中生成的,其中包含那些需要设计时编译的 XAML 元素。大部分 XAML 最终都会成为编译后程序集中嵌入了二进制的资源,在运行时会与二进制标记表示的已编译代码合并。
    如果看一下窗口的代码隐藏,您会发现 Click 处理程序如下所示:
    private void myButton_Click(
      object sender, RoutedEventArgs e) { }
    
    到目前为止,它看起来就象任何其他 .NET 事件挂接一样——您有一个显式声明的委托,它挂接到一个对象事件且委托指向某个处理方法。使用路由事件的唯一标记是 Click 事件的事件参数类型,即 RoutedEventArgs。那么路由事件究竟有何独特之处呢?要理解这一点,首先需要了解 WPF 元素化的组合模型。

    WPF 元素树
    如果您在项目中开启一个新窗口并在设计器中将按钮拖入窗口内,您会得到 XAML 格式的元素树,如下所示(为了清楚略去了属性):
    <Window>
      <Grid>
        <Button/>
      </Grid>
    </Window>
    
    其中的每个元素都代表对应 .NET 类型的一个运行时实例,元素的声明分层结构形成了所谓的逻辑树。此外,WPF 中的许多控件不是 ContentControl 就是 ItemsControl,这代表他们可以有子元素。例如,Button 是一个 ContentControl,它可以将复杂的子元素做为其内容。您可以展开逻辑树,如下所示:
    <Window>
      <Grid>
        <Button>
          <StackPanel>
            <Image/>
            <TextBlock/>
          </StackPanel>
        </Button>
      </Grid>
    </Window>
    
    生成的 UI 如 图 1 所示。
    图 1  包含按钮内容的简单窗口
    如您所想,树可以有多个分支(Grid 中的另一 Button),因此逻辑树会变得极为复杂。对于逻辑树的 WPF 元素,您需要意识到您所见到的并不是您在运行时真正得到的内容。每个这样的元素通常都会在运行时扩展为更为复杂的可视元素树。在本例中,元素的逻辑树扩展为可视元素树,如 图 2 所示。
    图 2 简单窗口可视树
    我使用名为 Snoop 的工具 ( blois.us/Snoop) 查看 图 2 中所示可视树的元素。您可以看到窗口 (EventsWindow) 实际是将其内容置入 Border 和 AdornerDecorator 之内,用 ContentPresenter 显示其中的内容。按钮也与此类似,将其内容置入 ButtonChrome 对象,然后用 ContentPresenter 显示内容。
    单击按钮时,我可能实际根本没有单击 Button 元素,可能是单击可视树中的某一子元素,甚至是逻辑树中未显示的元素(如 ButtonChrome)。例如,假设我在按钮内的图像上方单击鼠标。这一单击操作在一开始实际是将其表达为 Image 元素中的 MouseLeftButtonDown 事件。但却需要转化为 Button 层级的 Click 事件。这就要引入路由事件中的路由。

    事件路由
    对逻辑树和可视树有所了解很有必要,因为路由事件主要是根据可视树进行路由。路由事件支持三种路由策略:气泡、隧道和直接。
    气泡事件最为常见,它表示事件从源元素扩散(传播)到可视树,直到它被处理或到达根元素。这样您就可以针对源元素的上方层级对象处理事件。例如,您可向嵌入的 Grid 元素附加一个 Button.Click 处理程序,而不是直接将其附加到按钮本身。气泡事件有指示其操作的名称(例如,MouseDown)。
    隧道事件采用另一种方式,从根元素开始,向下遍历元素树,直到被处理或到达事件的源元素。这样上游元素就可以在事件到达源元素之前先行截取并进行处理。根据命名惯例,隧道事件带有前缀 Preview(例如 PreviewMouseDown)。
    直接事件类似 .NET Framework 中的正常事件。该事件唯一可能的处理程序是与其挂接的委托。
    通常,如果为特殊事件定义了隧道事件,就会有相应的气泡事件。在这种情况下,隧道事件先触发,从根元素开始,下行至源元素,查找处理程序。一旦它被处理或到达源元素,即会触发气泡事件,从源元素上行,查找处理程序。气泡或隧道事件不会仅因调用事件处理程序而停止路由。如果您想中止隧道或气泡进程,可使用您传递的事件参数在事件处理程序中将事件标记为已处理。
    private void OnChildElementMouseDown(object sender, 
      MouseButtonEventArgs e) {
      e.Handled = true;
    }
    
    一旦您的处理程序将事件标记为已处理,该事件便不会传给任何其他处理程序。这一论断只是部分正确。实际上,事件路由仍在继续起作用,您可利用 UIElement.AddHandler 的替换方法在代码中显式挂接事件处理程序,该方法有一个额外的标记,可以有效指出“即使事件被标记为已处理也可调用我”。您用类似如下所示的调用指定该标记:
    m_SomeChildElement.AddHandler(UIElement.MouseDownEvent, 
      (RoutedEventHandler)OnMouseDownCallMeAlways,true);
    
    AddHandler 的第一个参数是您想要处理的 RoutedEvent。第二个参数是对事件处理方法(它需要有事件委托的正确签名)的委托。第三个参数指明如果另一个处理程序已将事件标记为已处理,您是否想得到通知。您调用 AddHandler 的元素就是在路由期间观察事件流动的元素。

    路由事件和组合
    现在我们来看一看 Button.Click 事件的形成过程,以了解为什么它如此重要。如前所述,用户将对 Button 可视树中的某些子元素(例如上一示例中的 Image)使用 MouseLeftButtonDown 事件启动 Click 事件。
    在 Image 元素内发生 MouseLeftButtonDown 事件时,PreviewMouseLeftButtonDown 在根元素启动,然后沿隧道下行至 Image。如果没有处理程序为 Preview 事件将 Handled 标记设置为 True,MouseLeftButtonDown 即会从 Image 元素开始向上传播,直至到达 Button。按钮处理这一事件,将 Handled 标记设为 True,然后引发其自身的 Click 事件。本文中的示例代码包括一个应用程序,它带有整个路由链挂接的处理程序,可帮您查看这一进程。
    其蕴含的意义不可小视。例如,如果我选择通过应用包含 Ellipse 元素的控件模板替换默认按钮外观,可以保证在 Ellipse 外部单击即可触发 Click 事件。靠近 Ellipse 的外缘单击仍处于 my button 的矩形边界内,但 Ellipse 有其自身的 MouseLeftButtonDown 击中检测,而 Ellipse 外部按钮的空白区域则没有。
    因此,只有在 Ellipse 内部的单击才会引发 MouseLeftButtonDown 事件。它仍由附加此模板的 Button 类进行处理,所以,即便是自定义的按钮,您也能得到预测的行为。在编写自己自定义的复合控件时也需牢记这一非常重要的概念,因为您的操作很可能类似 Button 对控件内子元素的事件处理。

    附加事件
    为了让元素能处理在不同元素中声明的事件,WPF 支持附加事件。附加事件也是路由事件,它支持元素 XAML 形式的挂接,而非声明事件所用的类型。例如,如果您想要 Grid 侦听采用气泡方式通过的 Button.Click 事件,仅需按如下所示进行挂接即可。
    <Grid Button.Click="myButton_Click">
      <Button Name="myButton" >Click Me</Button>
    </Grid>
    
    在编译时生成的局部类中的最终代码现在如下所示:
    #line 5 "..\..\Window1.xaml"
    ((System.Windows.Controls.Grid)(target)).AddHandler(
    System.Windows.Controls.Primitives.ButtonBase.ClickEvent, 
    new System.Windows.RoutedEventHandler(this.myButton_Click));
    
    附加事件可在挂接事件处理程序位置方面给予您更大的灵活性。但如果元素包含在同一类中(如本例所示),其差异并不会显露出来,这是由于处理方法针对的仍是 Window 类。
    它在两方面产生影响。第一,事件处理程序根据处理元素在气泡或隧道元素链中的位置进行调用。第二,您可额外执行一些操作,如从所用控件内封装的对象处理事件。例如,您可以象处理 Grid 中所示的事件一样处理 Button.Click 事件,但这些 Button.Click 事件可以从窗口中包含的用户控件内部向外传播。
    提示:事件处理程序命名
    如果您不想一味使用事件处理程序的默认命名约定(objectName_eventName),仅需输入您需要的事件处理程序名称,右键单击,然后单击上下文菜单中的“浏览到事件处理程序”即可。Visual Studio 随即按指定的名称生成事件处理程序。
    在 Visual Studio 2008 SP1 中,“属性”窗口会有一个事件视图,它与 Windows 窗体中的视图类似,因此如果您有 SP1,即可以在那里指定事件名称。但如果您采用的是 XAML,这是生成显式命名的处理程序的便捷方法。
    生成事件处理程序(单击图像可查看大图)
    并非所有事件都声明为附加事件。实际上,大部分事件都不是这样。但当您需要在控件来源之外处理事件时,附加事件会提供相当大的帮助。

    路由命令概述
    您已看到了路由事件,接下来我来介绍路由命令。WPF 的路由命令为您提供了一种特定的机制,用于将工具栏按钮和菜单项这类 UI 控件挂接到处理程序,并且无需在应用程序中加入许多关联性很强的重复代码。与正常事件处理相比,路由命令有三大优点:
    • 路由命令源元素(调用程序)能够与命令目标(处理程序)分离——它们不需要彼此引用,如果是通过事件处理程序链接,就需要相互引用。
    • 处理程序指出命令被禁用时,路由命令将自动启用或禁用所有相关的 UI 控件。
    • 您可以使用路由命令将键盘快捷方式与其他形式的输入手势(例如,手写)相关联,作为调用命令的另一种方式。
    此外,路由命令特有的 RoutedUICommand 类可以定义单一 Text 属性,用做任何控件(命令调用程序)的命令提示。与访问每个相关的调用程序控件相比,Text 属性的本地化更为容易。
    要在调用程序上声明命令,仅需在触发命令的控件上设置 Command 属性即可。
    <Button Command="ApplicationCommands.Save">Save</Button>
    
    MenuItem、Button、RadioButton、CheckBox、Hyperlink 和许多其他控件都支持 Command 属性。
    对于您想用做命令处理程序的元素,可设置 CommandBinding:
    <UserControl ...>
      <UserControl.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Save"    
          CanExecute="OnCanExecute" Executed="OnExecute"/>
      </UserControl.CommandBindings>
      ...
    </UserControl>
    
    CommandBinding 的 CanExecute 和 Executed 属性指向声明类代码隐藏中的方法,这些方法会在命令处理进程中被调用。此处的要点是命令调用程序既不需要了解,也不需要引用命令处理程序,处理程序不必知道是哪个元素将要调用命令。
    调用 CanExecute 来确定是否应启用命令。要启用命令,应将事件参数的 CanExecute 属性设置为 True,如下所示:
    private void OnCanExecute(object sender, 
      CanExecuteRoutedEventArgs e) {
      e.CanExecute = true;
    }
    
    如果命令处理程序带有定义的 Executed 方法,但没有 CanExecute 方法,命令也会被启用(在这种情况下,CanExecute 隐式为 true)。通过 Executed 方法,根据调用的命令执行相应的操作。这类与命令相关的操作可以是保存文档、提交订单、发送电子邮件等。

    操作中的路由命令
    为了使这一概念更为具体并让路由命令的益处立竿见影,我们来看一个简单的示例。在 图 3 中,您可看到一个简单的 UI,它有两个输入文本框,一个对文本框中的文本执行 Cut 操作的工具栏按钮。
    图 3  包含 Cut 命令工具栏按钮的简单示例
    要使用事件完成挂接,需要为工具栏按钮定义 Click 处理程序,且该代码需要引用两个文本框。您需要根据控件中的文本选择确定哪个文本框是焦点项并调用相应的剪贴板操作。还要根据焦点项的位置和文本框中是否有选项,在适当的时候启用或禁用工具栏按钮。代码十分凌乱且复杂。
    对于这一简单示例,问题还不大,但如果这些文本框深入用户控件或自定义控件的内部,且窗口代码隐藏无法直接访问它们,情况又会如何?您不得不在用户控件的边界显示 API 以便能从容器实现挂接,或公开显露文本框,两者皆不是理想的方法。
    如使用命令,只需将工具栏按钮的 Command 属性设为在 WPF 中定义的 Cut 命令即可。
    <ToolBar DockPanel.Dock="Top" Height="25">
      <Button Command="ApplicationCommands.Cut">
        <Image Source="cut.png"/>
      </Button>
    </ToolBar>
    
    现在您运行应用程序,会看到工具栏按钮一开始是被禁用的。在其中一个文本框中选择了文本后,工具栏按钮会启用,如果单击该按钮,文本会被剪切到剪贴板。这一操作适用于 UI 中任何位置的任何文本框。喔,很不错吧?
    实际上,TextBox 类实现有一个针对 Cut 命令的内置命令绑定,并为您封装了该命令(Copy 和 Paste)的剪贴板处理。那么,命令如何只调用所关注的文本框,消息如何到达文本框并告诉它处理命令?这便是路由命令中路由部件发挥作用的地方。

    命令路由
    路由命令与路由事件的区别在于命令从其调用程序路由至处理程序的方法。具体来说,路由事件是从幕后在命令调用程序和处理程序之间路由消息(通过将其挂接至可视树中的命令绑定)。
    这样,众多元素间都存在关联,但在任何时刻都实际只有一个命令处理程序处于活动状态。活动命令处理程序由可视树中命令调用程序和命令处理程序的位置、以及 UI 中焦点项的位置共同决定。路由事件用于调用活动命令处理程序以询问是否应启用命令,并调用命令处理程序的 Executed 方法处理程序。
    通常,命令调用程序会在自己在可视树中的位置与可视树根项之间查找命令绑定。如找到,绑定的命令处理程序会确定是否启用命令并在调用命令时一并调用其处理程序。如果命令挂接到工具栏或菜单中的一个控件(或将设置 FocusManager.IsFocusScope = true 的容器),则会运行一些其他的逻辑,沿可视树路径从根项到命令绑定的焦点元素进行查看。
    图 3 的简单应用程序中,实际发生的情况是:由于 Cut 命令按钮位于工具栏内,所以由具备焦点项的 TextBox 实例处理 CanExecute 和 Execute。如 图 3 中的文本框包含在用户控件之内,您就有机会对窗口、包含 Grid 的用户控件、包含文本框的用户控件或单个文本框设置命令绑定。有焦点项的文本框将确定其路径的终点(它的起点是根项)。
    要理解 WPF 路由命令的路由,需要认识到一旦调用一个命令处理程序,就不能再调用其他处理程序。因此,如果用户控件处理 CanExecute 方法,就不会再调用 TextBox CanExecute 实现。

    定义命令
    ApplicationCommands.Save 和 ApplicationCommands.Cut 是 WPF 提供的诸多命令中的两个命令。 图 4 中显示了 WPF 中五个内置命令类及其所包含的一些命令示例。
    命令类 示例命令
    ApplicationCommands Close、Cut、Copy、Paste、Save、Print
    NavigationCommands BrowseForward、BrowseBack、Zoom、Search
    EditingCommands AlignXXX、MoveXXX、SelectXXX
    MediaCommands Play、Pause、NextTrack、IncreaseVolume、Record、Stop
    ComponentCommands MoveXXX、SelectXXX、ScrollXXX、ExtendSelectionXXX
    XXX 代表操作的集合,例如 MoveNext 和 MovePrevious。每一类中的命令均定义为公用静态(在 Visual Basic ® 中共享)属性,以便您可轻松挂接。通过使用以下方式,您可以轻松定义自己的自定义命令。稍后我会提供相应的示例。
    您也可搭配使用一个简短的注释,如下所示:
      <Button Command="Save">Save</Button>
    
    如您使用此缩写版本,WPF 中的类型转换器将尝试从内置命令集合找到命名的命令。在此例中结果完全相同。我倾向于使用长名版本,这样代码更为明确、更易维护。不会对命令的定义位置产生歧义。即使是内置命令,在 EditingCommands 类和 ComponentCommands 类之间也会有一些重复。

    命令插入
    路由命令是 WPF 所定义的 ICommand 界面的一种特殊实现。ICommand 的定义如下:
      public interface ICommand {
        event EventHandler CanExecuteChanged;
        bool CanExecute(object parameter);
        void Execute(object parameter);
      }
    
    内置的 WPF 命令类型为 RoutedCommand 和 RoutedUICommand。这两种类均实现 ICommand 界面并使用我先前所介绍的路由事件执行路由。
    我们期望命令调用程序调用 CanExecute 来确定是否启用任何相关的命令调用代码。命令调用程序可通过订阅 CanExecuteChanged 事件来确定何时调用该方法。在 RoutedCommand 类中,根据状态或 UI 中焦点项的变化触发 CanExecuteChanged。调用命令时,会调用 Executed 方法并通过路由事件沿可视树分派至处理程序。
    支持 Command 属性的类(如 ButtonBase)实现 ICommandSource 界面:
    public interface ICommandSource {
      ICommand Command { get; }
      object CommandParameter { get; }
      IInputElement CommandTarget { get; }
    }
    
    Command 属性在调用程序和它将调用的命令之间建立关联。CommandParameter 允许调用程序在调用命令的同时传递某些数据。您可使用 CommandTarget 属性根据焦点项的路径替换默认路由,并通知命令系统使用指定的元素做为命令处理程序,而不是依赖路由事件和命令处理程序基于焦点项所做的决定。

    路由命令的局限
    路由命令非常适合单用户界面,挂接工具栏和菜单项以及处理与键盘焦点项目(如剪贴板操作)相关的条目。但是,如果您要构建复杂的用户界面,即命令处理逻辑位于视图定义的支持代码之内,且命令调用程序不总是在工具栏或菜单之内,在这种情况下,路由命令就显得力不从心了。使用 UI 复合模式时,如 Model View Controller 或 MVC ( msdn.microsoft.com/magazine/cc337884)、Model View Presenter 或 MVP ( msdn.microsoft.com/magazine/cc188690)、Presentation Model,在 WPF 循环中亦称做 Model View ViewModel ( msdn.microsoft.com/library/cc707885),通常会出现这种情况。
    此时的问题是启用并处理命令逻辑可能不是直接归属于可视树,而是位于表示器或表示模型。此外,确定是否启用命令的状态与命令调用程序和视图在可视树中的位置无关。有时,您会遇到一个特殊命令在给定时间有多个处理程序的情形。
    要了解在哪些情况下路由命令会出现问题,请查看 图 5。它是一个简单的窗口,包含一对用户控件,这两个控件以 MVP 或 MVC 模式表示视图。主窗口包含一个 File 菜单和工具栏,其中有 Save 命令按钮。在主窗口上方还有一个输入文本框,以及一个将 Command 设为 Save 的 Button。
    图 5  复合用户界面(单击图像可查看大图)
    提示:挂接匿名方法
    图 6 所示的代码中,我使用了我同事 Juval Lowy 传授给我的技巧,向声明中的委托挂接一个空的匿名方法。
    Action<string> m_ExecuteTargets = delegate { };
    
    这样,在调用委托前,您就不必再检查是否有空值,因为在调用列表中始终都有一个 no-op 订户。您还可能通过在多线程环境中取消订阅避免可能的争用,如果您检查空值,经常会出现争用。
    有关此技巧的详细信息,请参阅 Juval Lowy 撰写的 《Programming .NET Components, Second Edition》。
    UI 的其余部分由两个视图提供,每个都是简单用户控件的实例。每个用户控件实例的边界颜色各不相同,这是为更清楚地显示它们所提供的 UI 内容。每个用户控件实例都有一个 Save 按钮,它将 Command 属性设为 Save 命令。
    路由命令(与可视树中的位置密切相关)带来的困难在这一简单示例中一览无余。在 图 5 中,窗口本身没有针对 Save 命令的 CommandBinding。但它的确包含该命令的两个调用程序(菜单和工具栏)。在此情形中,我不想让顶层窗口在调用命令时必须了解采取何种操作。而是希望由用户控件表示的子视图处理命令。此例中的用户控件类有针对 Save 命令的 CommandBinding,它为 CanExecute 返回 true。
    但在 图 5 中,您可以看到焦点项位于顶部文本框的窗口内,而此级别的命令调用程序却被禁用。此外,尽管用户控件中没有焦点项,但用户控件中的 Save 按钮却被启用。
    如果您将焦点项从一个文本框更改到一个用户控件实例内,菜单和工具栏中的命令调用程序会变为启用状态。但窗口本身的 Save 按钮不会变为启用状态。实际上,在这种情况下无法用正常路由启用窗口上方文本框旁的 Save 按钮。
    原因仍与单个控件的位置相关。由于在窗口级没有命令处理程序,尽管焦点项位于用户控件之外,但可视树上方或焦点项路径上仍没有命令处理程序会启用挂接为命令调用程序的控件。因此一旦涉及这些控件,会默认禁用命令。但是,对于用户控件内的命令调用程序,由于处理程序在可视树的位置靠上,所以会启用命令。
    一旦您将焦点项转到其中一个用户控件内,位于窗口和焦点项路径上文本框之间的用户控件即会提供命令处理程序,用于为工具栏和菜单启用命令,这是因为它们会检查焦点项路径以及其在可视树中的位置与根项之间的路径。由于窗口级按钮和根项之间没有处理程序,所以无法启用该按钮。
    要是这个简单的小示例中的可视树和焦点项路径的繁文缛节就让您倍感头疼,如果 UI 相当复杂,在可视树中众多不同位置有命令调用程序和处理程序,要想理顺命令启用和调用有多难就可想而知了。那会您联想起电影《Scanners》中的怕人情节,让人头昏眼花。

    避免命令出错
    要防止路由命令出现与可视树位置相关的问题,您需要保持简洁。通常应确保命令处理程序位于相同的元素,或在可视树中处于调用命令的元素上方。您可以从包含命令处理程序的控件使用 CommandManager.RegisterClassCommandBinding 方法,在窗口级加入命令绑定,这样就能实现上述目标。
    如果您实现的是本身接受键盘焦点项(像文本框)的自定义控件,那么属于例外情况。在这种情形下,如果您想在控件本身嵌入命令处理且该命令处理仅在焦点项处于您的控件上时产生关联,您可实现这一目标,它的工作状况类似先前所示的 Cut 命令示例。
    您也可通过 CommandTarget 属性明确指定命令处理程序来解决上述问题。例如,对于 图 5 中从未启用过的窗口级 Save 按钮,您可将其命令挂接更改为如下所示:
    <Button Command="Save" 
      CommandTarget="{Binding ElementName=uc1}"
      Width="75" Height="25">Save</Button>
    
    在此代码中,Button 专门将其 CommandTarget 设为 UIElement 实例,该实例中包含一个命令处理程序。在本例中,它指定名为 uc1 的元素,该元素恰好为示例中两个用户控件实例之一。由于该元素有一个始终返回 CanExecute = true 的命令处理程序,窗口级的 Save 按钮始终处于启用状态,并仅调用该控件的命令处理程序,无论调用程序相对于命令处理程序的位置如何都是如此。

    超越路由命令
    由于路由命令存在一定的限制,许多用 WPF 构建复杂 UI 的公司已转为使用自定义 ICommand 实现,这些实现能为它们提供自己的路由机制,特别是与可视树无关联且支持多个命令处理程序的机制。
    创建自定义命令实现并不困难。针对类实现 ICommand 界面后,会为挂接命令处理程序提供一种方式,然后可在调用命令时执行路由。您还必须确定使用何种标准确定引发 CanExecuteChanged 事件的时机。
    创建自定义命令时最好先使用委托。委托已支持调用目标方法,并支持多个订户。
    图 6 显示了名为 StringDelegateCommand 的命令类,它使用委托来允许挂接多个处理程序。它支持向处理程序传递字符串参数,并使用调用程序的 CommandParameter 确定向处理程序传递的消息。
    public class StringDelegateCommand : ICommand {
      Action<string> m_ExecuteTargets = delegate { };
      Func<bool> m_CanExecuteTargets = delegate { return false; };
      bool m_Enabled = false;
    
      public bool CanExecute(object parameter) {
        Delegate[] targets = m_CanExecuteTargets.GetInvocationList();
        foreach (Func<bool> target in targets) {
          m_Enabled = false;
          bool localenable = target.Invoke();
          if (localenable) {
            m_Enabled = true;
            break;
          }
        }
        return m_Enabled;
      }
    
      public void Execute(object parameter) {
        if (m_Enabled)
          m_ExecuteTargets(parameter != null ? parameter.ToString() : null);
      }
    
      public event EventHandler CanExecuteChanged = delegate { };
    
      ...
    }
    
    如您所见,我选择使用 Func<bool> 委托挂接确定是否启用命令的处理程序。在 CanExecute 实现中,类遍历挂接到 m_CanExecuteTargets 委托的处理程序,查看是否有处理程序想执行的委托。如果有,它为要启用的 StringDelegateCommand 返回 true。调用 Execute 方法时,它仅需检查是否启用了命令,如启用,则调用所有挂接到 m_ExecuteTargets Action<string> 委托的处理程序。
    要将处理程序挂接到 CanExecute 和 Execute 方法,StringDelegateCommand 类公开 图 7 中所示的事件访问器,从而允许处理程序从基础委托轻松订阅或取消订阅。注意,您还可以在处理程序订阅或取消订阅时使用事件访问器触发 CanExecuteChanged 事件。
    public event Action<string> ExecuteTargets {
      add {
        m_ExecuteTargets += value;
      }
      remove {
        m_ExecuteTargets -= value;
      }
    }
    
    public event Func<bool> CanExecuteTargets {
      add {
        m_CanExecuteTargets += value;
        CanExecuteChanged(this, EventArgs.Empty);
      }
      remove {
        m_CanExecuteTargets -= value;
        CanExecuteChanged(this, EventArgs.Empty);
      }
    }
    

    路由处理程序示例
    在代码下载的示例应用程序中,我挂接了这个类。该示例有一个简单视图,隐含一个表示器(沿用 MVP,但没有模型)。表示器向视图公开一个表示模型以绑定数据(您可将表示模型想象成位于表示器和视图之间,而 MVP 模型位于表示器之后)。表示模型通常公开视图可以绑定数据的属性。在本例中,它仅公开了一个命令属性,以便可以通过数据绑定在视图的 XAML 中轻松实现挂接。
    <Window x:Class="CustomCommandsDemo.SimpleView" ...>
      <Grid>
        <Button Command="{Binding CookDinnerCommand}" 
          CommandParameter="Dinner is served!" ...>Cook Dinner</Button>
        <Button Click="OnAddHandler" ...>Add Cook Dinner Handler</Button>
      </Grid>
    </Window>
    
    Binding 声明只查找当前 DataContext 的属性(名为 CookDinnerCommand),如找到,则将它传给 Icommand。我们在前面提到过 CommandParameter,调用程序可以用它随同命令传递某些数据。在本例中,请注意我只传递了将通过 StringDelegateCommand 传递给处理程序的字符串。
    此处所示为视图的代码隐藏(Window 类):
    public partial class SimpleView : Window {
      SimpleViewPresenter m_Presenter = new SimpleViewPresenter();
    
      public SimpleView() {
        InitializeComponent();
        DataContext = m_Presenter.Model;
      }
    
      private void OnAddHandler(object sender, RoutedEventArgs e) {
        m_Presenter.AddCommandHandler();
      }
    }
    
    视图构建其表示器,从表示器取得表示模型,然后将其设置为 DataContext。它还有按钮 Click 的处理程序,该处理程序调入表示器,让它为命令添加处理程序。
    复合事件和命令
    今年我一直在与 Microsoft 模式和实践小组合作,帮助为 WPF 开发复合应用程序指南,这组指南用于在 WPF 中开发复杂的复合应用程序。其中包含称为 Composite Application Libraries (CAL) 的库,为复合应用程序提供服务和帮助程序类。
    Glenn Block 的文章“使用 WPF 构建复合应用程序的模式”中有“WPF 复合应用程序指南”的更多信息,网址为  msdn.microsoft.com/magazine/cc785479
    图 8 显示了运行中的这一应用程序。第一个窗口处于初始状态,未挂接命令处理程序。由于没有命令处理程序,所以您会看到第一个按钮(调用程序)被禁用。按第二个按钮时,它会调入表示器并挂接新的命令处理程序。此时会启用第一个按钮,您再单击它时,它会调用其通过数据绑定松散联接的命令处理程序和基础命令的订户列表。
    图 8  运行中的自定义命令示例(单击图像可查看大图)
    表示器代码如 图 9 中所示。您可以看到表示器构建了表示模型,并通过 Model 属性将其公开给视图。从视图调用 AddCommandHandler 时(响应第二个按钮 Click 事件),它会向模型的 CanExecuteTargets 和 ExecuteTargets 添加一个订户。这些订阅方法是表示器中的简单方法,它们分别返回 true 并显示 MessageBox。
    public class SimpleViewPresenter {
      public SimpleViewPresenter() {
        Model = new SimpleViewPresentationModel();
      }
    
      public SimpleViewPresentationModel Model { get; set; }
    
      public void AddCommandHandler() {
        Model.CookDinnerCommand.CanExecuteTargets += CanExecuteHandler;
        Model.CookDinnerCommand.ExecuteTargets += ExecuteHandler;
      }
    
      bool CanExecuteHandler() {
        return true;
      }
    
      void ExecuteHandler(string msg) {
        MessageBox.Show(msg);
      }
    }
    
    本例显示数据绑定、UI 模式和自定义命令的组合将为您带来清晰独立的命令途径,可以摆脱路由命令的限制。由于命令是通过绑定以 XAML 形式挂接的,您甚至可以通过此方式完全用 XAML 定义视图(没有代码隐藏)、从 XAML 使用绑定命令触发表示模型中的操作、启动您原本需要表示模型代码隐藏执行的操作。
    您需要控制器来构建视图并为其提供表示模型,但您不用代码隐藏就能编写交互视图。如果无需代码隐藏,在代码隐藏文件中添加相互纠结、不可测试的复杂代码的机率会大大降低,在 UI 应用程序中,这种情况经常出现。此方式刚在 WPF 中试用。但它的确值得考虑,您应该了解更多的示例。
    Brian Noyes 是 IDesign ( www.idesign.net) 的首席架构师、Microsoft 区域总监 ( www.theregion.com)和 Microsoft MVP。他是《Developing Applications with Windows Workflow Foundation》、《Smart Client Deployment with ClickOnce》和《Data Binding with Windows Forms 2.0》的作者。他还经常在全球行业会议上发表演讲。您可以通过 Brian 的博客  briannoyes.net 与他联系。

    展开全文
  • 利用语言的按钮事件特征可以帮助我们破解一些软件,测试软件的强度,为我们的软件安全提供一些思路 首先了解什么是特征码,举个例之: 0047FA10 > $ 55 push ebp 0047FA11 . 8BEC mov ebp,esp 0047FA13 . 83...

    利用语言的按钮事件特征可以帮助我们破解一些软件,测试软件的强度,为我们的软件安全提供一些思路

    首先了解什么是特征码,举个例之:

    0047FA10 > $  55            push ebp
    0047FA11   .  8BEC          mov ebp,esp
    0047FA13   .  83C4 F0       add esp,-0x10
    比如说push ebp的特征码就是55, mov ebp,esp的特征码就是8BEC,这就是特征码

    1.Delphi和BC++

    因为Delphi和BC++的特征码是通用的,我们放在一起说,首先PEID查壳(习惯)

    载入od,然后右键---查找-----二进制字符串,输入我们的特征码

    那我图片里的?代表什么呢,就我的图片例子而言

    0047FA4B   .  E8 4049FDFF   call Delphi.00454390          //E8代表call,而call后的地址是会变动的
    0047FA50   .  E8 6B43F8FF   call Delphi.00403DC0

    所以我们就用?代表不断变动的地址,call向哪里的地址无所谓,地址变到哪里我们就用?代替,之后点击确定


    展开全文
  • Qt Designer中的Buttons部件包括Push Button(常规按钮、一般称按钮)、Tool Button(工具按钮)、Radio Button(单选按钮)、Check Box(复选框)、Command Link Button(命令链接按钮)和Dialog Button Box...
  • Qt Designer中的Buttons部件包括Push Button(常规按钮、一般称按钮)、Tool Button(工具按钮)、Radio Button(单选按钮)、Check Box(复选框)、Command Link Button(命令链接按钮)和Dialog Button B...
  • 路由事件命令

    千次阅读 2011-08-28 10:15:12
    MSDN: http://msdn.microsoft.com/zh-cn/magazine/cc785480.aspx 路由事件概述 刚开始接触 WPF 时,您可能会在自己并知晓的情况下就用到了路由事件。例如,当您在 Visual Studio® 设计器中向窗
  • JAVA命令大全

    千次阅读 2018-10-04 22:58:49
    :跟java命令相对的,可以运行.class文件,主要用来执行图形界面的java程序运行java命令时,会出现并保持一个console窗口,程 序中的信息可以通过System.out在console内输出,而运行javaw,开始时会出现console,...
  • 【XBEE手册】AT命令

    千次阅读 2018-07-31 21:03:45
    【XBEE手册】AT命令 @(ZigBee)(ZigBee)[ZigBee, XBEE手册] 【XBEE手册】AT命令 寻址命令 DH(Destination address High ) DL(Destination address Low) MY(16-bit Network Address) MP(16-bit Parent ...
  • 组态王命令语言程序.doc

    千次阅读 2021-05-20 09:26:29
    组态王命令语言程序命令语言程序10.1 命令语言...根据事件和功能的不同,包括应用程序命令语言、热键命令语言、事件命令语言、数据改变命令语言、自定义函数命令语言、动画连接命令语言和画面命令语言等。具有完备...
  • C#:C#控件系列三 (按钮类控件)

    千次阅读 2018-07-11 17:41:48
     Button 控件:Button控件又称按钮控件,是Windows应用程序中最常用的控件之一,通常用它来执行命令。如果按钮具有焦点,就可以使用鼠标左键、Enter键或空格键触发该按钮的Click事件。通过设置窗体的AcceptButton或...
  • wxpython 基本的控件 (按钮

    万次阅读 2016-09-13 14:32:03
    这一节,我们将讨论文本按钮、位图按钮、开关按钮(toggle buttons )和通用(generic )按钮。   如何生成一个按钮?   在第一部分(part 1)中,我们已经说明了几个按钮的例子,所以这里我们只...
  • CorelDRAW 是由Corel公司开发的图形设计软件,随着版本的不断推出,其功能也在不断完善,虽然CorelDRAW 的菜单命令、工具特别繁杂,但是其操作都很简单、方便,系统性和条理性也都相当强。  广泛的应用  Corel...
  • 使用按钮工作   在wxPython 中有很多不同类型的按钮。这一节,我们将讨论文本按钮、位图按钮、开关按钮(toggle buttons )和通用(generic )按钮。   如何生成一个按钮?   在第一部分...
  • 7、命令按钮 8、综合实验 1、创建新项目 可通过文件->新建->项目 命令来创建一个新的Windows程序 在这里选择创建了一个Windows窗口程序 (1)工具箱窗口 工具箱提供了Windows应用程序的用户界面控件...
  • SQL命令和常用语句大全

    千次阅读 2016-05-22 21:41:32
    select distinct column_name form table_name --------- distinct指定检索独有的列值,重复 select stocknumber ,"stocknumber + 10" = stocknumber + 10 fromtable_name select stockname , "stocknumber" =...
  •  一般情况下,在窗体的右上角都有最大化、最小化和关闭按钮,丹在MDI窗体中,有事为了避免重复打开同一个窗口,需要禁用窗口上面的“关闭”按钮,本实例就实现了这样的功能。  说道禁用、有的人会说:直接在...
  • 这几天基于react写了一个小demo测试,主要实现的功能是:在输入框中输入文字,点击添加按钮,在下方的表格中会自动添加一行数据,点击删除按钮后,该行数据被删除。  先来看看最后的效果图:  操作前  操作...
  • 关于批处理以及批处理常用命令的总结   【 一、什么是批处理 】  批处理文件图标 批处理(Batch),也称为批处理脚本。顾名思义,批处理就是对某对象进行批量的处理。批处理文件的扩展名为 bat 。  目前比较...
  • java命令大全

    万次阅读 2017-05-31 19:49:56
    转载地址:... JAVA命令大全 1、java.exe: ====================== 运行java程序,这个相信每一位用Java的人知道了。 2、javac.exe: ====================== 编译的Java程序,生成.class文件
  • 属性用于指示当前命令是否可用,也就是说系统会不断地检视该命令与该命令的作用对象,并根据你所提供的条件来判断当前命令是否可用,比如文本框状态变为"只读"后,其"粘贴"命令可用,作用于该文本框的粘贴按钮会自动...
  • vue的绑定点击事件连续执行两次

    千次阅读 2021-01-12 03:57:46
    问题场景:代码如下图:图1 html结构图2 js代码为了排除其他影响因素,我将代码逻辑全部注释掉。只留下一句打印语句。执行结果如下图显示:图3 打印结果由打印结果可以看出:addGoods这个函数被执行了两次。问题猜想...
  • 安卓指令和命令学习总结

    千次阅读 2016-05-16 11:50:39
    Linux挂装CD-ROM后,会锁定CD—ROM,这样就不能用CD- ROM面板上的Eject按钮弹出它。但是,当不再需要光盘时,如果已将/cdrom作为符号链接,请使用umount/cdrom来卸装它。仅当无用户 正在使用光盘时,该命令才会...
  • 还有一些设备属于使用SCSI命令集的其他(即被视为SCSI)传输,其主要示例是(S-)ATAPI CD和DVD驱动器。并非所有外围设备类型都映射到上层驱动程序,并且这些类型的设备通常通过SCSI generic(sg)驱动程序访问 ...
  • selenium IDE命令全手册

    千次阅读 2017-11-16 10:06:42
    三类命令 Action:操作被测应用的状态,如“点击这个link”、“选择这个选项”。如果失败,测试运行停止。  每一个Action“XXX”都对应一个XXXAndWait命令。  XXXAndWait会告诉selenium这个XXX操作会向...
  • //必须用这个才能得到值,不能用$("#date2").value //alert(UserTime); //通报设置的时间 UserTime_Seconds=(new Date(UserTime)).getTime(); //也是必须用(new Date(p))才可以,此时获取的是字符串的秒数 ...
  • WPF学习第九集-深入浅出话命令

    千次阅读 2014-01-15 15:48:01
    WPF为我们准备了完善的命令系统,你可能会问:“有了路由事件为什么还需要命令系统呢?”。事件的作用是发布、传播一些消息,消息传达到了接收者,事件的指令也就算完成了,至于如何响应事件送来的消息事件做...
  • 有些网页的内容为什么不能复制

    千次阅读 2018-05-14 10:22:19
    有些网页的内容为什么不能复制?怎么才能将不可以复制的内容复制下来呢?估计在很多时候你会遇到很多的优美的比较实用的文章,你很想将其复制下来然后为己所用,但是可恨的是不知网页到底加了些什么东西搞得你复制不...
  • Flash动作命令全集

    千次阅读 2010-06-09 16:49:00
    在上例括号位置插入动态文本框,输入任何内容。该文本框变量名为:ans。在该帧适当 位置插入电影“对错提示”,该电影片断名属性为“ql”,在该电影片断上输人脚本: //键盘事件控制程序 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,051
精华内容 12,820
关键字:

命令按钮不能影响的事件是