【问题标题】:How to get Scrollbar notifications from a TMemo control?如何从 TMemo 控件获取滚动条通知?
【发布时间】:2013-12-09 04:37:31
【问题描述】:

我有一个 VCL TMemo 控件,每次滚动文本时都需要通知。没有 OnScroll 事件并且滚动消息似乎没有传播到父窗体。

知道如何获取通知吗? 作为最后的手段,我可​​以在 OnScroll 事件中放置一个外部TScrollBar 并更新TMemo,但是当我移动光标或滚动鼠标时我必须使它们保持同步轮到TMemo...

【问题讨论】:

  • AFAICT,您必须编写自己的后代并覆盖 WndProc 以捕获 WM_VSCROLL 和 WM_HSCROLL 消息,然后执行您需要的操作来响应它们。
  • @KenWhite,这不是 Delphi 应用程序...我已将标签改回。
  • 您的标签最初并未表明它不是 Delphi。它只是说VCL,它是 Delphi。不过答案是一样的。
  • 嗯,VCL 也是 C++ Builder ;)
  • :-) 好吧,不。它可以从 C++ Builder 中使用,但 VCL 的所有源代码都是用 Delphi 编写的。

标签: vcl messages mousewheel tmemo c++builder-xe3


【解决方案1】:

您可以使用插入器类来处理WM_VSCROLL 和WM_HSCROLL 消息以及EN_VSCROLL 和EN_HSCROLL 通知代码(通过WM_COMMAND 消息公开)。

试试这个示例

type
  TMemo  = class(Vcl.StdCtrls.TMemo)
  private
   procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
   procedure WMVScroll(var Msg: TWMHScroll); message WM_VSCROLL;
   procedure WMHScroll(var Msg: TWMHScroll); message WM_HSCROLL;
  end;

  TForm16 = class(TForm)
    Memo1: TMemo;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form16: TForm16;

implementation

{$R *.dfm}


{ TMemo }

procedure TMemo.CNCommand(var Message: TWMCommand);
begin
   case Message.NotifyCode of
    EN_VSCROLL : OutputDebugString('EN_VSCROLL');
    EN_HSCROLL : OutputDebugString('EN_HSCROLL');
   end;

   inherited ;
end;

procedure TMemo.WMHScroll(var Msg: TWMHScroll);
begin
   OutputDebugString('WM_HSCROLL') ;
   inherited;
end;

procedure TMemo.WMVScroll(var Msg: TWMHScroll);
begin
   OutputDebugString('WM_HSCROLL') ;
   inherited;
end;

【讨论】:

  • 抱歉,忘了说我用的是 C++ Builder,不过我看看能不能翻译你的例子……
  • Interposer 类在 C++ 中不起作用。但是您可以在运行时继承标准TMemo 组件的WindowProc 属性。
  • 只是一个小小的修正:WM_VSCROLL 在TMemo.WMVScroll 过程中(现在有一个WM_HSCROLL)。
【解决方案2】:

您可以在运行时子类化备忘录的WindowProc 属性以捕获发送到备忘录的所有消息,例如:

private:
    TWndMethod PrevMemoWndProc;
    void __fastcall MemoWndProc(TMessage &Message);

__fastcall TMyForm::TMyForm(TComponent *Owner)
    : TForm(Owner)
{
    PrevMemoWndProc = Memo1->WindowProc;
    Memo1->WindowProc = MemoWndProc;
}

void __fastcall TMyForm::MemoWndProc(TMessage &Message)
{
    switch (Message.Msg)
    {
        case CN_COMMAND:
        {
            switch (reinterpret_cast<TWMCommand&>(Message).NotifyCode)
            {
                case EN_VSCROLL:
                {
                    //...
                    break;
                }

                case EN_HSCROLL:
                {
                    //...
                    break;
                }
            }

            break;
        }

        case WM_HSCROLL:
        {
            //...
            break;
        }

        case WM_VSCROLL:
        {
            //...
            break;
        }
    }

    PrevMemoWndProc(Message);
}

【讨论】:

  • 我确实收到了消息,但它们都不是任何 SCROLL 消息。如果我按下备忘录滚动条的向上和向下按钮,我得到 Notifycode 0x0602 (WParamHi),没有其他 CN_COMMANDS。
  • @MaxKielland:NotifyCode 0x0602 是 EN_VSCROLL(EN_HSCROLL 是 0x0601)。
  • 谢谢!由于某种原因,代码被优化掉了。当我做了一个更正确的实现时,它工作得很好。通过使用 WM_xSCROLL 消息,我捕获了所有滚动条行为,而不仅仅是箭头按钮。但是,有没有一种方法可以捕捉备忘录由于光标移动而滚动的时间?滚动条已更新,但我没有收到任何滚动条消息。我试图听 SBM_SETPOS 但我猜它是直接发送到嵌入式滚动条的。在最坏的情况下,我想我必须听 Key down 事件。
  • 使用TWinControl的WindowProc属性的好例子。
猜你喜欢
  • 1970-01-01
  • 2013-10-12
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多