| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
共有 669 人关注过本帖
标题:RichTextbox控件如何根据自身宽、高,以及用户设定的字体、字号和行距,计算 ...
只看楼主 加入收藏
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10698
专家分:43295
注 册:2014-5-20
收藏
得分:0 
回复 40楼 cssnet
重新设置后生效
试试选定之前输入的块再重新设置看看有效否
前天 17:31
sych
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:7
帖 子:420
专家分:648
注 册:2019-10-11
收藏
得分:0 
*_screen.LockScreen = .t.
with thisform.richtextbox1
   lnSelstart = lo1.Selstart
   lcRTF = .textRTF
   lcText = .text + REPLICATE(CHR(254), 2000)
*   .visible = .f.
   .text = lcText
* 统计一屏总行数(见上边帖子,略。)
* ...
* --------------
* 恢复现场
* --------------
   .textRTF = lcRTF
   .Selstart = lnSelstart
*   .visible = .T.
endwith
*_screen.LockScreen = .F.

注释掉这几句,我测试没有闪一下
*_screen.LockScreen = .t.
*   .visible = .f.
*   .visible = .T.
*_screen.LockScreen = .F.
前天 20:08
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:489
专家分:372
注 册:2013-10-4
收藏
得分:0 
以下是引用sych在2025-9-4 20:08:10的发言:
注释掉这几句,我测试没有闪一下
*_screen.LockScreen = .t.
*   .visible = .f.
*   .visible = .T.
*_screen.LockScreen = .F.


大致明白了,谢谢!不过,设置thisform.LockScreen = .t.应无坏处,理论上。


前天 20:52
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10698
专家分:43295
注 册:2014-5-20
收藏
得分:0 
参考示例,没有精准测试。
图片附件: 游客没有浏览图片的权限,请 登录注册

图片附件: 游客没有浏览图片的权限,请 登录注册

程序代码:
CLEAR
CLEAR ALL 

PUBLIC cDefPath
cDefPath = ADDBS(JUSTPATH(SYS(16)))
SET DEFAULT TO (cDefPath)

**    int GetRichEditCharsW(HWND hRichEdit, LPCWSTR text, char* cFontName, int nFontSize)
DECLARE integer GetRichEditCharsW IN TextMetric long,string@,string@,integer

**    int SetRichEditLineHeight(HWND hRichEdit, int nPixels)
DECLARE integer SetRichEditLineHeight IN TextMetric long,integer

**    int GetRichEditLineCount(HWND hRichEdit, char* pFontName, int nFontSize)
DECLARE integer GetRichEditLineCount IN TextMetric long,string@,integer

of = CREATEOBJECT("form1")
of.show(1)
CLEAR ALL 
RETURN

DEFINE CLASS form1 as Form 
    width       = 420
    height      = 420
    AllowOutput = .f.
    AutoCenter  = .t.
    ADD OBJECT edit as OleControl WITH left=10,top=10,width=400,height=400,;
        OleClass="RICHTEXT.RichtextCtrl.1"
    
    PROCEDURE init
        #if 1
            this.edit.font.name = "宋体"   
        #else
            this.edit.font.name = "微软雅黑"
        #endif
        this.edit.font.size = 12
        
        ** 行高 = 字高 + 行间距
        nLineHeight = FONTMETRIC(1,this.edit.font.name, MTON(this.edit.font.size)) + 5
        SetRichEditLineHeight(this.edit.hWnd, nLineHeight)    && 设置行高
        
        ** 获取总行数

        nLineCount = GetRichEditLineCount(this.edit.hWnd, this.edit.font.name, MTON(this.edit.font.size))

        this.Caption = "    FontName: "+this.edit.font.name;
                     + "    FontSize: "+TRANSFORM(MTON(this.edit.font.size));
                     + "    LineCount: "+TRANSFORM(nLineCount)

        ** 显示一页字(测试只显示一页)
        cText = REPLICATE("AaBbCcDdEeFfGgHhIiJjKk字字字字1234567890",100)
        cStr = ""    && 一页字串
        nCount = 0   && 行计数
        DO WHILE !EMPTY(cText) AND nCount < nLineCount
            ** 获取一行字串
            nChars = GetRichEditCharsW(this.edit.hWnd, STRCONV(cText,5), this.edit.font.name, MTON(this.edit.font.size)) 
            IF nChars < LENC(cText)    && 如果不是最后一行
                nChars = nChars - 1    && 减一个字,忽略边际不完整的字
            ENDIF 
            cStr  = cStr + LEFTC(cText,nChars) + 0h0D0A && 添加一行
            cText = SUBSTRC(cText, nChars+1)            && 下一行开始
            nCount = nCount + 1                         && 行计数
        ENDDO
        
        ** 显示输出
        this.edit.text = ""                                    && test方法会清除字体设置信息
        SetRichEditLineHeight(this.edit.hWnd, nLineHeight)     && 重新设置字体信息
        this.edit.SelText  = cStr
        this.edit.selstart = 0
    ENDPROC
