3 Stimmen

Das Laden von Daten in ein Kombinationsfeld ist langsam

Ich habe eine VB6-Anwendung mit einer Suchmaske. In der Suchmaske habe ich 9 Kombinationsfelder. Einige der Kombinationsfelder haben nur ein paar Einträge, aber einige haben ein paar hundert Einträge. Es dauert lange (einige Sekunden), bis die Daten ausgefüllt sind.

Jedes Kombinationsfeld ist gleich konfiguriert: Sorted = False, Style = 2 - Dropdown-Liste

3 der Kombinationsfelder haben weniger als 20 Einträge. 1 hat 130 Einträge. 4 haben ungefähr 250 Einträge 1 hat fast 700 Einträge.

Ich fülle alle neun Kombinationsfelder mit ähnlichem Code.

While Not RS.EOF

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

    i = i + 1

    RS.MoveNext
Wend

Ich habe versucht, Visible = False zu setzen, aber das hatte keine Auswirkungen auf die Leistung.

Gibt es einen anderen Weg, um das Kombinationsfeld zu füllen, die besser als meine bestehende Methode durchführen wird?

8voto

Robert Harvey Punkte 173098

Hier ist etwas, das Sie ausprobieren können. Laut diese Stelle können Sie etwa 60 % des Aufwands einsparen, indem Sie eine Windows-API-Funktion zum Auffüllen des Kombinationsfelds anstelle der üblichen AddItem-Methode verwenden:

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

Möglicherweise können Sie ein wenig mehr einsparen, indem Sie den Funktionsaufruf weglassen und nur die API-Funktion direkt aufrufen.

5voto

Kredns Punkte 35211

Sie müssen Ihr Design wirklich überdenken. Kein Benutzer wird zwischen 700 Elementen in einem Kombinationsfeld wählen wollen. Wenn Sie das nicht korrigieren, wirkt Ihre App unübersichtlich.

Mir kommt immer ein Bild in den Sinn, wenn ich eine solche Situation höre:

2voto

onedaywhen Punkte 52850

Einige Vorschläge:

  • Utilisez With RS .

  • Verwenden Sie die Recordset-Objektfunktion RecordCount Eigenschaft, anstatt zu prüfen, ob EOF bei jeder Iteration (wenn RecordCount = -1 dann sollten Sie den Cursortyp, die Cursorposition usw. ändern, um sicherzustellen, dass RecordCount unterstützt wird).

  • Verwenden Sie eine For..Next Schleife, anstatt eine eigene Iteratorvariable zu pflegen.

  • Verwenden Sie den Operator bang ( ! ).

Zum Beispiel:

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

Vielleicht sollte man auch die Einstellung der Combo's Sorted Eigenschaft zu False und wenn eine Sortierung erforderlich ist, dann verwenden Sie entweder die Recordset's Sort Eigenschaft oder führen Sie die Sortierung an der Quelle durch (z. B. mit einer ORDER BY Klausel im SQL-Code).

2voto

MarkJ Punkte 29670

Sie können versuchen, der Combobox mitzuteilen, dass sie sich nicht neu malen soll, während Sie die neuen Elemente hinzufügen. Sie können dies mit WM_SETREDRAW . EDIT - offenbar hat dies nicht helfen, wahrscheinlich, weil das Kombinationsfeld ausgeblendet wird, während es gefüllt ist, die wahrscheinlich gibt Ihnen alle die gleichen Vorteile.

  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&)

Warnung: viele ansonsten ausgezeichnete VB6-Websites sagen Sie zu verwenden LockWindowUpdate stattdessen. Tun Sie das nicht, sonst werden Sie Bugs bekommen . Auch die Missgunst der Raymond Chen !

1voto

AngryHacker Punkte 56638

Warum füllen Sie die Liste im Voraus auf und füllen dann List(i) und ItemData(i) neu auf? Stattdessen sollten Sie wie folgt vorgehen

While Not RS.EOF

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

    RS.MoveNext
Wend

Sie werden keinen Leistungsunterschied zwischen der Antwort von Robert Harvey und dem obigen Code feststellen. Für zusätzliche Geschwindigkeit, wenden Sie MarkJs Antwort an.

Ein weiteres Problem könnte der Cursor sein, den Sie verwenden, um die Daten aus der Datenbank zurückzuholen. Da Sie jedes einzelne Element aus dem Recordset laden, gibt es kaum einen Grund, einen serverseitigen Cursor zu verwenden. Daher sollten Sie beim Abrufen des Datensatzes einen clientseitigen Cursor angeben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X