| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
共有 996 人关注过本帖, 1 人收藏
标题:RichTextbox控件如何根据自身宽、高,以及用户设定的字体、字号和行距,计算 ...
只看楼主 加入收藏
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
以下是引用sych在2025-9-6 11:11:27的发言:

另外如果用字符串,可以用消息传递
Declare INTEGER SendMessage in WIN32API as sendmessage_c2 INTEGER hwnd , INTEGER wMsg , INTEGER wParam , string lParam
#defi EM_REPLACESEL 0xC2
SendMessage_c2(this.edit.hwnd, EM_REPLACESEL, 1, 0hefbbbf+0hc58b)  &&这里要带上标记

UTF-8字串输入在C测试正常,偷点懒贴代码,很简单的。
vfp测试代码:
SetTextUtf8(this.edit.hWnd, STRCONV(0h0D0A+"abc字字123"+0h0D0A+"si",9)+0hC58B)
C代码:
程序代码:
//输入UTF-8字串
DLLIMPORT_C void SetTextUtf8(HWND hRichEdit, LPVOID* pTextUtf8)
{
    SETTEXTEX stx;                                                          //SETTEXTEX {DWORD flags; UINT codepage}
    stx.flags    = ST_SELECTION;                                            //#define ST_SELECTION  2
    stx.codepage = CP_UTF8;                                                 //#define CP_UTF8       65001
    SendMessage(hRichEdit, EM_SETTEXTEX, (WPARAM)&stx, (LPARAM)pTextUtf8);  //#define EM_SETTEXTEX  0x0461
}


前天 14:20
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
顺便也试一下保存UTF-8字串,再偷点懒贴代码,也很简单的。
vfp测试代码:
程序代码:
        textUtf8 = REPLICATE(0h00, 10000)    &&要足够大
        len = GetTextUtf8(this.edit.hWnd, @textUtf8, 10000) 
        STRTOFILE(LEFT(textUtf8,len), "utf8.txt", 4)

C代码
程序代码:
//保存为UTF-8字串
DLLIMPORT_C UINT GetTextUtf8(HWND hRichEdit, LPVOID* pBuffer, UINT bufferSize)
{
    GETTEXTEX gtx;  //GETTEXTEX {DWORD cb; DWORD flags; UINT codepage; LPCSTR lpDefaultChar; LPBOOL lpUsedDefChar;}
    gtx.cb            = bufferSize;
    gtx.flags         = GT_USECRLF; //#define GT_USECRLF    1
    gtx.codepage      = CP_UTF8;    //#define CP_UTF8       65001
    gtx.lpDefaultChar = NULL;
    gtx.lpUsedDefChar = NULL;
    return SendMessage(hRichEdit, EM_GETTEXTEX, (WPARAM)&gtx, (LPARAM)pBuffer); //#define EM_GETTEXTEX  0x045E
}


前天 14:52
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
完善一下上面保存的过程,增加获取缓冲字节数的函数,不用去乱猜。
vfp代码:
程序代码:
        ** 保存UTF-8字串
        size = GetTextLenGthex(this.edit.hWnd)
        textUtf8 = REPLICATE(0h00, size)
        len = GetTextUtf8(this.edit.hWnd, @textUtf8, size) 
        STRTOFILE(LEFT(textUtf8,len), "utf8.txt", 4)

C代码
程序代码:
//获取RichEdit编辑的UTF-8字节数
DLLIMPORT_C UINT GetTextLenGthex(HWND hRichEdit)
{
    GETTEXTLENGTHEX gtl;            //GETTEXTLENGTHEX {DWORD flags; UINT  codepage;}
    gtl.flags    = GTL_NUMBYTES;    //#define GTL_NUMBYTES  16      返回字节数
    gtl.codepage = CP_UTF8;         //#define CP_UTF8       65001   UTF-8编码
    return SendMessage(hRichEdit, EM_GETTEXTLENGTHEX, (WPARAM)&gtl, 0); //#define EM_GETTEXTLENGTHEX    0x045F
}