ENDDEFINE

程序代码:
/*
    库文件 gdi32.lib
*/
#define DLLIMPORT_C extern "C" __declspec(dllexport)
#include <windows.h>
#include <richedit.h>

//获取 Rich Edit 字体信息并创建字体对象句柄
HFONT GetRichEditFontHandle(HWND hRichEdit, char* pFontName, int nFontSize)
{
    HDC hdc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);

    CHARFORMAT cf;
    ZeroMemory(&cf, sizeof(CHARFORMAT));
    cf.cbSize = sizeof(CHARFORMAT);

    // 获取当前选择文本的字符格式
    SendMessage(hRichEdit, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&cf);

    // 从CHARFORMAT创建字体对象
    HFONT hFont = CreateFont(
        -MulDiv(nFontSize, GetDeviceCaps(hdc,LOGPIXELSY), 72),   //转换单位
        0, 0, 0,
        (cf.dwEffects & CFE_BOLD) ? FW_BOLD : FW_NORMAL,
        (cf.dwEffects & CFE_ITALIC) ? TRUE : FALSE,
        (cf.dwEffects & CFE_UNDERLINE) ? TRUE : FALSE,
        (cf.dwEffects & CFE_STRIKEOUT) ? TRUE : FALSE,
        DEFAULT_CHARSET,
        OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS,
        DEFAULT_QUALITY,
        DEFAULT_PITCH | FF_DONTCARE,
        pFontName
    );

    DeleteDC(hdc);
    return hFont;
}

//获取 Rich Edit 在客户区一行字串的字数
DLLIMPORT_C int GetRichEditCharsW(HWND hRichEdit, LPCWSTR text, char* pFontName, int nFontSize)
{
    //获取控件尺寸和边距
    RECT rect;
    GetClientRect(hRichEdit, &rect);
    int editWidth = rect.right - rect.left;

    DWORD margins = SendMessage(hRichEdit, EM_GETMARGINS, 0, 0);
    editWidth -= (LOWORD(margins) + HIWORD(margins));

    HDC hdc = GetDC(hRichEdit);

    //获取当前字体
    HFONT hFont    = GetRichEditFontHandle(hRichEdit, pFontName, nFontSize);
    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);

    int len    = lstrlenW(text);
    int nChars = 0;
    SIZE sz;

    //计算一行的字数
    for (int i = 1; i <= len; i++) {
        if (!GetTextExtentPoint32W(hdc, text, i, &sz)) break;
        if (sz.cx > editWidth) break;
        nChars = i;
    }

    SelectObject(hdc, hOldFont);
    ReleaseDC(hRichEdit, hdc);
    return nChars;
}

//设置 Rich Edit 行高
DLLIMPORT_C int SetRichEditLineHeight(HWND hRichEdit, int nPixels)
{
    //获取当前设备DPI
    HDC hdc = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
    int dpi = GetDeviceCaps(hdc, LOGPIXELSY);
    DeleteDC(hdc);
    
    //设置行高
    PARAFORMAT2 pf;
    ZeroMemory(&pf, sizeof(PARAFORMAT2));
    pf.cbSize           = sizeof(PARAFORMAT2);
    pf.dwMask           = PFM_LINESPACING;
    pf.bLineSpacingRule = 4;                                        //精确行高
    pf.dyLineSpacing    = (nPixels * 20 * 72) / dpi;                //像素转换为缇
    return SendMessage(hRichEdit, EM_SETPARAFORMAT, 0, (LPARAM)&pf);
}

