delphi रिचएडिट हाइपरलिंक पर कार्रवाई नहीं करता है




hyperlink richedit (2)

आपके प्रश्न में दिखाए गए कोड मेरे लिए एकदम सही काम करता है जैसे- है अपने दावे के बावजूद, प्रपत्र के WndProc() EN_LINK सूचना प्राप्त करता है और अपेक्षित के रूप में क्लिक किए गए यूआरएल को लॉन्च करता है

हालांकि, अगर आप किसी अन्य अभिभावक नियंत्रण पर एक TPanel एक TPanel तरह TPanel , तो फ़ॉर्म को अब WM_NOTIFY संदेश प्राप्त नहीं होगा। पैरेंट कंट्रोल उन्हें प्राप्त करेगा, और इस तरह आपको इसके बजाय उस पेरेंट कंट्रोल को उप-क्लास करना होगा।

कहा जा रहा है कि, कुछ सुधार हैं जो दिखाए गए कोड के लिए किए जा सकते हैं:

  1. अपने EN_LINK निपटने में, आप इसे बदल सकते हैं:

    CE := TRichEdit(ProgCorner.ActiveControl);

    इसके बजाय:

    CE := TRichEdit(FindControl(TWMNotify(Msg).NMHdr.hwndFrom));

    अधिसूचना आपको TWinControl नियंत्रण के HWND को भेजता है जो इसे भेज रहा है, और वीसीएल जानता है कि कैसे एक TWinControl से TWinControl को पुनः प्राप्त किया TWinControl

  2. EM_EXSETSEL और SelText (जो कि EM_EXGETSEL और EM_GETTEXTEX का संयोजन है) का उपयोग करने के बजाय क्लिक किए गए यूआरएल को पुनः प्राप्त करने के लिए EM_GETTEXTRANGE का उपयोग करें। इस तरह, आप कम संदेश का उपयोग कर रहे हैं, और RichEdit के चयनित पाठ को बिल्कुल भी हेरफेर करने की आवश्यकता नहीं है। अधिसूचना आपको यूआरएल के लिए वर्णों की सटीक सीमा बताती है, इसलिए आप उन पात्रों को सीधे सीधे पकड़ कर सकते हैं

  3. आपको HWND मनोरंजन को संभालना होगा वीसीएल किसी भी समय HWND के HWND को पुनर्निर्मित कर सकता है । हर बार एक नया HWND बनाया जाता है, आपको अपना EM_SETEVENTMASK और EM_SETEVENTMASK सन्देश फिर से भेजना होगा, अन्यथा आप अपना ऑटो-डिटेक्शन खो देंगे। इसे संभालने का सबसे अच्छा तरीका TRichEdit से एक वर्ग प्राप्त TRichEdit और इसके CreateWnd() विधि को ओवरराइड करना है।

  4. चूंकि आपको किसी वर्ग को वैसे ही प्राप्त करना है, इसलिए आप मूल WM_NOTIFY सन्देश को सीधे माता-पिता के WndProc में संभालने के बजाय, वीसीएल के CN_NOTIFY संदेश को संभालना WM_NOTIFY सकता है। वीसीएल जानता है कि कैसे उसे भेजे गए वीसीएल नियंत्रण के लिए एक WM_NOTIFY संदेश को रीडायरेक्ट करना है। यह वीसीएल नियंत्रण को अपनी सूचनाओं को नियंत्रित करने की अनुमति देता है। इस प्रकार, आपका EN_LINK हैंडलर कोई भी काम नहीं करेगा जो अभिभावक के EN_LINK को नियंत्रित करते हैं, आप को माता-पिता की WndProc() सभी को उप-वर्ग / ओवरराइड नहीं करना पड़ता है, और आप RichEdit के Self पॉइंटर का उपयोग कर सकते हैं जो संदेश संसाधित कर रहा है जब RichEdit के सदस्यों को एक्सेस करते हैं, जैसे कि इसकी Handle प्रॉपर्टी

उस सभी के साथ, निम्नलिखित कोड मेरे लिए काम करता है:

unit RichEditUrlTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls;

type
  TRichEdit = class(Vcl.ComCtrls.TRichEdit)
  private
    procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
  protected
    procedure CreateWnd; override;
  end;

  TProgCorner = class(TForm)
    RichEdit2: TRichEdit;
    RichEdit1: TRichEdit;
    RichEdit3: TRichEdit;
    RichEdit4: TRichEdit;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  ProgCorner: TProgCorner;

implementation

{$R *.dfm}

uses
  Winapi.ShellAPI, Winapi.RichEdit;

const
  AURL_ENABLEURL = 1;
  AURL_ENABLEEAURLS = 8;

procedure TRichEdit.CreateWnd;
var
  mask: LResult;