前天 17:35
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:494
专家分:372
注 册:2013-10-4
收藏
得分:0 
回到顶楼“1行有几列?”的原始问题。
在UTF-8领空,我遇到了好些莫名其妙的意外状况,挺随机的,也无法复现:
有时会返回1,有时会返回1000(可能因为REPLICATE(0hA1, 1000)填充了1000次的缘故吧)。
退一步想想,其实我的需求,也并非要那么精确,精确到“X列 * Y行 = N个字符”的地步;权衡再三,最终决定放弃治疗,还是用回自己先前不那么精确的“神秘参数”版本罢……

这一次的讨论过程,确实是学到了不少新知识,在此特别感谢吹版和sych二位英雄的精彩展示!
尤其下边这一帖,属实是意外惊喜!——

以下是引用吹水佬在2025-9-5 07:36:15的发言:
LockScreen 是 Lock vfp窗口,对 richedit 可能无效。
试试:
SendMessage(hRichEdit, WM_SETREDRAW, 0, 0)    && Lock
SendMessage(hRichEdit, WM_SETREDRAW, 1, 0)    && UnLock



前天 22:54
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
回复 84楼 cssnet
用一个字符来填充来算不太精确,除非字体固定用等宽字体。

前天 23:10
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
这样试试:
输入要显示的字串-->取第一屏字数-->显示一屏字
下一屏就是去掉上屏字数的字串继续上面的步骤。
程序代码:
oRichEdit = this.edit 
hRichEdit = oRichEdit.hWnd

DECLARE long SendMessage   IN user32 long,long,long,long
DECLARE long SendMessage   IN user32 as SendMessage2 long,long,long,string@
DECLARE long SendMessage   IN user32 as SendMessage3 long,long,string@,string@
DECLARE long SendMessageW  IN user32 long,long,long,string@
DECLARE long GetClientRect IN user32 long,string@
#define WM_SETREDRAW        0x000B
#define EM_SETPARAFORMAT    0x0447    &&(WM_USER + 71)
#define ST_SELECTION        2
#define CP_UTF8             65001
#define EM_SETTEXTEX        0x0461
#define WM_SETTEXT          0x000C
#define EM_GETLINE          0x00C4

SendMessage(hRichEdit, WM_SETREDRAW, 0, 0)        && LockScreen
oRichEdit.text = ""
**用户区高
rc = REPLICATE(0h00,16)
GetClientRect(hRichEdit, @rc)
nClientHeight = CTOBIN(RIGHT(rc,4),"4rs")
**行高
nLineHeight = FONTMETRIC(1,oRichEdit.font.name, MTON(oRichEdit.font.size)) + 5
&&设置行高
pf = BINTOC(188,"4RS") + BINTOC(256,"4RS") + REPLICATE(0h00,156);
   + BINTOC(nLineHeight*15,"4RS") + 0h0000 + BINTOC(4,"1RS") + REPLICATE(0h00,17)
SendMessage2(hRichEdit, EM_SETPARAFORMAT, 0, @pf)
**用户区行数
nClientLines = INT(nClientHeight / nLineHeight)
**填字串(UTF-8)
cText = REPLICATE("abc字字123",1000)
textUtf8 = STRCONV(cText,9)
stx = BINTOC(ST_SELECTION,"4rs") + BINTOC(CP_UTF8,"4rs")
SendMessage3(hRichEdit, EM_SETTEXTEX, stx, textUtf8)
oRichEdit.selstart = 0
**算计一屏
nSize   = 2048    && 要足够大
cBuffer = BINTOC(nSize,"4rs") + REPLICATE(0h00,nSize)
i = 0
nWordCount = 0
nWordLine  = SendMessageW(hRichEdit, EM_GETLINE, i, @cBuffer)
DO WHILE (nWordLine > 0) AND (i < nClientLines)
    nWordCount = nWordCount + nWordLine 
    i = i+1
    nWordLine = SendMessageW(hRichEdit, EM_GETLINE, i, @cBuffer)
