用DELPHI、RxRichEdit控件实现类似QQ的表情输入方法

在UDP即时通讯软件中实现类似于QQ的动画表情,在richEdit控件中插入gif动画表情。
发送的时候将表情转为命令,接收之后,再将命令转换为相应的动画表情。
需要引用一个QQ的DLL,文件在附件中。将此DLL导入到DELPHI中。

源码及DLL 附件下载地址:
http://www.j2soft.cn

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.
 

Unofficial version Rx library for Delphi 2005/2006/2007/2009/2010/XE/XE2/XE3 DISCLAIMER: * This software is provided "as is" and is without warranty of any kind. The author(s) of this software does not warrant, guarantee or make any representations regarding the use or results of use of this software in terms of reliability, accuracy or fitness for purpose. You assume the entire risk of direct or indirect, consequential or inconsequential results from the correct or incorrect usage of this software even if the author(s) has been informed of the possibilities of such damage. Neither the author(s) nor anybody connected to this software in any way can assume any responsibility. * All rights held by the author(s) or owner(s) of units or documents. _______________________________________________________________________________ Update 1.10 1/ Update for Delphi XE3 _______________________________________________________________________________ Update 1.09 1/ Delphi package source actualization 2/ Delphi 6 conditional corections 3/ TRxFindFiles support class added 4/ Corrections for default (ENG) lang. resource _______________________________________________________________________________ Update 1.08 1/ file case name unit corrections. 2/ only one language file can be used in your applications like: a) in Rx.inc activate {$DEFINE _LNG_ONE_}. b) activate yours own language in new include RxLangDef.inc like {$DEFINE RXLANG_Cze}. note: Languages different from English locates in utf-8 files, may be editor problem for lower version Delphi than 2005. c) in your project use global conditional define like RXLANG_MYLANG (it activate your lang file only). d) rebuild your application, it will be smaller with one your language mutation for RxLibrary only. 3/ repair malfunction of TColor property (big thanks to Remy Lebeau). 4/ many new constant color names added into module RxColors (+ 229 named constant). 5/ new component TRxThread added for better access. 6/ repair malfunction of property caption editor. 7/ new components TRxAnimBitBtn, TRxAnimSpeedButton added. 8/ repair malfunction with styles in TRxProgress. 9/ refresh code in TRxDBGridSorter. 10/ adopted 20 function utilities by Alexey Popov into module RxProps. 11/ activate Align property in TRxSpinButton. 12/ rename parameter Name to AName in define event TExecOpenDialogEvent, because occur names conflict. 13/ repair conflict in string property in module RxTranslate for unicodes. 14/ some functions added into module RxVerInf for better work with versions. Note for users Delphi 5/6/7: ---------------------------- RxLibrary is not directly designed for this Delphi versions. When you will want compile source code in this versions of Delphi, you have to open all units contain form (*.dfm) and resave it for resource compatibility (crash prevent IDE) before rebuild and install into IDE. Some functionality will be lost. Note for users Delphi XE2 (64 bit.ver): --------------------------------------- This source code is 64 bit ready but untested. BDE packs must be removed from 64 bit project as unsuported technology. Note for users CBuilder: ------------------------ This source code is CBuilder (2006/2007) ready but uncomplete and untested yet. Releases February 29, 2012 _______________________________________________________________________________ Update 1.07 1/ Update all packages in unit scope. 2/ Change namespace in RxViewer unit for XE2. _______________________________________________________________________________ Update 1.06 1/ repair malfunction of TFormStorage under Unicode Delphi. 2/ update packages file for Delphi 2005 - XE. 3/ update package for Delphi XE2 32 bit. _______________________________________________________________________________ Update 1.05 1/ better compatibility with Delphi 2009. 2/ new adopted component for view any supported files. 3/ convert dfm files to text. _______________________________________________________________________________ Update 1.04 Updated: 1/ small mistake in RxDBCtrl.pas (wrong show DBGrid). 2/ activate tables in general RxDemo. 3/ replacement deprecated FileAge() in RxFileUtils. _______________________________________________________________________________ The initial release(s) no included
RX Library 2.75 =============== The Set of Native Delphi Components for Borland Delphi versions 1, 2, 3, 4 & 5 and Borland C++ Builder 1, 3 & 4. 100% Source Code. Last revision date Oct 12, 1999. PLEASE FOLLOW THE INSTRUCTIONS PROVIDED IN THE INSTALLATION SECTION! TABLE OF CONTENTS ----------------- Latest Changes Overview History License Agreement Installation Demonstration Programs Source Files Using GIF Images Copyright Notes NEW FOR VERSION 2.75 -------------------- Delphi 5.0 & C++Builder 4.0 Compatibility New components: TRxLoginDialog New properties, events: TFormPlacement.RegistryRoot TFormPlacement.Version TFontComboBox.UseFonts TRxDBGrid.OnTopLeftChanged TRxDBLookupCombo.DisplayValues TStrHolder.Macros, TStrHolder.OnExpandMacros RxSpin.TValueType.vtHex New routines, methods, constants: SaveClipboardToStream, LoadClipboardFromStream (clipmon.pas) AppFileName, AppVerInfo (rxverinf.pas) XorString, XorEncode, XorDecode (strutils.pas) BUG FIXES. Overview -------- RX Library contains a large number of components, objects and routines for Borland Delphi with full source code. This library is compatible with Borland Delphi 1, 2, 3, 4, 5 and Borland C++ Builder 1, 3, 4. This collection includes over 60 native Delphi components. RX Library is a freeware product. Feel free to distribute the library as long as all files are unmodified and kept together. The authors disclaim all warranties as to this software, whether express or implied, including without limitation any implied warranties of merchantability or fitness for a particular purpose. Use under your own responsibility, but comments (even critique) in English (or in Russian) are welcome. 1. Components: TRxDBLookupCombo provides an incremental search through lookup list by directly typing into the combo control while the lookup list is displayed, LookupSource can refer to TTable, TQuery, TRxQuery or TQBEQuery. It even incrementally searches on the query results and much more... TRx
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值