2012-10-09 6 views
4

Это, очевидно, ошибка, но я не могу отследить, почему происходит. Вот минималистский код для воспроизведения. Просто поместите поле со списком и кнопки на форме и написать следующие обработчики событий:Почему поле со списком меняет текст на текст элемента при изменении шрифта?

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 при изменении шрифта и как он узнает о совпадении текста второго элемента, когда автозаполнение отключено?

До сих пор я мог воспроизвести это в Delphi 2009 и Delphi XE3 на Windows 7 Home Premium 64-бит с установленными последними обновлениями.

+0

Такое же поведение подтверждено в delphi 2007, это может быть ошибка api в Windows, в какой версии окон вы проверили? – MikeT

+0

Я включу его в вопрос, в Windows 7. – TLama

+1

уже добавил тег :) – whosrdaddy

ответ

2

Я не думаю, что это проблема VCL, глядя на стек вызовов, кажется, что сообщение похоже обрабатывается через comctl32.dll. Вы можете решить эту проблему, установив цвет шрифта перед установкой текста:

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

Я также спокойно подозреваю Windows. У меня есть только Windows 7, поэтому я не могу проверить это на других версиях, где вы это пробовали? – TLama

+0

Delphi XE/W7. Я могу попробовать это на XP завтра, если вы хотите – whosrdaddy

+0

Это было бы здорово, спасибо! – TLama

4

Вы могли бы отследить это вниз самостоятельно в течение нескольких секунд, просто позволяя Debug DCUs, а затем заходя в Font.Color собственности сеттера.

Когда по какой-либо причине изменяется Font, происходит событие TFont.OnChange. TControl имеет обработчик событий, назначенный этому, даже если он может отправить сообщение CM_FONTCHANGED, чтобы позволить классам потомков реагировать на изменение. Когда TWinControl получает это сообщение, он отправляет сообщение WM_SETFONT себе, которое затем запускает ComCtl32 для отправки сообщения WM_SETTEXT, которое вы видите.

+0

только что нашел это, поэтому причина, по которой он работает правильно во втором клике, - это уже красный шрифт. – MikeT

+1

Конечно, я использовал debug dcus; Я не смог бы отследить это до метода «EditWndProc» и сообщения, которое вызывает изменение. Больше мне было интересно, как этот отправитель знает о соответствующем элементе, но даже ваш ответ подразумевает, что это comctl32 отправляет это сообщение. – TLama

+3

Я не понимаю, как этот ответ объясняет, почему текст меняется на текст элемента. –

0

Мои эксперименты с Delphi XE8 показывают, что может быть достаточно, чтобы заставить запрос на изменение шрифта (скажем, просто установив цвет в clBlack, даже если он уже есть), как только вы впервые начнете использовать TComboBox и до этого вы сначала пишете текст. Понятно, что WM_SETTEXT выбирает неправильный текст, это происходит только в первый раз, когда записывается шрифт (или другие атрибуты шрифта). После этого все ведет себя правильно. Является ли это ошибкой в ​​Windows или Delphi, я не мог потрудиться, чтобы узнать, так как этот трюк вылечил проблему для меня. :) Я подозреваю, однако, что это еще один случай «действия перед инициализацией» в том, что кодеры не учитывали тот факт, что вещи не всегда вызываются в удобном порядке, когда вы предоставляете своим пользователям множество постконструирующих (например, изменение шрифтов и текста в неиспользуемом TCombobox). Если это окажется «излечением», то, возможно, нам следует убедить команду Delphi поместить ее в конструктор TCombobox (или предка) для нас. Кстати, эта же «ошибка» приводит к тому, что SelLength изменяется с нуля - очень раздражает, потому что она заканчивает окрашивание текстового поля синим цветом, что подразумевает фокус, когда он не фокусируется на нем! Поэтому, если вы получите много comboboxes в своей форме, все отображаются синим цветом и утверждают, что у вас есть фокус - это источник этой конкретной головной боли!

Кстати, я поднял эту проблему с Embarcadero и предложил решение, в котором вышеупомянутый трюк включен в базовый конструктор. Они передали его кодировщикам, но еще предстоит выяснить, будут ли новые версии Delphi включать необходимое исправление.