ENDDO
**显示一屏
oRichEdit.text = ""
SendMessage3(hRichEdit, EM_SETTEXTEX, stx, STRCONV(LEFTC(cText,nWordCount),9))
oRichEdit.selstart = 0
SendMessage(hRichEdit, WM_SETREDRAW, 1, 0)        && UnLockScreen



[此贴子已经被作者于2025-9-7 10:13编辑过]

昨天 10:02
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
这样做总觉得有点另类
通常都是控制字串的屏首位置字符(或自动翻屏,好像按一下PgDn)

昨天 10:19
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:494
专家分:372
注 册:2013-10-4
收藏
得分:0 
其实,最初对RichEdit/RichTextbox发生兴趣,还是因为该死的 Markdown。

对于 Markdown,我有一个大胆想法。试考虑这个闭环:

假设日后我们能找到一组相对完美的可逆的双向转换代码库:

RTF --> Markdown
Markdown --> RTF

那么,我们便可以利用 RichEdit 来编辑/显示 Markdown 格式文档了!

让我来分析一下流程:

===============
1、打开一个 .MD 文档;
2、调用“Markdown --> RTF”,将 Markdown 标记转换为 RTF 标记;
3、利用RichEdit,WYSIWYG 编辑此 RTF 文档,以类似 Typora 的方式!而最终用户根本不可能知晓:此时此刻,我们内部编辑处理的,其实是 RTF 标记文档;
4、编辑结束,存档。此时调用“RTF --> Markdown”,将最终文档保存为 .MD 格式。
===============

整个文档编辑、修改的过程,我们的编辑器,根本无需真的去解析、渲染 Markdown 格式文档,一直都处在最古老的 RTF 领空!然而却能够实现近乎完美的 Markdown 实时 WYSIWYG 编辑!

这是最初的构想。

当然,这一切取决于如下必要前提——

在这个星球上,存在一组相对完美的、可逆的“Markdown <--> RTF”双向转换代码库。

可惜目前暂未能找到合适的转换库。Pandoc 据说可以实现双向转换,还是开源的,可惜太大啦,100MB+,且是64位,我试了一个多星期,都无办法将其编译成32位、小于10MB的DLL,以供VFP代码调用。

以上。就是我琢磨 RichEdit 的深层的原因所在啊!
昨天 14:59
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10713
专家分:43295
注 册:2014-5-20
收藏
得分:0 
回复 88楼 cssnet
你这是想大工程搞小动作。
如果你首贴是这个也许我不会去理会RICH EDIT控件。
还以为只是简单的几行几列的小事通过EDIT控件解释一下就算。
到头来还是要花了一个晚上通读RICH EDIT的消息和结构,看来是白花了。
昨天 16:01
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:494
专家分:372
注 册:2013-10-4
收藏
得分:0 
以下是引用吹水佬在2025-9-7 16:01:45的发言:

你这是想大工程搞小动作。
如果你首贴是这个也许我不会去理会RICH EDIT控件。
还以为只是简单的几行几列的小事通过EDIT控件解释一下就算。
到头来还是要花了一个晚上通读RICH EDIT的消息和结构,看来是白花了。


什么“大工程”?哦,明白了,吹版可能误解了。我的意思是:

如果能找到一个DLL库,只需包含这两个函数:MD2RTF 和 RTF2MD,且此二函数可逆;那么,现有的Richtextbox控件,无需任何额外改造,就能够支持在VFP中显示与编辑 Markdown 格式的文档了!
“RTF 《==》 MD”转换的库,大把,网上是现成的啊,只是大多不是C,也不可逆,难以编译成32位DLL而已。
话说,那也只不过私下里随便那么一想,并无什么雄心壮志。

RichEdit是目前仍在维护的古早工程里,实际用到的控件;而这一个行、列计算的遗留Bug,也是一直未得到精确解决方案的实际遗留问题。


[此贴子已经被作者于2025-9-7 17:46编辑过]

昨天 16:23
快速回复:RichTextbox控件如何根据自身宽、高,以及用户设定的字体、字号和行距 ...
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.039927 second(s), 10 queries.
Copyright©2004-2025, BC-CN.NET, All Rights Reserved