为什么组合框会在字体更改时将其文本更改为项目文本?

时间:2012-10-09 20:16:12

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

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

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中重现这一点。

3 个答案:

答案 0 :(得分:4)

您可以通过简单地启用调试DCU然后单步执行Font.Color属性设置器,在几秒钟内自行跟踪。

当因任何原因更改Font时,会触发TFont.OnChange事件。 TControl有一个事件处理程序,即使这样它也可以向自己发送一条CM_FONTCHANGED消息,以允许后代类对更改作出反应。当TWinControl收到该消息时,它会向自己发送一条WM_SETFONT消息,然后触发ComCtl32发送您正在看到的WM_SETTEXT消息。

答案 1 :(得分:2)

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

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

答案 2 :(得分:0)

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

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