zoukankan      html  css  js  c++  java
  • RichEdit

    RichEdit的奥妙

    一、如何得知当前行号
      用RichEdit(或者memo)控件制作文本编辑器时,通过访问lines�count属性可以得到总行数,但是若想知道光标当前所在行的行号就麻烦了,因为delphi没有提供这个属性。要实现这个编辑器必备功能,就须调用em_ LineFromChar。请试试下面的程序。
      先在窗口中布置一个RichEdit或者memo(命名为editor),以及一个button。在button的onclick事件中写入下列代码。
      var
      CurrentLine:Integer;
      begin
      CurrentLine:=Editor�Perform(em_ LineFromChar,SFFFF,0);
      Application�MessageBox(PChar(′当前行号是′+IntToStr(CurrentLine)),′消息′,mb_ iconinformation);
      end;
      需要注意的是,第一行的行号为零。
      二、如何撤消操作(undo)
      对于memo来说,实现undo是不需编程的,只要让popupmenu属性为空,运行时就能用鼠标右键激活一个常用操作菜单,其中包括撤消、剪切、复制、粘贴、删除和全选六项。
      但可惜的是,这一招对于功能强大的RichEdit控件居然行不通,害得我们还要自己设计一个popupmemu。当你用CutToClipBoard等语句轻松而顺利地完成了“剪切”等功能,接着便会无奈地发现,竟找不到undo或cancel之类的语句来执行“撤消”。
      这时你需要这样处理:
      RichEdit1�Perform(EM_UNDO,0,0);
      另外还应检查是否允许撤消,从而开启或关闭弹出菜单中的“撤消”项:
      Undo1�Enabled:=RichEdit�Perform(EM_CANUNDO,0,0)<>0;
      以上程序在Delphi3中调试通过
    View Code

    JEDI JVCL组件安装

      JVCL组件是一套开源的VCL组件库,目前最新的版本是3.0,但其自带的Install.bat安装时从目前看存在一些问题,无法完成正常安装,下面是我在Delphi 7上安装时的提示,说是找不到system.pas,由于懒得找具体原因,就直接打开项目包文件进行安装。
    build.exe found. Pretest: ok
    Using d7 for build process.
    MAKE Version 5.2  Copyright (c) 1987, 1998 Inprise Corp.
    MAKE Version 5.2  Copyright (c) 1987, 1998 Inprise Corp.
    Borland Delphi for Win32 compiler version 18.0
    Copyright (c) 1983,2005 Borland Software Corporation
    JediInstaller.dpr(1) Fatal: F2063 Could not compile used unit 'System.pas'
    ** error 1 ** deleting ..inJediInstaller.exe
    ** error 1 ** deleting installer
    Press ENTER to continue
      在安装的时候,注意要先安装JCL,我试图直接安装JVCL,提示找不到文件,先安装JCL后再安装就不存在这个问题。安装到组件面板上的安装包以D结尾,可以Install,以R结尾的只要编译就可以了。
      安装完成后,需要在搜索路径中加入JCLSource、JCLSourceCommon、JCLSourceWindows、JVCLRun、JVCLCommon目录到搜索路径中。
    View Code

    XE2安装JVCL

    XE2安装JVCL
    1. 下载:
    要分别下载JCL和JVCL安装包,不可以图省事不下载前者。
    http://sourceforge.net/projects/jcl/files/JCL%20Releases/JCL%202.4%20Build%204571/jcl-2.4.1.4571.zip/download
    http://sourceforge.net/projects/jvcl/files/JVCL%20Help%20Files/JVCL%203.41%20Help/jvcl-3.41-pdfhelp.zip/download
    2. 安装JVCL
    必须先安装JCL。虽然JVCL压缩包本身包含JCL,但那个可以废弃(改个名字),另外下载JCL,然后编译
    E:Editor_goodPython_IDEComposantsjclinstallJCLInstall.dpr
    然后编译:
    E:Editor_goodPython_IDEComposantsjvclinstallJVCLInstallJVCLInstall.dpr
    编译成功后,关掉所有Delphi进行安装
    如果遇到编译问题,则修改(屏蔽两句话):
    jvcldevtoolsPackagesGeneratorGenerateDefines.pas
    uses
    //{$IFDEF HAS_UNIT_TYPES}
    //System.Types,
    //{$ENDIF HAS_UNIT_TYPES}
    SysUtils, JclStrings;
    ---------------------------
    3. 加入路径:
    JCLSource
    JCLSourceCommon
    JCLSourceWindows
    JVCLRun
    JVCLCommon
    目录到搜索路径中。
    
    备注,不清楚install.bat有什么用处,留待下次研究。
    View Code

    delphi 2009 调用Msftedit.dll,重写Richedit,能更好地支持RTF,特别是画表格

    delphi 2009 调用Msftedit.dll,重写Richedit,能更好地支持RTF,特别是画表格
    
    画表格的具体思路分析
    
    4个步骤:
    
    1 指定类名称 RichEdit50W
    
    var
    FMoudlEdit:THandle;
    const
    RichEdit41ModuleName = 'Msftedit.dll';
    RichEdit41ClassName = 'RichEdit50W';
    
    2 从TCustomRichEdit继承
    
    TRichEdit41=class(TCustomRichEdit)
    private
    protected
        procedure CreateParams(var Params: TCreateParams);override;
    public
    
    3 重些CreateParams
    
    procedure TRichEdit41.CreateParams(var Params: TCreateParams);
    begin
    if FMoudlEdit = 0 then
    begin
        FMoudlEdit := LoadLibrary(RichEdit41ModuleName);
        if FMoudlEdit <= HINSTANCE_ERROR then FMoudlEdit := 0;
    end;
    
    inherited CreateParams(Params);
    
    CreateSubClass(Params, RichEdit41ClassName);
    with Params do
    begin
    //
    end;
    end;
    
    4 释放
    
    finalization
    if FMoudlEdit <> 0 then FreeLibrary(FMoudlEdit);
    View Code

    delphi RichEdit控件中插入GIF动画表情

    在UDP即时通讯软件中实现类似于QQ的动画表情,在richEdit控件中插入gif动画表情。
    发送的时候将表情转为命令,接收之后,再将命令转换为相应的动画表情。
    需要引用一个QQ的DLL,文件在附件中。将此DLL导入到DELPHI中。
    
    unit URichEdit;
    
    interface
    uses
    Windows, Messages, SysUtils, Classes, Controls, StdCtrls, ActiveX, ComCtrls,
    RxRichEd, OleServer, ImageOleLib_TLB, coconst, UConst, Dialogs;
    
    const
    REO_CP_SELECTION = ULONG(-1);
    REO_BELOWBASELINE = $00000002;
    REO_RESIZABLE = $00000001;
    REO_STATIC = $40000000;
    EM_GETOLEINTERFACE = WM_USER + 60;
    IID_IUnknown: TGUID = (D1: $00000000; D2: $0000; D3: $0000; 
    D4: ($C0, $00, $00, $00, $00, $00, $00, $46));
    IID_IOleObject: TGUID = (D1: $00000112; D2: $0000; D3: $0000; 
    D4: ($C0, $00, $00, $00, $00, $00, $00, $46));
    
    type
    _ReObject = record
    cbStruct: DWORD; { Size of structure }
    cp: ULONG; { Character position of Object }
    clsid: TCLSID; { Class ID of Object }
    pOleObj: IOleObject; { Ole Object interface }
    pstg: IStorage; { Associated storage interface }
    pOleSite: IOleClientSite; { Associated Client Site interface }
    sizel: TSize; { Size of Object (may be 0,0) }
    dvAspect: Longint; { Display aspect to use }
    dwFlags: DWORD; { Object status flags }
    dwUser: DWORD; { Dword for user憇 use }
    end;
    
    TReObject = _ReObject;
    TCharRange = record {Copy From RichEdit.pas}
    cpMin: Integer;
    cpMax: Integer;
    end;
    
    TFormatRange = record
    hdc: Integer;
    hdcTarget: Integer;
    rectRegion: TRect;
    rectPage: TRect;
    chrg: TCharRange;
    end;
    
    IRichEditOle = interface(System.IUnknown)
    ['{00020d00-0000-0000-c000-000000000046}']
    function GetClientSite(out ClientSite: IOleClientSite): HResult; stdcall;
    function GetObjectCount: HResult; stdcall;
    function GetLinkCount: HResult; stdcall;
    function GetObject(iob: Longint; out ReObject: TReObject; 
    dwFlags: DWORD): HResult; stdcall;
    function InsertObject(var ReObject: TReObject): HResult; stdcall;
    function ConvertObject(iob: Longint; rclsidNew: TIID; 
    lpstrUserTypeNew: LPCSTR): HResult; stdcall;
    function ActivateAs(rclsid: TIID; rclsidAs: TIID): HResult; stdcall;
    function SetHostNames(lpstrContainerApp: LPCSTR; 
    lpstrContainerObj: LPCSTR): HResult; stdcall;
    function SetLinkAvailable(iob: Longint; fAvailable: BOOL): HResult; stdcall;
    function SetDvaspect(iob: Longint; dvAspect: DWORD): HResult; stdcall;
    function HandsOffStorage(iob: Longint): HResult; stdcall;
    function SaveCompleted(iob: Longint; const stg: IStorage): HResult; stdcall;
    function InPlaceDeactivate: HResult; stdcall;
    function ContextSensitiveHelp(fEnterMode: BOOL): HResult; stdcall;
    function GetClipboardData(var chrg: TCharRange; reco: DWORD; 
    out dataObj: IDataObject): HResult; stdcall;
    function ImportDataObject(dataObj: IDataObject; cf: TClipFormat; 
    hMetaPict: HGLOBAL): HResult; stdcall;
    end;
    
    procedure InsertGif(re: TRxRichEdit; sFileName: string; dwUser: integer);
    function GetGif (re: TRxRichEdit): TList;
    function ConvertMsgToCmd (re: TRxRichEdit): string;
    procedure ConvertMsgToFace (re: TRxRichEdit; strMsg: string);
    
    implementation
    
    //***************************************************
    //名称:InsertGif
    //功能:插入图片
    //输入:re:RichEdit控件;sFileName:要插入的文件名;
    // dwUser:(标识,随机数,暂时用文件名【索引】代替)
    //输出:
    //返回:
    //***************************************************
    procedure InsertGif(re: TRxRichEdit; sFileName: string; dwUser: integer);
    type
    tagSize = TSize;
    var
    FRTF: IRichEditOle;
    FLockBytes: ILockBytes;
    FStorage: ISTORAGE;
    FClientSite: IOLECLIENTSITE;
    m_lpObject: IOleObject;
    m_lpAnimator: TGifAnimator;
    i_GifAnimator: IGifAnimator;
    reobject: TReObject;
    clsid: TGuid;
    sizel: tagSize;
    Rect: TRect;
    begin
    try
    if CreateILockBytesOnHGlobal(0, True, FLockBytes) <> S_OK then
    begin
    //showmessage('Error to create Global Heap');
    exit;
    end;
    //????????????
    if StgCreateDocfileOnILockBytes(FLockBytes, STGM_SHARE_EXCLUSIVE or
    STGM_CREATE or STGM_READWRITE, 0, FStorage) <> S_OK then
    begin
    //Showmessage('Error to create storage');
    exit;
    end;
    //??RichEdit???
    Sendmessage(re.handle, EM_GETOLEINTERFACE, 0, LongInt(@FRTF));
    
    if FRTF.GetClientSite(FClientSite) <> S_OK then
    begin
    //ShowMessage('Error to get ClentSite');
    Exit;
    end;
    
    CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
    m_lpAnimator := TGifAnimator.Create(re);
    i_GifAnimator := m_lpAnimator.ControlInterface;
    i_GifAnimator.LoadFromFile(sFileName);
    i_GifAnimator.QueryInterface(IID_IOleObject, m_lpObject);
    OleSetContainedObject(m_lpObject, True);
    FillChar(ReObject, SizeOf(ReObject), 0);
    ReObject.cbStruct := SizeOf(ReObject);
    m_lpObject.GetUserClassID(clsid);
    ReObject.clsid := clsid;
    reobject.cp := REO_CP_SELECTION;
    //content, but not static
    reobject.dvaspect := DVASPECT_CONTENT;
    //goes in the same line of text line
    reobject.dwFlags := REO_BELOWBASELINE; //REO_RESIZABLE |
    reobject.dwUser := 0;
    //the very object
    reobject.poleobj := m_lpObject;
    //client site contain the object
    reobject.polesite := FClientSite;
    //the storage
    reobject.pstg := FStorage;
    sizel.cx := 0;
    sizel.cy := 0;
    reobject.sizel := sizel;
    
    //Sel all text
    re.SelText := '';
    re.SelLength := 0;
    re.SelStart := re.SelStart;
    reobject.dwUser := dwUser;
    
    //Insert after the line of text
    FRTF.InsertObject(reobject);
    SendMessage(re.Handle, EM_SCROLLCARET, 0, 0);
    //VARIANT_BOOL ret;
    //do frame changing
    m_lpAnimator.TriggerFrameChange();
    //show it
    m_lpObject.DoVerb(OLEIVERB_UIACTIVATE, nil, FClientSite, 0, re.Handle, Rect);
    // m_lpObject.DoVerb(
    m_lpObject.DoVerb(OLEIVERB_SHOW, nil, FClientSite, 0, re.Handle, Rect);
    //redraw the window to show animation
    RedrawWindow(re.Handle, nil, 0, RDW_ERASE or RDW_INVALIDATE or RDW_FRAME or 
    RDW_ERASENOW or RDW_ALLCHILDREN);
    finally
    FRTF := nil;
    FClientSite := nil;
    FStorage := nil;
    end;
    end;
    
    //***************************************************
    //名称:GetGif
    //功能:分析控件内容,取得控件中的图片对象
    //输入:re:RichEdit控件;
    //输出:
    //返回:取得的对象列表(图片索引、图片位置)
    //***************************************************
    function GetGif (re: TRxRichEdit): TList;
    type
    tagSize = TSize;
    var
    i: integer;
    FRTF: IRichEditOle;
    ReObject: TReObject;
    lstGif: TList;
    slstRow: TStringList;
    begin
    lstGif := TList.Create;
    
    Sendmessage(re.handle, EM_GETOLEINTERFACE, 0, LongInt(@FRTF));
    
    for i := 0 to FRTF.GetObjectCount - 1 do
    begin
    slstRow := TStringList.Create;
    FillChar(ReObject, SizeOf(ReObject), 0);
    ReObject.cbStruct := SizeOf(ReObject);
    
    FRTF.GetObject (Longint (i), ReObject, REO_BELOWBASELINE);
    slstRow.Add (IntToStr (ReObject.dwUser));
    slstRow.Add (IntToStr (ReObject.cp));
    lstGif.Add (slstRow);
    end;
    
    Result := lstGif;
    end;
    
    //***************************************************
    //名称:ConvertMsgToCmd
    //功能:分析控件内容,将表情替换成相应的命令
    //输入:re:RichEdit控件;
    //输出:
    //返回:转换之后的消息内容
    //***************************************************
    function ConvertMsgToCmd (re: TRxRichEdit): string;
    var
    i: integer;
    lstGif: TList;
    strMsg: WideString;
    slstRow, slstMsg: TStringList;
    begin
    //分解消息文本内容,将所有内容分隔之后放到列表中
    slstMsg := TStringList.Create;
    strMsg := re.Text;
    for i := 1 to Length (strMsg) do
    begin
    slstMsg.Add (strMsg[i]);
    end;
    
    //取得表情,将表情替换成命令
    lstGif := GetGif (re);
    for i := lstGif.Count - 1 downto 0 do
    begin
    slstRow := TStringList (lstGif.Items[i]);
    
    slstMsg.Insert (StrToInt (slstRow.Strings[1]), 
    m_arrFace[StrToInt (slstRow.Strings[0]), 1]);
    slstRow.Free;
    end;
    lstGif.Free;
    
    strMsg := StringReplace (slstMsg.Text, #13#10, '', [rfReplaceAll]);
    slstMsg.Free;
    
    Result := strMsg;
    end;
    
    //***************************************************
    //名称:ConvertMsgToFace
    //功能:分析消息内容,将命令换成相应的表情
    //输入:re:RichEdit控件;strMsg:消息内容;
    //输出:
    //返回:
    //***************************************************
    procedure ConvertMsgToFace (re: TRxRichEdit; strMsg: string);
    var
    i, nFind: integer;
    strPath: string;
    strMessage: WideString;
    begin
    if StrPos (PChar (strMsg), '/') = nil then
    begin
    exit;
    end;
    
    strMessage := strMsg;
    strPath := ExtractFilePath (ParamStr (0)) + SYSSET_CHAT_FACEPATH;
    for i := 0 to Length (m_arrFace) - 1 do
    begin
    nFind := Pos (PChar (m_arrFace[i, 1]), strMessage);
    if nFind = 0 then
    continue
    else begin
    re.SelStart := nFind - 2;
    re.SelLength := Length (m_arrFace[i, 1]);
    InsertGif (re, strPath + m_arrFace[i, 0], i);
    end;
    end;
    end;
    
    end.
    View Code

    delphi 调用Msftedit.dll,重写Richedit,支持RTF画表格

    delphi 2009 调用Msftedit.dll,重写Richedit,能更好地支持RTF,特别是画表格
    
    画表格的具体思路分析
    
    4个步骤:
    
    1 指定类名称 RichEdit50W
    
    var
    FMoudlEdit:THandle;
    const
    RichEdit41ModuleName = 'Msftedit.dll';
    RichEdit41ClassName = 'RichEdit50W';
    
    2 从TCustomRichEdit继承
    
    TRichEdit41=class(TCustomRichEdit)
    private
    protected
        procedure CreateParams(var Params: TCreateParams);override;
    public
    
    3 重些CreateParams
    
    procedure TRichEdit41.CreateParams(var Params: TCreateParams);
    begin
    if FMoudlEdit = 0 then
    begin
        FMoudlEdit := LoadLibrary(RichEdit41ModuleName);
        if FMoudlEdit <= HINSTANCE_ERROR then FMoudlEdit := 0;
    end;
    
    inherited CreateParams(Params);
    
    CreateSubClass(Params, RichEdit41ClassName);
    with Params do
    begin
    //
    end;
    end;
    
    4 释放
    
    finalization
    if FMoudlEdit <> 0 then FreeLibrary(FMoudlEdit);
    View Code

    richedit画表格的具体分析

    Richedit支持画表格,要依靠msftedit.dll,参考
    
    delphi 2009 调用Msftedit.dll,重写Richedit,能更好地支持RTF,特别是画表格
    
    画表格,实质上是构造RTF格式的文档,RTF文档的构造<下面紫色部分>就按照RTF的格式书写,每构造好一部分后就放入StringStream里,TStringStream.WriteString。全部构造好后,导入到 richedit 组件中显示出来就可以了,TCustomRichEdit.Lines.LoadFromStream。
    
    其实画一个表格就3步,
    第一步,写RTF格式的文件头;
    第二步,定义表格的一行,包括行和每个单元格的位置、大小和样式;
    第三步,把内容写进去。
    
    下面详细列出RTF的每一部分,参照上面的三步:
    
    1 RTF文件头,可以找一个rtf文件分离出来,都是{}对。rtfto~ rtfto,为了方便,分割一下。依次写入到Stream里。rtfto规定了字体和语言,可自行修改。
    rtfto='{
    tf1ansiansicpg936deff0deflang2052deflangfe2052deftab420{fonttbl{f0fnilfcharset134 Sun;}{f1fromanfprq2fcharset0 Times New Roman;}}';
    rtfto='{*generator Msftedit 5.41.15.1507;}';
    ....
    
    2 行和本行单元格定义。行定义rtfbiaogehang1~31后面加上行高。各单元格的定义rtfbiaogecell1~9,cellx403是单元格位置。其他样式包括行的边界和间距等,以及单元格的垂直方向对齐方式,边界和宽度。
    
    rtfbiaogehang1='	rowd	rgaph10	rleft-40	rqc	rrh';
    rtfbiaogehang2='	rbrdrlrdrsrdrw10 	rbrdrtrdrsrdrw10 	rbrdrrrdrsrdrw10 	rbrdrbrdrsrdrww10 ';
    rtfbiaogehang3='	rpaddl10	rpaddr10	rpaddfl3	rpaddfr3';
    
    rtfbiaogecell1='clvertalcclbrdrlrdrw10rdrsclbrdrtrdrw10rdrsclbrdrrrdrw10rdrsclbrdrbrdrw10rdrs cellx403'; 
    rtfbiaogecell2='clvertalcclbrdrlrdrw10rdrsclbrdrtrdrw10rdrsclbrdrrrdrw10rdrsclbrdrbrdrw10rdrs cellx1395';
    
    3 写入内容
    
    开头 pardintbl
    owidctlpar
    中间 对每一列,都使用 对齐方式+内容的BigEndianUnicode+cell 的方式
    结束 
    ow
    
    其中对齐方式包括qc qj ql qr,不用解释了吧,用WPS/WORD的人都知道。
    
    BigEndianUnicode的处理,为了处理4字节汉字的显示,字符统一bigEndian编码<如:{卸 ?}>
    
    for i := 0 to Length(aString)-1 do
        result:=result+'{u'+inttostr(ord(aString[i+1]))+' ?}';
    
    使用这种方式写入内容纯粹是为了程序简单,并不是固定的,而这样可能多写入很多RTF代码,造成庞大的RTF文件:即多了很多格式显示指令,2字节汉字也使用了长编码。如果表格不是很多内容,目前的电脑配置基础上,运行起来是没感觉的。
    
    一个表格,顺利诞生。
    View Code

    用流方式存取

    保存:
    
    var
      Str: string;
      temStream: TMemoryStream;
    begin
      temStream := TMemoryStream.Create;
      RichEdit1.Lines.SaveToStream(temStream);
      str := 'select * from Table1';
      AdoQuery1.Close;
      AdoQuery1.SQL.Clear;
      AdoQuery1.SQL.Add(str);
      AdoQuery1.Open;
      AdoQuery1.Append;
      AdoQuery1.FieldByName('ID').AsInteger:= 3;
      TBlobField(AdoQuery1.FieldByName('RichEditText')).LoadFromStream(temStream);
      AdoQuery1.Post;
      temStream.Free;
    
    读取:
    
    var
      Str: string;
      temStream: TMemoryStream;
    begin
      temStream := TMemoryStream.Create;
      str := 'select * from Table1 ';
      AdoQuery1.Close;
      AdoQuery1.SQL.Clear;
      AdoQuery1.SQL.Add(str);
      AdoQuery1.Open;
      TBlobField(AdoQuery1.FieldByName('RichEditText')).SaveToStream(temStream);
      temStream.Seek(0,0);
      RichEdit1.Lines.LoadFromStream(temStream);
      temStream.Free;
    View Code
  • 相关阅读:
    JavaWeb 之 三层架构:软件设计架构
    JavaWeb 之 MVC 开发模式
    JavaWeb 之 JSTL 标签
    Java 之 JSP
    【LeetCode-动态规划】不同的二叉搜索树
    【深度学习】模型压缩
    【LeetCode-数学】两数相除
    【LeetCode-链表】删除链表的倒数第N个节点
    【LeetCode-链表】合并K个排序链表
    【LeetCode-链表】合并两个有序链表
  • 原文地址:https://www.cnblogs.com/blogpro/p/11453146.html
Copyright © 2011-2022 走看看