【问题标题】:Why does a combo box change its text to an item text at font change?为什么组合框会在字体更改时将其文本更改为项目文本?
【发布时间】:2012-09-30 05:46:14
【问题描述】:

这显然是一个错误,但我无法追查为什么会发生。这是一个要重现的简约代码。只需在表单上放置一个组合框和按钮,然后编写以下事件处理程序:

procedure TForm1.FormCreate(Sender: TObject);
begin
  ComboBox1.Items.Add('A Item');
  ComboBox1.Items.Add('B Item');
  ComboBox1.Items.Add('C Item');
  ComboBox1.Style := csDropDown;
  ComboBox1.AutoComplete := False;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ComboBox1.Text := 'B';
  ComboBox1.Font.Color := clRed;
  ShowMessage(IntToStr(ComboBox1.ItemIndex));
end;

当您第一次单击按钮时,您将在组合编辑中看到第二个项目的完全选定文本,但消息框会显示项目索引等于 -1。当您下拉它时,似乎选择了第二个项目。第二次单击将设置正确的文本,但其余部分与第一次单击时相同。因此,在这种情况下,组合框的行为就像启用了一些奇怪的自动完成功能。

我已将此追踪到EditWndProc,在收到字体更改后WM_SETTEXT 消息与第二项的文本,但我不知道它来自哪里以及为什么与第二项的文本项目。

所以,我的问题非常具体 - 什么(哪种方法)在字体更改时发送 WM_SETTEXT 以及在禁用自动完成时它如何知道第二项文本匹配?

到目前为止,我可以在安装了最新更新的 Windows 7 Home Premium 64 位上的 Delphi 2009 和 Delphi XE3 中重现此问题。

【问题讨论】:

  • 在 delphi 2007 中确认的相同行为认为这可能是 windows api 错误,您在哪个版本的 windows 中进行了测试?
  • 我会将它包含在问题中,在 Windows 7 上。
  • @whosrdaddy,是的,但在这种情况下,有关操作系统的更具体信息可能会很方便;-)
  • 据我所知,TComboBox 的“自动完成”纯粹是一种 VCL 便利(至少在 D2007 中),并且仅在按键事件中有效。我猜VCL与此无关。

标签: delphi winapi windows-7 delphi-2009 delphi-xe3


【解决方案1】:

我对 Delphi XE8 的实验似乎表明,只要你第一次开始使用 TComboBox 并且在你之前首先给它写文本。我认为 WM_SETTEXT 选择错误的文本只会在第一次写入字体颜色(或其他字体属性)时发生。之后,一切正常。无论是 Windows 还是 Delphi 中的错误,我都懒得去发现,因为这个技巧为我解决了问题。 :) 然而,我怀疑这是“初始化之前的操作”的另一种情况,因为当您为用户提供大量后期构造时,编码人员没有考虑到事情并不总是以方便的顺序调用的事实配置属性(例如更改尚未使用的 TCombobox 中的字体和文本)。如果这确实是“万灵药”,那么也许我们应该说服 Delphi 团队为我们将其放入 TCombobox(或祖先)构造函数中。顺便说一句,这个相同的“错误”导致 SelLength 从零开始变化 - 非常烦人,因为它最终将文本框着色为蓝色,暗示焦点,而当焦点不是!因此,如果您的表单上有很多组合框都显示为蓝色并声称拥有焦点 - 这也是特别令人头疼的根源!

顺便说一句,我已经向 Embarcadero 提出了这个问题,并提出了一个解决方案,将上述技巧合并到基本构造函数中。他们将其传递给编码人员,但新版本的 Delphi 是否会包含必要的修复还有待观察。

【讨论】:

    【解决方案2】:

    只需启用调试 DCU,然后进入 Font.Color 属性设置器,您就可以在几秒钟内自行追踪到这一点。

    Font 因任何原因发生更改时,将触发TFont.OnChange 事件。 TControl 具有分配给它的事件处理程序,即使它可以向自己发送 CM_FONTCHANGED 消息以允许后代类对更改做出反应。当TWinControl 收到该消息时,它会向自身发送WM_SETFONT 消息,然后触发 ComCtl32 发送您所看到的WM_SETTEXT 消息。

    【讨论】:

    • 刚刚也发现了这个,所以它在第二次点击时正常工作的原因是字体已经是红色的。
    • 我肯定用过 debug dcus;我无法追踪到 EditWndProc 方法和导致更改的消息。我一直对这个发件人如何知道匹配项感兴趣,但即使您的回答也暗示发送此消息的是 comctl32。
    • 我不明白这个怎么回答为什么文本会变成一个项目文本。
    • @TLama:启用调试 DCU 后,您可以进入 Font.Color 属性分配并使用调试器遵循逻辑流程,直到 EditWndProc() 在 @987654333 时使用 WM_SETTEXT 消息调用@ 向自己发送 WM_SETICON 消息。 @SertacAkyuk 是正确的,ComboBox 的自动完成行为与 AutoComplete 属性无关,该属性仅在按键处理期间使用。
    【解决方案3】:

    我认为这不是 VCL 问题,查看调用堆栈,似乎消息似乎是通过 comctl32.dll 处理的。 可以通过在设置文字之前设置字体颜色来解决问题:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ComboBox1.Font.Color := clRed;
      ComboBox1.Text := 'B';
      ShowMessage(IntToStr(ComboBox1.ItemIndex));
    end;
    

    【讨论】:

    • 我也在悄悄地怀疑 Windows。我只有 Windows 7 可用,所以我无法在其他版本上验证这一点,你在哪里试过这个?
    • 德尔福 XE/W7。如果你愿意,我明天可以在 XP 上试试这个
    • 更改字体时是否调用了类似 ReCreateWnd 的东西?
    • @TLama:XP 的行为方式相同(这是预期的)
    • @Arioch,没有。在内部深处将是SelectObject GDI 函数。 whosrdaddy,感谢您的确认!
    猜你喜欢
    • 2013-02-14
    • 2013-02-15
    • 2017-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    相关资源
    最近更新 更多