Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

VB6 コンボボックスのBeginUpdateにかわるものは? 解決済み

タグの編集...

投稿者 はなな   (社会人)   投稿日時 2022/5/11 14:16:05
VB6でコンボボックスにとあるデータを表示しているのですが、とても遅いです。
データの数も多いですが、表示するコンボボックスも複数あります。

簡単に書くと下記のようなものなのですが...

   Dim Count as Long
   Dim i as Long

   Count = 10000

   cmbbox1.clear
   cmbbox2.clear
   cmbbox3.clear
   cmbbox4.clear
   cmbbox5.clear

    For i = 0 To Count - 1
        cmbbox1.AddItem i
        cmbbox2.AddItem i+10
        cmbbox3.AddItem i+100
        cmbbox4.AddItem i+1000
        cmbbox5.AddItem i+10000
    Next


VB.NETのBeginUpdate、EndUpdateの代わりとなるようなものはないのでしょうか?

どなたかご存じの方がいましたら教えて下さい。
よろしくお願い致します。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/11 19:24:43
手元に VB6 が残ってないので試せないので、以下すべて未検証ですが。

そもそも 10000 件のデータを ComboBox に追加する時点で、
使いにくすぎるかと。選択したり探すのも大変なので、
まずは UI を見直すことをお奨めします。

> とても遅いです。
どのくらいかかるのですか?


> 簡単に書くと下記のようなものなのですが...

ひとまず、Visible = False 状態にしてから Clear & AddItem して、
完了後に Visible = True してみたら高速化されないでしょうか?

あるいは、ComboBox 操作前に
 SendMessageA ComboBox1.hWnd, WM_SETREDRAW, ByVal 0&, ByVal 0&
を呼んでから Clear & AddItem して、操作後に
 SendMessageA ComboBox1.hWnd, WM_SETREDRAW, ByVal 1&, ByVal 0&
を呼んでみるとか。


それでも遅いなら、たとえば 0.3 秒間で何件ぐらい登録できるのかを見極め、
その件数分、Timer 等を併用して、一度に少しずつ追加するようにするとか。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/11 20:00:23
あとは、「標準コントロール」では「ActiveXコントロール」に切り替えて、

ADOData Control(ADODC1) → DataCombo コントロール
Data Control(Data1) → DBCombo  コントロール

で、大量データをバインドした時の時間と比較してみるとか。(環境が無いので未確認)


DataCombo Control (OLEDB) … msdatlst.ocx
 DataList Control (OLEDB) … msdatlst.ocx
  DBCombo Control         … dblist32.ocx
   DBList Control         … dblist32.ocx


投稿者 はなな   (社会人)   投稿日時 2022/5/12 09:49:28
魔界の仮面弁士様、ありがとうございます。

>そもそも 10000 件のデータを ComboBox に追加する時点で、

10000 件は例えで書いてしまいました。すみません。
実際は各マスタ(多いものは300件程)を読み込んでFORM_LOAD時に表示させています。
コンボボックスの数は13個です。

各マスタを読み込みコンボボックスに表示させる、までの時間はだいたいい0.76秒です。
私のところでは0.76秒ですが、運用環境ではもっと遅いようです。


>ひとまず、Visible = False 状態にしてから Clear & AddItem して、
>完了後に Visible = True してみたら高速化されないでしょうか?

こちらを試してみましたが、0.76秒で変わりませんでした。


>あるいは、ComboBox 操作前に
> SendMessageA ComboBox1.hWnd, WM_SETREDRAW, ByVal 0&, ByVal 0&
>を呼んでから Clear & AddItem して、操作後に
> SendMessageA ComboBox1.hWnd, WM_SETREDRAW, ByVal 1&, ByVal 0&
>を呼んでみるとか。

こちらを試しているところですが、私の知識不足によりエラーでまだ実行できておりません。
また報告させていただきますので、よろしくお願い致します。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/12 11:37:34
.NET の BeingUpdate / EndUpdate は、WM_SETREDRAW を呼び出していますので、先の案はそれを模したものです。
https://dobon.net/vb/dotnet/control/beginupdate.html#wmsetredraw

> 私の知識不足によりエラーでまだ実行できておりません。
手元に環境が無いので掲示板直書きですが、宣言はこんな感じ。

