MFC基于CWnd重写CEdit控件

时间:2021-09-13 00:05:24
问题:
1.Unicode下,一个中文字占一个字符,在显示上占两个字符的宽度;多字节下,一个中文字占两个字符,在显示上占两个字符的宽度;这个中文字应该要怎么处理?
2.用什么方法将鼠标点击的坐标转换成光标位置?(多字节下,在点击中文字的时候,光标位置会因为占用两个字符而出现在中文字的中间)
3.当输入的字符串大于控件长度时,怎么实现自动滚动?
4.怎么实现选中文本删除操作?
针对这四个问题,求大神指点下···

18 个解决方案

#1


在线等···· MFC基于CWnd重写CEdit控件

#2


我倒是觉得你用CListBox比较合适 MFC基于CWnd重写CEdit控件

#3


引用 2 楼 swwllx 的回复:
我倒是觉得你用CListBox比较合适 MFC基于CWnd重写CEdit控件

为什么?
列表框又不能输入···

#4


重写Edit没必要吧,可以参考windowless RichEdit来做好了
https://www.codeproject.com/articles/15906/using-windowless-richedit-controls

#5


引用 4 楼 hurryboylqs 的回复:
重写Edit没必要吧,可以参考windowless RichEdit来做好了
https://www.codeproject.com/articles/15906/using-windowless-richedit-controls

我其他简单的控件都重写的差不多了,就是这个Edit有点难度,而且自带的太难看了,想弄好看点

#6


就用我刚才发的这个很好看的,而且支持的东西还多

#7


重写Edit需要做大量额外的工作,包括光标的处理等等事情。如果使用单一字体使用CEdit;如果多种字体并存使用CRichEdit一般就能满足要求;楼主是打算展示实力?

#8


这种一般用ListBox轻松实现啊
提供一点思路,我帮忙另一个网友写的函数这个是:
功能:在ListBox中刷新显示,并且将显示内容存储下来,你重点看显示部分

//Display information into the list
VOID CXXXXDlg::LogInfo(LPCTSTR tszlogMsg, int iColor, BOOL bAppend)
{
int dx  = 0;
CDC* pDC;
DWORD dwLineIndex=0;
FILE* pLogFile = NULL;
CString         strMsg;
CSize sz;
CString         strToken;
        COLORREF    itemColor;
CString strValue;
CString strFilePath;
CFile LogFile;
CTime sysTime;
CString strTime;
CString strHour;
CString strMin;
CString strSec;
CString strLogTime;
CString strLOG;

strFilePath.Format("%s\\config\\LOG_INFORMATION.ini", m_tszAppFolder);

switch(iColor)
{
case RED:
itemColor = RGB(255, 0, 0);
break;

case GREEN:
itemColor = RGB(0, 255, 0);
break;

case BLUE:
itemColor = RGB(0, 0, 255);
break;

case PURPLE:
itemColor = RGB(160, 32, 240);
break;

case CYAN:
itemColor = RGB(0, 255, 255);
break;
}

pDC = m_ColorListBox.GetDC();
dwLineIndex = m_ColorListBox.GetCount();

// if the lines is more than 256
// clear the message here

if(dwLineIndex > MAX_LIST_LINES)
{
m_ColorListBox.ResetContent();
dwLineIndex = 0;
}
    
//if bAppend true,line feed
if (bAppend)
{
strToken = strtok((char *)tszlogMsg, "\r\n");
strToken.Replace("\t", "    ");
m_ColorListBox.AddString(strToken);
while (strToken != "")
{
strToken = strtok(NULL, "\r\n");
strToken.Replace("\t", "     ");
m_ColorListBox.AddString(strToken, itemColor);
strValue.Format("%s", strToken);
}
}
else
m_ColorListBox.AddString(tszlogMsg, itemColor);

strValue.Format("%s", tszlogMsg);
sysTime = CTime::GetCurrentTime();
strTime = sysTime.Format("%Y-%m-%d");
int hour = sysTime.GetHour();
strHour.Format(" %d:", hour);
int Min = sysTime.GetMinute();
strMin.Format("%d:", Min);
int Sec = sysTime.GetSecond();
strSec.Format("%d ", Sec);
strLogTime = strTime + strHour + strMin + strSec;
strLOG = strLogTime + strValue;
//Backup:

LogFile.Open(strFilePath, CFile::modeReadWrite);
LogFile.SeekToEnd();
LogFile.Write(strLOG.GetBuffer(0), strLOG.GetLength());
LogFile.Write(_T("\r\n"), 2*sizeof(wchar_t));

m_ColorListBox.SetCurSel(dwLineIndex);

if (dwLineIndex > 8)
{
m_ColorListBox.SetTopIndex(dwLineIndex - 8);
}

for (DWORD i = 0; i < dwLineIndex + 1; i++)
{
m_ColorListBox.GetText(i, strMsg);
sz = pDC->GetTextExtent(strMsg);

if (sz.cx > dx)
dx = sz.cx;
}
m_ColorListBox.ReleaseDC(pDC);

// Set the horizontal extent so every character of all strings 
// can be scrolled to.
m_ColorListBox.SetHorizontalExtent(dx + 10);

UpdateWindow();
}

