2009-08-04 2 views
3

У меня есть приложение VB6 с экраном поиска. В поиске у меня есть 9 комбинированных ящиков. В некоторых из списков есть только пара элементов, но у некоторых есть пара сотен предметов. Для заполнения данных требуется много времени (пару секунд).Загрузка данных в комбинированное поле происходит медленно

Каждый выпадающий настроен тот же: Рассортировано = False, Style = 2 - Выпадающий список

3 из комбинированных окон имеют менее 20 пунктов. 1 имеет 130 единиц. 4 имеют приблизительно 250 предметов 1 имеет почти 700 предметов.

Я заполняю все девять комбинированных коробок с похожим кодом.

While Not RS.EOF 

    cmbX.List(i) = RS("Description") 
    cmbX.ItemData(i) = RS("Id") 

    i = i + 1 

    RS.MoveNext 
Wend 

Я попытался установить Visible = False, но это не повлияло на производительность.

Есть ли другой способ заполнить поле со списком, которое будет работать лучше, чем мой существующий метод?

ответ

8

Вот что вы можете попробовать. По this post вы можете бриться около 60% от вашего накладных расходов с помощью функции API Windows, для заполнения поля со списком, вместо обычного метода AddItem:

Private Const CB_ERR As Long = -1 
Private Const CB_ADDSTRING As Long = &H143 
Private Const CB_RESETCONTENT As Long = &H14B 
Private Const CB_SETITEMDATA As Long = &H151 

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal _ 
hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long 

Public Sub AddItem(cmb As ComboBox, Text As Variant, Optional ItemData As Long) 

    Dim l As Long 
    Dim s As String 

    If VarType(Text) = vbString Then 
     s = Text 
    Else 
     s = Trim$(Str$(Text)) 
    End If 

    l = SendMessage(cmb.hwnd, CB_ADDSTRING, 0&, ByVal s) 
    If l <> CB_ERR Then 
     SendMessage cmb.hwnd, CB_SETITEMDATA, l, ByVal ItemData 
    End If 

End Sub 

Public Sub Clear(cmb As ComboBox) 
    SendMessage cmb.hwnd, CB_RESETCONTENT, 0, 0& 
End Sub 

Вы могли бы побриться еще немного опуская вызов функции и просто вызов функции API напрямую.

+0

Это намного быстрее. Благодарю. В настоящее время я помещаю ID в свойство ItemData в поле со списком. Я использую это, когда пользователь нажимает кнопку поиска. Я мог хранить данные в массивах и использовать свойство ListIndex в поле со списком, чтобы получить идентификатор, но ... есть ли способ установить свойство ItemData? ' –

+0

Я добавил код, включающий вызов для добавления ItemData. –

+0

Спасибо. Он работает, и он быстрее. Именно то, что я искал. –

3

Вам действительно нужно переосмыслить свой дизайн. Ни один пользователь не захочет выбирать между 700 элементами в поле со списком. Это заставит ваше приложение казаться загроможденным, если вы его не исправите.

Изображение всегда приходит на ум, когда я слышу такую ​​ситуацию:

+2

Опознавательный рисунок, Лукас! Одна картинка стоит тысячи слов. – DOK

+0

@ DOK: Спасибо. В первый раз, когда мне это показалось, я очень усмехнулся. ;-) – Kredns

+0

iPod должен иметь дым, исходящий из него, хотя http://www.guardian.co.uk/technology/blog/2009/aug/03/uk-ipod-explodes – MarkJ

0

Это похоже, как долгое время. Как вы открываете свои записи? Используете ли вы плагины (только для чтения, только для записей)? Если вы этого не сделаете, вы можете получить некоторое улучшение производительности. Убедитесь, что ваши операторы SQL ТОЛЬКО возвращают данные, необходимые для комбинированных ящиков (т. Е. НЕ используют SELECT *).

Если ваши инструкции SQL содержат предложения WHERE или JOINS, убедитесь, что у вас есть индексы в соответствующих полях.

Если вы используете ACCESS в качестве бэкэнд, вы получите немедленное повышение скорости путем увеличения до SQL Server Express.

+0

Спасибо за полезный комментарий! Я использую SQL Server. Все запросы оптимизированы в меру моих возможностей. Фактически, я возвращаю несколько записей из одной хранимой процедуры. Хранимая процедура выполняется в 50 миллисекундах в окне запроса SQL Server. Он возвращается к vb примерно за 200 миллисекунд. Я чувствую себя комфортно, говоря, что это НЕ проблема с базой данных. –