begin
  inherited;
  mask := SendMessage(Handle, EM_GETEVENTMASK, 0, 0);
  SendMessage(Handle, EM_SETEVENTMASK, 0, mask or ENM_LINK);
  SendMessage(Handle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0);
end;

procedure TRichEdit.CNNotify(var Message: TWMNotify);
type
  PENLink = ^TENLink;
var
  p: PENLink;
  tr: TEXTRANGE;
  url: array of Char;
begin
  if (Message.NMHdr.code = EN_LINK) then begin
    p := PENLink(Message.NMHdr);
    if (p.Msg = WM_LBUTTONDOWN) then begin
      { optionally, enable this:
      if CheckWin32Version(6, 2) then begin
        // on Windows 8+, returning EN_LINK_DO_DEFAULT directs
        // the RichEdit to perform the default action...
        Message.Result :=  EN_LINK_DO_DEFAULT;
        Exit;
      end;
      }
      try
        SetLength(url, p.chrg.cpMax - p.chrg.cpMin + 1);
        tr.chrg := p.chrg;
        tr.lpstrText := PChar(url);
        SendMessage(Handle, EM_GETTEXTRANGE, 0, LPARAM(@tr));
        ShellExecute(Handle, nil, PChar(url), 0, 0, SW_SHOWNORMAL);
      except
        {ignore}
      end;
      Exit;
    end;
  end;
  inherited;
end;

procedure TProgCorner.FormCreate(Sender: TObject);
begin
  RichEdit1.Text:= 'http://www.example.com';
end;

end.

मैं अपने रिचइडिट को हाइपरलिंक पर कार्रवाई करने के लिए चाहता हूं, इसलिए मैंने निर्देशों का पालन किया: http://delphi.about.com/od/vclusioning/l/aa111803a.htm

यहां मैंने किए गए परिवर्तन कोड में किए हैं:

interface

type
  TProgCorner = class(TForm)
    RichEdit2: TRichEdit;
    RichEdit1: TRichEdit;
    RichEdit3: TRichEdit;
    RichEdit4: TRichEdit;
    procedure FormCreate(Sender: TObject);
  private
    procedure InitRichEditURLDetection(RE: TRichEdit);
  protected
    procedure WndProc(var Msg: TMessage); override;
  end;

implementation

{$R *.DFM}

uses
  ShellAPI, RichEdit;

const
  AURL_ENABLEURL = 1;
  AURL_ENABLEEAURLS = 8;

procedure TProgCorner.InitRichEditURLDetection(RE: TRichEdit);
var
  mask: LResult;
begin
  mask := SendMessage(RE.Handle, EM_GETEVENTMASK, 0, 0);
  //In the debugger mask is always 1, for all 4 Richedits.
  SendMessage(RE.Handle, EM_SETEVENTMASK, 0, mask or ENM_LINK); 
  //returns 67108865
  SendMessage(RE.Handle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0);
  //Returns 0 = success (according to MSDN), but no joy.
  //SendMessage(RE.Handle, EM_AUTOURLDETECT, AURL_ENABLEEAURLS, 0); 
  //When uncommented returns -2147024809
  //I don't think the registration works, but don't know how to fix this.
end;

procedure TProgCorner.WndProc(var Msg: TMessage);
var
  p: TENLink;
  sURL: string;
  CE: TRichEdit;
begin
  //'normal' messages do get through here, but...
  if (Msg.Msg = WM_NOTIFY) then begin
    //...the following line is never reached.
    if (PNMHDR(Msg.lParam).code = EN_LINK) then begin
      p:= TENLink(Pointer(TWMNotify(Msg).NMHdr)^);
      if (p.Msg = WM_LBUTTONDOWN) then begin
        try
          CE:= TRichEdit(ProgCorner.ActiveControl);
          SendMessage(CE.Handle, EM_EXSETSEL, 0, LPARAM(@(p.chrg)));
          sURL:= CE.SelText;
          ShellExecute(Handle, 'open', PChar(sURL), 0, 0, SW_SHOWNORMAL);
        except
          {ignore}
        end;
      end;
    end;
  end;

 inherited;
end;

procedure TProgCorner.FormCreate(Sender: TObject);
begin
  InitRichEditURLDetection(RichEdit1);
  InitRichEditURLDetection(RichEdit2);
  InitRichEditURLDetection(RichEdit3);
  InitRichEditURLDetection(RichEdit4);
  //If I set the text here (and not in the object inspector) 
  //the richedit shows a hyperlink with the 'hand' cursor.
  //but still no WM_notify message gets received in WndProc.
  RichEdit1.Text:= 'http://www.example.com';

end;

end.

हालांकि मैं अपने RichEditx.Lines में एम्बेडेड हाइपरलिंक्स। ऑब्जेक्ट निरीक्षक का इस्तेमाल करते हुए RichEditx.Lines सादा पाठ (लिंक नहीं) के रूप में दिखाया जाता है और उन पर क्लिक करने से काम नहीं करता