//获取 Rich Edit 客户区的行数
DLLIMPORT_C int GetRichEditLineCount(HWND hRichEdit, char* pFontName, int nFontSize)
{
    HDC hdc = GetDC(hRichEdit);

    // 强制重新获取当前字体
    HFONT hFont    = GetRichEditFontHandle(hRichEdit, pFontName, nFontSize);
    HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);

    //获取当前设备DPI
    HDC hdc2 = CreateDCW(L"DISPLAY", NULL, NULL, NULL);
    int dpi  = GetDeviceCaps(hdc2, LOGPIXELSY);

    // 获取行高
    PARAFORMAT2 pf;
    ZeroMemory(&pf, sizeof(PARAFORMAT2));
    pf.cbSize = sizeof(PARAFORMAT2);
    pf.dwMask = PFM_LINESPACING;
    SendMessage(hRichEdit, EM_GETPARAFORMAT, 0, (LPARAM)&pf);
    int lineHeight = 0;
    if (pf.dyLineSpacing > 0)
    {
        lineHeight = (pf.dyLineSpacing * dpi) / (20 * 72); // 转换为像素值
    }

    DeleteDC(hdc2);
    SelectObject(hdc, hOldFont);
    ReleaseDC(hRichEdit, hdc);
    
    // 计算客户区行数
    RECT rc;
    GetClientRect(hRichEdit, &rc);
    return rc.bottom / lineHeight;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)
{
    return TRUE;
}

vfp_RichEdit_Demo.rar (36.76 KB)


前天 23:57
cssnet
Rank: 5Rank: 5
等 级:职业侠客
威 望:5
帖 子:489
专家分:372
注 册:2013-10-4
收藏
得分:0 
以下是引用吹水佬在2025-9-4 23:57:43的发言:
参考示例,没有精准测试。


哇!牛逼 Turbo!牛逼 Ultra!
有C代码就好办啦,我想想办法,看能否翻译成VFP原生代码(估计DC能帮忙搞定一大半!最后自己再适当地修补一下下。)
有界面的东东,还是习惯赤条条不带个拖油瓶。

昨天 00:13
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10698
专家分:43295
注 册:2014-5-20
收藏
得分:0 
回复 45楼 cssnet
主要是调用windows api,转vfp应该无问题。
测试淘个方便才用C写给vfp用。



[此贴子已经被作者于2025-9-5 07:25编辑过]

昨天 07:06
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10698
专家分:43295
注 册:2014-5-20
收藏
得分:0 
以下是引用cssnet在2025-9-4 16:02:43的发言:

该死的屏幕,执行至此,总会闪一下!
无论如何设置,都会闪一下!
那么,聪明的,如何教他不要闪,只做一个安静的美男子呢?

LockScreen 是 Lock vfp窗口,对 richedit 可能无效。
试试:
SendMessage(hRichEdit, WM_SETREDRAW, 0, 0)    && Lock
SendMessage(hRichEdit, WM_SETREDRAW, 1, 0)    && UnLock

昨天 07:36
sych
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:7
帖 子:420
专家分:648
注 册:2019-10-11
收藏
得分:0 
以下是引用吹水佬在2025-9-5 07:36:15的发言:


LockScreen 是 Lock vfp窗口,对 richedit 可能无效。
试试:
SendMessage(hRichEdit, WM_SETREDRAW, 0, 0)    && Lock
SendMessage(hRichEdit, WM_SETREDRAW, 1, 0)    && UnLock

这个方法好用,这样随便在后台折腾,获取行数和列数后在刷新一下就OK了

[此贴子已经被作者于2025-9-5 08:45编辑过]

昨天 08:43
schtg
Rank: 13Rank: 13Rank: 13Rank: 13
来 自:Usa
等 级:贵宾
威 望:67
帖 子:2202
专家分:4711
注 册:2012-2-29
收藏
得分:0 
回复 44楼 吹水佬
学习啦,谢谢!
昨天 09:44
吹水佬
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:451
帖 子:10698
专家分:43295
注 册:2014-5-20
收藏
得分:0 
下面代码可以禁止 RichEdit 自动换行
#define WM_USER               0x0400
#define EM_SETTARGETDEVICE    WM_USER + 72   
SendMessage(hRichEdit, EM_SETTARGETDEVICE, 0, 1)  && 禁止自动换行

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



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

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