SetFocus清除编辑框。 (跨Windows和/或delphi版本的不同行为)

时间:2014-06-06 04:03:08

标签: delphi

喋喋不休有问题。

(一个由丰富的编辑框和编辑组成的简单聊天。) (第一个显示来自双方的消息,第二个用于输入新消息)

以下命令清除编辑框。 (参见下面的SetFocus)

我不想要那个。

此行为从Windows XP更改为Windows 7或delphi版本之间不确定是哪个。

上次我看过这个,我觉得它可能是windows版本的变化,delphi的编辑框可能已经用windows apis实现了。

在Windows XP和/或以前版本的Delphi上没有用它。

问题在于:

vActiveControl.SetFocus;

这会清除编辑框...我不想要那个。

当用户输入新消息并且消息从另一方到达时,这是一个问题...代码在富编辑消息和编辑框之间来回切换焦点。 这导致新输入的消息被清除,这是令人讨厌的。 (想到一个可能的解决方案是记住在触发器发生后输入的内容并重新粘贴它)

在更新丰富的编辑聊天消息后,必须将焦点设置回此编辑框。 这样用户就可以继续输入新消息了。

有一个简单的解决方法吗? (也许记住技巧和重复可能有用,也许还有其他解决方案)

如果富编辑聊天消息会自动向下滚动,那也很好 不需要专注......现在重点介于两者之间 聊天消息和聊天编辑框以输入新消息。

如果用户想要快速输入消息...它可能最终会出现在富编辑框中 导致设置焦点回到聊天编辑框没有发生得足够快..

我可以尝试用firemonkey替换vcl ......我不确定是不是firemonkey 有更好的支持编写网络聊天应用程序和聚焦和文本滚动等。 我也可以调查一下。 复制&粘贴文本也很好。

(如果修复程序可以在Windows版本中运行,也许首选也可以使用记忆和重写技巧,我知道firemonkey可能无法在所有Windows版本上运行,我正在考虑制作双版本,一个vcl和一个firemonkey版本。)

procedure TFormMain.ChatterMessageReceived( Sender : TObject );
var
    vActiveControl : TWinControl;
begin
    vActiveControl := Screen.ActiveControl;


//  RichEditChatterMessages.Lines.Add( ProtocolWrapper.Chatter.OtherNickname + ': ' + ProtocolWrapper.Chatter.OtherMessage );
    RichEditChatterMessages.Lines.Add( 'Remote: ' + ProtocolWrapper.Chatter.OtherMessage );



//  RichEditChatterMessages.Perform(EM_LineScroll, 0, RichEditChatterMessages.Lines.Count); // werkt niet goed
    if ColoredPageControl1.ActivePage = ColoredTabSheetChatter then
    begin
        RichEditChatterMessages.SetFocus; // must set focus first for perform scroll caret to work
    end;

    RichEditChatterMessages.Perform (em_scrollcaret,0,0);

    if vActiveControl <> nil then
    begin
        vActiveControl.SetFocus;
    end;

    ColoredTabSheetChatter.TabColor := clLime;
    FlashApplication;
end;

自从我发现这个问题以来,互联网已经更新。

我遇到了这个目前似乎工作的解决方案......将不得不在不同的Windows版本和情况下进行测试......看起来很有希望,暂时删除这个问题,因为它可能已经重复了:< / p>

procedure ScrollToEnd(ARichEdit: TRichEdit);
var
isSelectionHidden: Boolean;
begin
  with ARichEdit do
begin
    SelStart := Perform(Messages.EM_LINEINDEX, Lines.Count, 0);//Set caret at end
    isSelectionHidden := HideSelection;
    try
      HideSelection := False;
    Perform(Messages.EM_SCROLLCARET, 0, 0);  // Scroll to caret
    finally
    HideSelection := isSelectionHidden;
    end;
end;
end;

procedure TFormMain.ChatterMessageReceived( Sender : TObject );
begin

//  RichEditChatterMessages.Lines.Add( ProtocolWrapper.Chatter.OtherNickname + ': ' + ProtocolWrapper.Chatter.OtherMessage );
    RichEditChatterMessages.Lines.Add( 'Remote: ' + ProtocolWrapper.Chatter.OtherMessage );

    ScrollToEnd(RichEditChatterMessages);

    ColoredTabSheetChatter.TabColor := clLime;
    FlashApplication;
end;

我虽然取消了这个问题。

这个解决方案有其他缺点。

如果其他用户正在聊天,用户可能无法再选择文字。

它似乎也引发了例外。 (不知道为什么,也许它会在用户尝试选择文本时发生,或者可能是异常的原因来自于其他事情......调查...)