Private Const WM_SETREDRAW As Integer = &HB
Private Declare Function SendMessageA Lib "user32" (ByVal hwnd As OLE_HANDLE, ByVal msg As Long, wParam As Any, lParam As Any) As Long



> 0.76秒で変わりませんでした。
Form_Load で処理しているなら変わらないと思います。
通常は Load イベントを抜けるまで、コントロールは表示されていない状態ですから。


> コンボボックスの数は13個です。
トータルで 0.76 秒なのか、それとも、13 個 × 0.76 秒≒ 10秒程度なのかはさておき。

質問内容からすると、.NET で BeginUpdate した時には 0.76 秒を下回るので、
VB6 でもそれを目指したい…ということでしょうか?

ちなみに当方の .NET で試した時には、13個×300件で 1.2 秒程度でした(AddRange でも同様)。
BeginUpdate しない場合は 3.3 秒程度でした。

Public Class Form1
    Private combos As New List(Of ComboBox)()
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        For i = 1 To 13
            Dim c As New ComboBox() With {.Name = $"ComboBox{i}", .DropDownStyle = ComboBoxStyle.DropDownList}
            c.Items.Add(c.Name)
            c.SelectedIndex = 0
            combos.Add(c)
            FlowLayoutPanel1.Controls.Add(c)
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim sw = Stopwatch.StartNew()
        For Each cb As ComboBox In combos
            cb.BeginUpdate()
            cb.Items.Clear()
            For n = 1 To 300
                cb.Items.Add(n)
            Next
            cb.EndUpdate()
        Next
        sw.Stop()
        Button1.Text = sw.Elapsed.ToString()
    End Sub
End Class



> 各マスタを読み込みコンボボックスに表示させる、までの時間はだいたいい0.76秒です。
> 私のところでは0.76秒ですが、運用環境ではもっと遅いようです。

運用環境のボトルネックは ComboBox だけでしょうか。
検証用に、マスターではなく最初の例のような固定的なデータを 300件用意し、
それを単純に追加するだけの処理でも、同じように時間がかかるか確認してみてください。

たとえばデータベースアクセスがある場合における当方の経験ですが、
対 Oracle の場合において、oo4o でのダイナセットと ADODB の前方カーソルを
比較したところ、MoveNext の時間は ADODB の方が早かったため、
ミドルウェアの変更で高速化させたことがあります。

投稿者 はなな   (社会人)   投稿日時 2022/5/12 12:18:46
魔界の仮面弁士様、ありがとうございます。
結果から申しますと、0.76秒から0.36秒に短縮することが出来ました!


>.NET の BeingUpdate / EndUpdate は、WM_SETREDRAW を呼び出していますので、先の案はそれを模したものです。
実はこちらを見ていたのですが、宣言の記載がうまくいかずに苦戦していました。
魔界の仮面弁士様に宣言のところを記載いただいたおかげで、実行することが出来ました。
ありがとうございました。


>トータルで 0.76 秒なのか、それとも、13 個 × 0.76 秒≒ 10秒程度なのかはさておき。
トータルで 0.76 秒でした。

>質問内容からすると、.NET で BeginUpdate した時には 0.76 秒を下回るので、
>VB6 でもそれを目指したい…ということでしょうか?
はい、その通りです。


>運用環境のボトルネックは ComboBox だけでしょうか。
>検証用に、マスターではなく最初の例のような固定的なデータを 300件用意し、
>それを単純に追加するだけの処理でも、同じように時間がかかるか確認してみてください。
データアクセスが遅い原因かと思って調査したのですが、
単純に追加するだけの処理でも同じくらいの時間がかかっていましたので
コンボボックスに表示するところで時間がかかっていると分かり、今回の質問をさせていただきました。


おかげさまで、時間短縮することができ助かりました。
ありがとうございました。

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/5/13 19:33:44
> 宣言はこんな感じ。
> Private Const WM_SETREDRAW As Integer = &HB

ごめんなさい、間違えていました。

本来はこうですね。
Private Const WM_SETREDRAW As Long = &HB&

※ SendMessage 側で ByVal msg As Long にて受けるようにしているので、実害は無いですが。

投稿者 はなな   (社会人)   投稿日時 2022/5/16 09:46:48
魔界の仮面弁士さん、ありがとうござます。

IntegerでなくLongですね!
実害は無い、とのことですが修正しておきます。
ありがとうございました。