मैं Windows 7 में Win32 मोड में डेल्फी सिएटल का उपयोग कर रहा हूं।

मैं क्या गलत कर रहा हूं?

अद्यतन करें
पदावनत जारी करने के संयोजन का उपयोग करना
SendMessage(RE.Handle, EM_AUTOURLDETECT, AURL_ENABLEURL, 0); और RichEditx.Text:= 'http://www.example.com' मैन्युअल रूप से FormCreate में FormCreate रहा FormCreate मैं FormCreate को एक हाइपरलिंक और हैंडसर्स प्रदर्शित करने में सक्षम हूं।
हालांकि, WndProc अभी भी एक WM_Notify संदेश प्राप्त नहीं करता है
WndProc अन्य संदेश प्राप्त करता है

UPDATE2
इस मुद्दे को सरल बनाने के लिए मेरी उत्सुकता में मैंने इस तथ्य को छोड़ दिया कि RichEdit एक Panel शीर्ष पर बैठता है पैनल WM_Notify संदेशों को खाता करता है ताकि वे WM_Notify गए फार्म तक नहीं पहुंच सकें।


समस्या यह है कि WM_Notify संदेश कभी भी मुख्य फ़ॉर्म तक नहीं पहुंचता है
इसके बजाय इसे रिसीडित के माता-पिता (एक पैनल जो मैंने संरेखण प्रयोजनों के लिए वहां रखा था) द्वारा बाधित किया गया था।
मैंने गलती से इस तथ्य को छोड़ दिया कि सवाल यह सोचते हैं कि इससे कोई फर्क नहीं पड़ा।
उसने कहा कि निम्नलिखित मेरे लिए काम किया

हालांकि मैं दृढ़ता से रेमी की वास्तुकला और अधिक सुदृढ़ दृष्टिकोण का समर्थन करता हूं, और इस समस्या से जूझ रहे लोगों को पहली बार प्रयास करना चाहिए।

वीसीएल कॉमट्रैक्स में

  TCustomRichEdit = class(TCustomMemo)
  private  //Why private !?
    procedure CNNotify(var Message: TWMNotifyRE); message CN_NOTIFY;

इसका समाधान हमारे अपने TRICHEdit के हस्तक्षेप करना है:

uses   
  ...., RichEdit;

type
  TRichEdit = class(ComCtrls.TRichEdit)
    procedure CNNotify(var Message: TWMNotifyRE); message CN_NOTIFY;
  end;  //never mind that its ancester is private, it will still work.

  TProgCorner = class(TForm)

मैं RichRdits को किसी सरणी में संग्रहीत करता हूं, इसलिए मैं उनके HWnd बिना पाश को देख सकता हूं, हालांकि मेरे फॉर्म के सभी बाल कंट्रोल

implementation

function TProgCorner.RichEditByHandle(Handle: HWnd): TRichEdit;
var
  i: integer;
begin
  //Keep track of the richedits in an array, initialized on creation.
  for i:= Low(RichEdits) to High(RichEdits) do begin
    if RichEdits[i].Handle = Handle then exit(RichEdits[i]);
  end;
  Result:= nil;
end;

procedure TRichEdit.CNNotify(var Message: TWMNotifyRE);
var
  p: TENLink;
  sURL: string;
  CE: TRichEdit;
begin
  if (Message.NMHdr.code = EN_LINK) then begin
    p:= TENLink(Pointer(TWMNotify(Message).NMHdr)^);
    if (p.Msg = WM_LBUTTONDOWN) then begin
      try
        //CE:= TRichEdit(ProgCorner.ActiveControl);
        //SendMessage(CE.Handle, EM_EXSETSEL, 0, Longint(@(p.chrg)));
        SendMessage(p.nmhdr.hwndFrom, EM_EXSETSEL, 0, Longint(@(p.chrg)));
        CE:= ProgCorner.RichEditByHandle(p.nmhdr.hwndFrom);
        if assigned(CE) then begin
          sURL:= CE.SelText;
          ShellExecute(Handle, 'open', PChar(sURL), 0, 0, SW_SHOWNORMAL);
        end;
      except
        {ignore}
      end;
    end;
  end;
  inherited;
end;

सौभाग्य से संदेश हैंडलर्स के इंटरपोसन काम करते हैं, हालांकि मूल को निजी घोषित किया जाता है।

अब यह काम कर रहा है। जादू की तरह।

नीचे भविष्य की संदर्भ के लिए यूनिट की पूरी प्रति है:

unit ProgCorn;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, ComCtrls, Menus, Clipbrd, LifeConst, Tabnotbk, LifeUtil,
  MyLinkLabel, RichEdit;