这是一个令人讨厌的问题......

我认为解决方案是使用适用于任何版本的RichEdit dll delphi正在使用的解决方案。

这会产生一些棘手的情况......如果有人想编写适用于所有delphi版本的代码......

现在只使用它似乎适用于Delphi XE6:

执行(Messages.EM_SCROLLCARET,0,0); //滚动到插入符号

如果我希望这段代码适用于所有delphi版本,我可能必须使用{$ ifdef} ......

所以我将来可能再次调查这个问题。

以下是有关此控件的Microsoft软件文档的一个很好的链接:

http://msdn.microsoft.com/en-us/library/windows/desktop/bb787873(v=vs.85).aspx

有4个版本:

•Rich Edit的版本  ◦Rich编辑版本1.0  ◦Rich编辑版本2.0  ◦Rich编辑版本3.0  ◦Rich编辑版本4.1

我不确定哪个Delphi版本使用哪个控件版本。

哪个版本的控件有滚动问题......

继续......

(目前我将专注于Delphi XE6,如果我希望我的软件可以在不同的Windows版本和delphi版本上运行,将来可能会回到这个问题)

这可能是一个很酷的解决方案:

How to test if a control is a RichEdit control

^在运行时检测任何delphi版本正在使用哪个版本的控件。

然后为每个控件版本编写一个解决方案,这很不错。

进一步提示: ComCtrls单元具有此代码,用于确定要加载的版本: RichEditModuleName =&#39; RICHED20.DLL&#39;;

也许可以用简单的Tmemo替换丰富的编辑...或者可能不是......也许Tmemo不会滚动或者它可能是同一种控制......或者看起来不太好......不确定为什么选择富编辑。我想我担心Tmemo只能包含有限的线路?

这种执行解决方案也不是很好。 如果用户将焦点切换到其他控件......它将干扰这些控件的胡萝卜。 Woops忘了包含RichEditControl .. 代替: 执行(Messages.EM_SCROLLCARET,0,0); //滚动到插入符号 此代码更好用: RichEditChatterMessages.Perform(Messages.EM_SCROLLCARET,0,0); //滚动到插入符号

性能监控控制本身就令人耳目一新,因此也不是测试这种效果的好方法......到目前为止一直很好。

也许切换到像firemonkey这样的更好的GUI可能是一个解决方案。虽然firemonkey可能会引入新的问题,但是用vcl / richedit看到所有这些问题......值得一试。虽然firemonkey ...不确定哪个Windows版本可以使用...现在仍然有趣的是调查vcl / richedit等等旧的os-es等。

还有什么尚未讨论的是为什么Tedit在收到时很清楚.SetFocus ......嗯......

下面的一位评论员发现了这个问题。 TEdit.AutoSelect属性设置为True时会创建此清除行为...请参阅下面的测试代码&#34; despatcher&#34;。

剩下的一个问题是......如果richedit不可见/焦点或其他东西,则不会滚动...例如,另一个标签是可见的。我尝试在richedit上使用.SetFocus,但似乎没有帮助......实际上它前面有一个分支......如果用户选择了tab,它只会设置焦点...因此SetFocus不是应用......嗯...当然我不能用这样的setfocus打断用户...嗯......所以setfocus可能是不可能的......必须找到一种不同的滚动方式财富向下,所以它在最近的消息上的位置很好......嗯......

好的,最后所有问题都解决了:

SendMessage(RichEditChatterMessages.Handle, WM_VSCROLL, SB_BOTTOM, 0);

完美地适用于向下滚动...只要所有事件处理程序都使用此方法进行丰富的编辑。

1 个答案:

答案 0 :(得分:4)

多年来,我还没有看到TEdit Change的这种基本行为......

在D2009 + Windows 7 64中并在XP上测试过。我毫无困难地进行了模拟工作。我怀疑您将消息编辑器的AutoSelect设置为True。因此,当焦点来回切换时,编辑器会自动选择所有文本,然后您的下一次击键将其删除。发生得太快,你没有注意到。

如果不是这样,您可能会在FlashApplication中进行其他操作。

使用计时器进行模拟:

...
edmessage.AutoSelect := False;
...

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  richedit1.SetFocus;
  richedit1.Lines.Add('Text message, interrupting typing');
  richedit1.SelStart := richedit1.GetTextLen;
  richedit1.SelLength := 0;
  richedit1.ScrollBy(0, richedit1.Lines.Count);
  richedit1.Refresh;
  edmessage.SelLength := 0;
  edmessage.SelStart := edmessage.GetTextLen;
  edmessage.SetFocus;
end;