#9


我使用CEdit主要是感觉控件不能透明显示,而且字体样式比较难看。

我现在实现了CEdit的基础功能(3D字体显示,背景透明,输入英文字符和数字),
就是在有中文字的处理上会出现一些误差,还有就是选中删除剪切处理上有问题

#10


细节决定成败,上代码。

#11


代码上不了,都在公司电脑里···
1.处理鼠标点击位置转化成光标位置的原理:
把输入的字符进行for循环,获取对应字符到起始字符的长度,然后和鼠标点击的坐标进行比较,得出鼠标点击位置的前后两个字符序号,然后设置光标位置。
2.选中字符串的处理原理:
在鼠标按下时间开始,把鼠标位置转换成字符序号,然后根据字符序号来截取对应的字符串,然后进行其他处理。

大概的原理就是这样,这其中有中文字就会出现误差,就是因为一个中文字的宽度导致的,还在想办法解决···
不知道我这样处理好不好,请大神们指教···

#12


最难的控件就是编辑框了

#13


给你顶下,每个控件自绘的都是充满了汗水

#14


自绘是早晚要学会的技能。

#15


听说CEdit和CRichEdit都有类似的开源项目的源码可供参考。

#16


不是有个开源的EDIT吗? Scintilla 

#17


使用炫彩界面库的 RichEdit ,支持背景透明; 

#1


在线等···· MFC基于CWnd重写CEdit控件

#2


我倒是觉得你用CListBox比较合适 MFC基于CWnd重写CEdit控件

#3


引用 2 楼 swwllx 的回复:
我倒是觉得你用CListBox比较合适 MFC基于CWnd重写CEdit控件

为什么?
列表框又不能输入···

#4


重写Edit没必要吧,可以参考windowless RichEdit来做好了
https://www.codeproject.com/articles/15906/using-windowless-richedit-controls

#5


引用 4 楼 hurryboylqs 的回复:
重写Edit没必要吧,可以参考windowless RichEdit来做好了
https://www.codeproject.com/articles/15906/using-windowless-richedit-controls

我其他简单的控件都重写的差不多了,就是这个Edit有点难度,而且自带的太难看了,想弄好看点

#6


就用我刚才发的这个很好看的,而且支持的东西还多

#7


重写Edit需要做大量额外的工作,包括光标的处理等等事情。如果使用单一字体使用CEdit;如果多种字体并存使用CRichEdit一般就能满足要求;楼主是打算展示实力?

#8


这种一般用ListBox轻松实现啊
提供一点思路,我帮忙另一个网友写的函数这个是:
功能:在ListBox中刷新显示,并且将显示内容存储下来,你重点看显示部分