type
  TRichEdit = class(ComCtrls.TRichEdit)
    procedure CNNotify(var Message: TWMNotifyRE); message CN_NOTIFY;
  end;


  TProgCorner = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Label1: TLabel;
    TabbedNotebook1: TTabbedNotebook;
    PopupMenu1: TPopupMenu;
    Copy1: TMenuItem;
    Panel3: TPanel;
    Button1: TButton;
    RichEdit1: TRichEdit;
    RichEdit2: TRichEdit;
    RichEdit3: TRichEdit;
    RichEdit4: TRichEdit;
    Button2: TButton;
    procedure Copy1Click(Sender: TObject);
    procedure PopupMenu1Popup(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    RichEdits: array[1..4] of TRichEdit;
    procedure InitRichEditURLDetection(RE: TRichEdit);
    function RichEditByHandle(Handle: HWnd): TRichEdit;
  public
    { Public declarations }
  end;

var
  ProgCorner: TProgCorner;


implementation

{$R *.DFM}

uses
  ShellAPI;

const
  AURL_ENABLEEAURLS = 8;
  AURL_ENABLEURL = 1;

procedure TProgCorner.InitRichEditURLDetection(RE: TRichEdit);
var
  mask: NativeInt;
begin
  mask := SendMessage(RE.Handle, EM_GETEVENTMASK, 0, 0);
  SendMessage(RE.Handle, EM_SETEVENTMASK, 0, mask or ENM_LINK);
  SendMessage(RE.Handle, EM_AUTOURLDETECT, {AURL_ENABLEEAURLS} AURL_ENABLEURL, 0);
end;



procedure TProgCorner.FormCreate(Sender: TObject);
begin
  ProgCorner:= Self;
  InitRichEditURLDetection(RichEdit1);
  InitRichEditURLDetection(RichEdit2);
  InitRichEditURLDetection(RichEdit3);
  InitRichEditURLDetection(RichEdit4);
  RichEdits[1]:= RichEdit1;
  RichEdits[2]:= RichEdit2;
  RichEdits[3]:= RichEdit3;
  RichEdits[4]:= RichEdit4;

  //WordWarp should be set during runtime only, because
  //otherwise the text will not warp, but rather be cut off
  //before run time.
  RichEdit1.Text:= RichEdit1.Text + ' ';
  RichEdit2.Text:= RichEdit2.Text + ' ';
  RichEdit3.Text:= RichEdit3.Text + ' ';
  RichEdit4.Text:= RichEdit4.Text + ' ';
  RichEdit1.WordWrap:= true;
  RichEdit2.WordWrap:= true;
  RichEdit3.WordWrap:= true;
  RichEdit4.WordWrap:= true;
end;

procedure TProgCorner.Copy1Click(Sender: TObject);
var
  ActiveRichEdit: TRichEdit;
begin
  ActiveRichEdit:= TRichEdit(Self.FindComponent('RichEdit'+
    IntToStr(TabbedNotebook1.PageIndex+1)));
  with ActiveRichEdit do begin
    if SelText <> '' then Clipboard.AsText:= SelText
    else ClipBoard.AsText:= Lines.Text;
  end; {with}
end;

procedure TProgCorner.PopupMenu1Popup(Sender: TObject);
begin
  Copy1.Enabled:= true;
end;


procedure TProgCorner.Button2Click(Sender: TObject);
begin
  Application.HelpContext(4);
end;

{ TRichEdit }

function TProgCorner.RichEditByHandle(Handle: HWnd): TRichEdit;
var
  i: integer;
begin
  for i:= Low(RichEdits) to High(RichEdits) do begin
    if RichEdits[i].Handle = Handle then exit(RichEdits[i]);
  end;
  Result:= nil;
end;

procedure TRichEdit.CNNotify(var Message: TWMNotifyRE);
var
  p: TENLink;
  sURL: string;
  CE: TRichEdit;
begin
  //if (Message.Msg = WM_NOTIFY) then begin
    if (Message.NMHdr.code = EN_LINK) then begin
      p:= TENLink(Pointer(TWMNotify(Message).NMHdr)^);
      if (p.Msg = WM_LBUTTONDOWN) then begin
        try
          //CE:= TRichEdit(ProgCorner.ActiveControl);
          //SendMessage(CE.Handle, EM_EXSETSEL, 0, Longint(@(p.chrg)));
          SendMessage(p.nmhdr.hwndFrom, EM_EXSETSEL, 0, Longint(@(p.chrg)));
          CE:= ProgCorner.RichEditByHandle(p.nmhdr.hwndFrom);
          if assigned(CE) then begin
            sURL:= CE.SelText;
            ShellExecute(Handle, 'open', PChar(sURL), 0, 0, SW_SHOWNORMAL);
          end;
        except
          {ignore}
        end;
      end;
    end;
  //end;
  inherited;
end;

end.




richedit