栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

EDIT控件只读模式及实践问题

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

EDIT控件只读模式及实践问题

EDIT控件实现只读模式


先说三种使EDIT控件实现只读模式的简单方式,然后由于这三种方式不能满足要求,最后又引出两种稍复杂的方式。这三种简单方式如下:
1、设置EDIT控件窗口风格,使窗口风格中含有ES_READONLY属性。
    ::SetWindowLong(hEdit,GWL_STYLE,oldstyle|ES_READONLY);
2、向EDIT控件窗口发送EM_SETREADONLY 消息。
    ::SendMessage(hEdit,EM_SETREADONLY,TRUE,0);
3、使用EnableWindow函数禁用EDIT控件窗口
    ::EnableWindow(hEdit,FALSE);
但是以上三种简单方式的效果差不多,虽然实现了只读,但都会使用EDIT控件窗口变灰。下面介绍两种可以让EDIT控件实现只读同时又不变灰的方法:

第一种,借助父窗口让EDIT控件实现只读同时又不变灰的方法。

这种方法要借助上面介绍的三种简单方式先把EDIT控件改为只读,然后再让EDIT控件保持不灰。只读模式的EDIT控件不再向父窗口发送WM_CTLCOLOREDIT通知,而是改为发送WM_CTLCOLORSTATIC通知。
父窗口可以在对WM_CTLCOLOREDIT和WM_CTLCOLORSTATIC通知的响应函数中设置EDIT控件的背景和文本颜色为任意值。

BOOL MyDialog::OnEditCtrlColor(WPARAM wParam,LPARAM lParam)
{
    //设置红色的文本
    ::SetTextColor((HDC)wParam,RGB(255,0,0)); 
    //设置黑色的背景      
    ::SetBkColor((HDC)wParam,RGB(0,0,0));     
    //返回背景色对应的刷子句柄
    ::SetWindowLong(this->Handle(),DWL_MSGRESULT,::CreateSolidBrush(clr));
    return TRUE;
}


第二种,通过子类化EDIT控件实现只读同时又不变灰的方法。

STEP1、派生自己的EDIT控件类edit。

派生的目的是实现对EDIT控件的子类化。如果你使用的基类不能自动子类化EDIT控件,那就需要你在Create之后自己调用SetWindowLong来子类化。这里使用的基类rubbish::window虽然会自动子类化EDIT控件,但派生类还需要重载rubbish::window::OnWndMsg函数才能实现对改变EDIT控件内容的行为拦截。

    class edit:public rubbish::window
    {
		BOOL m_isReadOnly;
		......
	public:
		void setReadOnley(BOOL isReadOnly){m_isReadOnly = isReadOnly;}
	private:
		//重载rubbish::window::OnWndMsg函数
		virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);
	};

   SETP2、重载OnWndMsg函数,如果控件处于只读模式,就阻止可以更改控件内容的动作。
    BOOL edit::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
	{
		if(!m_isReadOnly)
		{
            //如果控件未处于只读模式,就返回FALSE,交由控件的原生过程函数处理
            return FALSE;
        }
        //下面是控件处于只读模式时的代码逻辑
        ......
	}

需要拦截的动作有三种,第一种来自系统菜单:

鼠标在EDIT控件窗口上单击右键,就会出现上图菜单。 菜单中的“复制”和“全选”不会改变控件内容,"剪切"、“粘贴”、“删除”等却会改变控件内容,它们对应着WM_CUT、WM_PASTE等系统命令。所以重载后的OnWndMsg函数绝不能让EDIT控件的原生过程处理这些命令。代码部分如下:

    BOOL edit::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
	{
		if(!m_isReadOnly)
		{
            //如果控件未处于只读模式,就返回FALSE,交由控件的原生过程函数处理
            return FALSE;
        }
        //下面是控件处于只读模式时的代码逻辑
        switch(message)
		{
			case WM_CUT:
			case WM_PASTE:
			case WM_CLEAR:
			case WM_UNDO:
				return TRUE;//阻止命令菜单
				break;
            ......
        }
	}

第二种需要拦截的行为是来自DELETE键。当DELETE键被按下时,系统会向控件发送WM_KEYDOWN消息,同时wParam中包含着VK_DELETE虚拟键。

    BOOL edit::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
	{
        ......
        //下面是控件处于只读模式时的代码逻辑
        
        switch(message)
		{
			......

            case WM_KEYDOWN:
				switch(wParam)
				{
				case VK_DELETE:
					return TRUE;//阻止删除键
					break;
				default:
					break;
				}
				break;
            ......
        }
	}

第三种是对WM_CHAR行为的拦截。但是并非所有的WM_CHAR行为都可以拦截,例如,当CTRL功能键被按下时如果不允许控件的原生过程处理的话,WM_PASTE、WM_COPY这些消息就不会产生。只读模式只是不允许改变控件内容,但复制控件的内容应该是允许的。所以还必须产生WM_COPY才行!

    BOOL edit::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
	{
        ......
        //下面是控件处于只读模式时的代码逻辑
        
        switch(message)
		{
			......

            case WM_CHAR:
				if (::GetKeyState(VK_CONTROL) >= 0 )
				{
					return TRUE;//阻止通过键盘敲入字符
				}
				break;
            ......
        }
	}

经过这样的重载之后,EDIT控件已经实现了不变灰的只读模式。使用这个控件类,只需要调用它的void setReadOnley(BOOL isReadOnly)函数就可以在只读模式和正常模式之间切换,比依赖父窗口的方案更适合封装成类库。这正是rubbish的实现方式。

下面是使用过程中遇到的一个问题,解决之后发现是一个误会,但还是值得注意:

EDIT控件只读模式的实践问题

(https://download.csdn.net/download/freex64/21081882)

上图界面是一个基于MDI框架的小工具,在文档区的左边有一些EDIT控件用来输入一些参数。但是当像上图那样选中“FreeX64”然后按下CTRL+C时却无法把选中的“FreeX64”放到粘贴板里去。一开始还以为是重载后的OnWndMsg函数代码有问题,后来才发现原来是应用程序的资源里有一个“加速键表”,而这个“加速键表”里已经有一个CTRL+C了。因此CTRL+C被rubbish::MDIFrame拦截而没有发往控件。

解决办法就是:在rubbish::MDIFrame::PreTranslateMessage里先判断当前键盘焦点在哪个窗口里,若是rubbish::MDIFrame不关心的窗口,就交由默认函数处理过程!完美解决,下面是具体代码:

BOOL MDIFrame::PreTranslateMessage(MSG* lpMsg)
{
	if ( TranslateMDISysAccel (this->m_Client.Handle(), lpMsg) != FALSE)
	{
		return TRUE;
	}
	rubbish::Window * activeViewPtr = this->GetActiveView();
	if(activeViewPtr)
	{
		HWND const hFoucsWnd = ::GetFocus();
		if(hFoucsWnd == NULL || ::IsChild(activeViewPtr->Handle(),hFoucsWnd) != 0 )
		{
			if(activeViewPtr->PreTranslateMessage(lpMsg)!= FALSE)
			{
				return TRUE;
			}
		}
	}
	return RBSFrame::PreTranslateMessage(lpMsg); 
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/980042.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号