2

Некоторые предложения:

  • Использование With RS.

  • Использование объекта Recordset в RecordCount свойства, а не тест на EOF на каждой итерации (если , то вы должны изменить тип курсора, курсор местоположение и т.д., чтобы обеспечить RecordCount поддерживается).

  • Используйте петлю For..Next, а не поддерживайте собственную переменную итератора.

  • Используйте оператора bang (!).

Например:

With RS 

    Debug.Assert .RecordCount >= 0 

    Dim counter As Long 
    For counter = 0 To .RecordCount - 1 

    cmbX.List(counter) = !Description 
    cmbX.ItemData(counter) = !Id 

    .MoveNext 
    Next 

End With 

Возможно, что-то еще, чтобы рассмотреть устанавливает Sorted свойство Комбо для False и если сортировки требуется, то либо использовать Sort свойство Recordset или сделать сортировку в источнике (например, используя предложение ORDER BY в коде SQL).

+0

sorted уже установлен на false (как указано в моем первоначальном сообщении). Использование с блоком немного ускорило ситуацию, но не сильно изменило ситуацию. Однако я ценю предложение. Благодарю. –

2

Вы можете попытаться сказать, что вы не можете перекрасить себя при добавлении новых элементов. Вы можете сделать это с помощью WM_SETREDRAW. EDIT - видимо, это не помогло, возможно, потому, что поле со списком скрывается, пока оно заполнено, что, вероятно, дает вам все те же преимущества.

Private Declare Function SendMessage Lib "user32" Alias "SendMessageA"(_ 
    ByVal hwnd As Long, ByVal wMsg As Long, _ 
    ByVal wParam As Long, lParam As Any) As Long 
    Private Const WM_SETREDRAW = &HB 

    Call SendMessage(cmbX.hWnd, WM_SETREDRAW, 0, 0&) 
    'DO STUFF' 
    Call SendMessage(cmbX.hwnd, WM_SETREDRAW, 1, 0&) 

Предупреждение: много иначе прекрасных VB6 сайтов tell вам использовать LockWindowUpdate вместо. Не делайте этого, или вы будете get bugs. Также disfavour Raymond Chen!

+0

Спасибо за предложение. К сожалению, это не вызвало заметных улучшений. –

1

Почему вы предварительно заполняете список, а затем повторно заполняете список (i) и ItemData (i)? Вместо этого вы должны сделать следующее:

While Not RS.EOF 

    cmbX.AddItem RS("Description") 
    cmbX.ItemData(cmbX.NewIndex) = RS("Id") 

    RS.MoveNext 
Wend 

Вы увидите нулевое различие в производительности между ответом Роберта Харви и приведенным выше кодом. Для дополнительной скорости примените ответ MarkJ.

Другой проблемой может быть курсор, который вы используете, чтобы вернуть данные из базы данных. Поскольку вы загружаете каждый элемент из набора записей, очень мало причин иметь серверный курсор. Таким образом, вы можете указать курсор на стороне клиента при получении набора записей.

+0

Спасибо за ваше предложение. Я не заполняю список и список (i) и ItemData (i). AddItem во много раз медленнее, чем установка свойства списка. Ваше предложение во много раз медленнее, чем у Роберта Харви. Фактически, это в 10 раз медленнее. Я уже использую курсор на стороне клиента, проблема не в базе данных. –

+0

Хорошо, может быть, не предварительная, но вы сначала создаете строки, а затем заполняете их. Вкратце вы делаете это: cmbX.AddItem "" cmbX.List (i) = "blah" cmbX.ItemDate (i) = 123 Я не уверен, что ваш путь быстрее – AngryHacker

0

«» Populate COMBOBOX

мне пришлось ждать 20 секунд, чтобы моя программа заселить город выпадающий с 80000 записей я попробовал несколько методов, но все они были хуже

это был мой оригинальный код

Me.txt_City.DataSource = tblCities 
    Me.txt_City.ValueMember = "city" 
    Me.txt_City.DisplayMember = "city" 

и угадайте, что я только что переехал первую строку кода в конце , а затем население заняло всего 5 секунд

Me.txt_City.ValueMember = "city" 
    Me.txt_City.DisplayMember = "city" 

    Me.txt_City.DataSource = tblCities 

попробуйте его

Смежные вопросы