//Display information into the list
VOID CXXXXDlg::LogInfo(LPCTSTR tszlogMsg, int iColor, BOOL bAppend)
{
int dx  = 0;
CDC* pDC;
DWORD dwLineIndex=0;
FILE* pLogFile = NULL;
CString         strMsg;
CSize sz;
CString         strToken;
        COLORREF    itemColor;
CString strValue;
CString strFilePath;
CFile LogFile;
CTime sysTime;
CString strTime;
CString strHour;
CString strMin;
CString strSec;
CString strLogTime;
CString strLOG;

strFilePath.Format("%s\\config\\LOG_INFORMATION.ini", m_tszAppFolder);

switch(iColor)
{
case RED:
itemColor = RGB(255, 0, 0);
break;

case GREEN:
itemColor = RGB(0, 255, 0);
break;

case BLUE:
itemColor = RGB(0, 0, 255);
break;

case PURPLE:
itemColor = RGB(160, 32, 240);
break;

case CYAN:
itemColor = RGB(0, 255, 255);
break;
}

pDC = m_ColorListBox.GetDC();
dwLineIndex = m_ColorListBox.GetCount();

// if the lines is more than 256
// clear the message here

if(dwLineIndex > MAX_LIST_LINES)
{
m_ColorListBox.ResetContent();
dwLineIndex = 0;
}
    
//if bAppend true,line feed
if (bAppend)
{
strToken = strtok((char *)tszlogMsg, "\r\n");
strToken.Replace("\t", "    ");
m_ColorListBox.AddString(strToken);
while (strToken != "")
{
strToken = strtok(NULL, "\r\n");
strToken.Replace("\t", "     ");
m_ColorListBox.AddString(strToken, itemColor);
strValue.Format("%s", strToken);
}
}
else
m_ColorListBox.AddString(tszlogMsg, itemColor);

strValue.Format("%s", tszlogMsg);
sysTime = CTime::GetCurrentTime();
strTime = sysTime.Format("%Y-%m-%d");
int hour = sysTime.GetHour();
strHour.Format(" %d:", hour);
int Min = sysTime.GetMinute();
strMin.Format("%d:", Min);
int Sec = sysTime.GetSecond();
strSec.Format("%d ", Sec);
strLogTime = strTime + strHour + strMin + strSec;
strLOG = strLogTime + strValue;
//Backup:

LogFile.Open(strFilePath, CFile::modeReadWrite);
LogFile.SeekToEnd();
LogFile.Write(strLOG.GetBuffer(0), strLOG.GetLength());
LogFile.Write(_T("\r\n"), 2*sizeof(wchar_t));

m_ColorListBox.SetCurSel(dwLineIndex);

if (dwLineIndex > 8)
{
m_ColorListBox.SetTopIndex(dwLineIndex - 8);
}

for (DWORD i = 0; i < dwLineIndex + 1; i++)
{
m_ColorListBox.GetText(i, strMsg);
sz = pDC->GetTextExtent(strMsg);

if (sz.cx > dx)
dx = sz.cx;
}
m_ColorListBox.ReleaseDC(pDC);

// Set the horizontal extent so every character of all strings 
// can be scrolled to.
m_ColorListBox.SetHorizontalExtent(dx + 10);

UpdateWindow();
}

#9


我使用CEdit主要是感觉控件不能透明显示,而且字体样式比较难看。

我现在实现了CEdit的基础功能(3D字体显示,背景透明,输入英文字符和数字),
就是在有中文字的处理上会出现一些误差,还有就是选中删除剪切处理上有问题

#10


细节决定成败,上代码。

#11


代码上不了,都在公司电脑里···
1.处理鼠标点击位置转化成光标位置的原理:
把输入的字符进行for循环,获取对应字符到起始字符的长度,然后和鼠标点击的坐标进行比较,得出鼠标点击位置的前后两个字符序号,然后设置光标位置。
2.选中字符串的处理原理:
在鼠标按下时间开始,把鼠标位置转换成字符序号,然后根据字符序号来截取对应的字符串,然后进行其他处理。

大概的原理就是这样,这其中有中文字就会出现误差,就是因为一个中文字的宽度导致的,还在想办法解决···
不知道我这样处理好不好,请大神们指教···

#12


最难的控件就是编辑框了

#13


给你顶下,每个控件自绘的都是充满了汗水

#14


自绘是早晚要学会的技能。

#15


听说CEdit和CRichEdit都有类似的开源项目的源码可供参考。

#16


不是有个开源的EDIT吗? Scintilla 

#17


使用炫彩界面库的 RichEdit ,支持背景透明; 

#18