作成したプログラムを使い回しが聞くようにするために、プログラムを独立したモジュールにしたいのですが、そのプログラムの中にフォームのオブジェクト(と、いうのでしょうか?)が含まれている場合、どのようにモジュールとして、分割するべきなのかわかりません。
これは、ツリービューのノードを利用している時や、リストビューのリストアイテムを利用している時などに頻繁に起こり、今まではあきらめてきました。
以下のプログラムは以前の質問でのものですが、もし、ご面倒でなければ、これからの参考としたいので、これを元に sortNumList() の部分をモジュールに分割していただけないでしょうか?
Option Explicit
Dim isAsc As Boolean
Private Sub Form_Load()
Dim li As ListItem
Set li = lvwList.ListItems.Add(, , "Test")
li.SubItems(1) = FormatCurrency(25.25)
Set li = lvwList.ListItems.Add(, , "TAKE")
li.SubItems(1) = FormatCurrency(10.25)
Set li = lvwList.ListItems.Add(, , "AAAA")
li.SubItems(1) = FormatCurrency(35.55)
Set li = lvwList.ListItems.Add(, , "BBB")
li.SubItems(1) = FormatCurrency(5.55)
Set li = lvwList.ListItems.Add(, , "ZZZ")
li.SubItems(1) = FormatCurrency(125.55)
End Sub
Private Sub lvwList_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
If ColumnHeader.Index = 1 Then
lvwList.Sorted = True
sortList (ColumnHeader.Index)
Else
lvwList.Sorted = False
sortNumList
End If
End Sub
Private Sub sortNumList()
Dim i As Integer 'index
Dim j As Integer 'index
Dim li As ListItem 'list item
Dim intMin As Double 'minimum value
Dim intMax As Double 'maximum value
Dim intRemovedRow As Integer 'row number to be removed
Dim intCount As Integer 'the number of row listed
intCount = lvwList.ListItems.Count
If isAsc = False Then
For i = 1 To lvwList.ListItems.Count
'Set dammy minimum value
intMin = 100000
For j = 1 To intCount
'Check if the item is minimum
If lvwList.ListItems(j).SubItems(1) < intMin Then
intMin = lvwList.ListItems(j).SubItems(1)
intRemovedRow = j
End If
Next
isAsc = True
'Add new list item
Set li = lvwList.ListItems.Add(, , lvwList.ListItems(intRemovedRow))
li.SubItems(1) = lvwList.ListItems(intRemovedRow).SubItems(1)
'Remove old list item
lvwList.ListItems.Remove (intRemovedRow)
intCount = intCount - 1
Next
Else
For i = 1 To lvwList.ListItems.Count
'Set dammy maximum value
intMax = 0
For j = 1 To intCount
'Check if the item is minimum
If lvwList.ListItems(j).SubItems(1) > intMax Then
intMax = lvwList.ListItems(j).SubItems(1)
intRemovedRow = j
End If
Next
isAsc = False
'Add new list item
Set li = lvwList.ListItems.Add(, , lvwList.ListItems(intRemovedRow))
li.SubItems(1) = lvwList.ListItems(intRemovedRow).SubItems(1)
'Remove old list item
lvwList.ListItems.Remove (intRemovedRow)
intCount = intCount - 1
Next
End If
End Sub
Private Sub sortList(ColumnHeaderIndex As Integer)
If lvwList.SortKey = ColumnHeaderIndex - 1 Then
If lvwList.SortOrder = lvwAscending Then
lvwList.SortOrder = lvwDescending
Else
lvwList.SortOrder = lvwAscending
End If
Else
lvwList.SortKey = ColumnHeaderIndex - 1
lvwList.SortOrder = lvwAscending
End If
End Sub
ちょっとコードがながいんで、
勝手に変えますが、たとえば
List1というListBoxが存在するのが前提です。
(Form1.frm)
Option Explicit
Dim isAsc As Boolean
Private sub AddData()
if isAsc=False then
List1.Additem "a"
Else
List1.Additem "b"
End if
end sub
private sub command1_click()
call AddData()
end sub
というプログラムのがあったとします。
これを分割するとしたら
(Form1.frm)
Option Explicit
Dim isAsc As Boolean
private sub command1_click()
call AddData(List1,isAsc) '引数が追加される
end sub
(Module1.bas)
Public Function AddData(ByRef ocxList As Listbox,isAsc As Boolean)
'外から呼べるようにPublic宣言である
'引数としてオブジェクトと、ここで必要な変数を宣言
if isAsc=False then
ocxList.Additem "a"
Else
ocxList.Additem "b"
End if
end Function
//////////////////////////
こんなかんじです。
まず、lvwListがなんなのかわかりませんが、
そのコントロールの型に合う引数、
外で宣言されているのに中で使っている変数(isAscがそうですね)を
Public Function SortNum(ByRef ocxList As ????, ByRef isAsc As Boolean)
というように宣言してやります(????には、正しい型を入れてください。
As Controlとかでもいけますけど、しっかり指定したほうが良いでしょう。)
あとは、SortNum内の lvwListをocxListと置換してあげれば
いけると思います。
基本的には引数としてコントロールを、参照渡しするだけです。
大変ありがとうございました。とてもうまくいきました。
結構簡単なことだったんですね。
これで、これからのプログラムを整理しやすくなりました。
> 基本的には引数としてコントロールを、参照渡しするだけです。
私の場合は、このような要件では、ocxList、isAscのいずれも
参照渡し(ByRef)にはせず、値渡し(ByVal)を使う事が
多かったりします。(^-^A
(ByRefは、戻りを返す時ぐらいしか利用しないようにしているので…)
まぁ、コーディング規則は人それぞれ違うでしょうし、
今回のコードではどちらでも同じような結果になりますから、
参照渡しのままでも、動作的には問題無いですけれどね。
http://support.microsoft.com/?kbid=161308
> まず、lvwListがなんなのかわかりませんが、
lvwという接頭辞は、ListViewコントロールに使われる事が多いですね。
http://www.microsoft.com/japan/developer/library/VBCon98/vbconobjectnamingconventions.htm
魔界の仮面弁士さん、追加説明ありがとうございます。
まだByValとByRefの使い分けが完全には把握しきれていませんが、
できるだけ、それ相応の使い方をしていけるように心がけるようにしますね。
>ocxList、isAscのいずれも参照渡し(ByRef)にはせず、
>値渡し(ByVal)を使う事が多かったりします。(^-^A
isAscに関しては、関数内で代入を行っていたので参照渡しにしたんですよ
で、まぁForm中のグローバル変数だったので、返しておいたわけです
コントロールって値渡しでも操作できるんですねぇ。
ハンドルもコピーされるから当然といえば当然か・・・
私の場合も戻りを返す・・・というか「値の変更を適用させたい時」
という基準でやっているのと、
コントロールのような大き目のものを渡すときは
値渡しではメモリを多く食いそうという勝手な解釈で
(Cのポインタのような気持ちで)
やってたもので
と、いうか、規定値がByRefというのを忘れてました(笑)
なので、私のリストボックスでのサンプルにおいて、
isAscは気持ちだけ値渡しです(笑)
# なんだか、重箱の隅をつついてるようで申し訳無いですが、
# Functionの戻り値の型指定が抜けているのも、気になっていたり。。。
> isAscに関しては、関数内で代入を行っていたので参照渡しにしたんですよ
あぁ、なるほど。そういうわけですか。
それならば、ByRefでないと駄目ですね。
> isAscは気持ちだけ値渡しです(笑)
ん? ocxListではなく?(^^;)
> 値渡しではメモリを多く食いそうという勝手な解釈で
少し難しい話になりますが、メモリ使用量や処理手順という点から言えば、
ByRefの方が「重い」事もありますし、逆に「軽く」なる場合もありえます。
http://www.microsoft.com/japan/developer/library/VBCon98/vbconinprocessoutofprocesscodecomponents.htm
> isAscは気持ちだけ値渡しです(笑)
私の(最初の)例ではisAscは値変更不要なので、指定無しの(気持ちだけ)値渡しということです。
ocxListは、きっとそっちの方がいいと信じていたので、ByRefです(笑)
># Functionの戻り値の型指定が抜けているのも、気になっていたり。。。
たしかにそうですね。
戻り値返さないなら、手続きにしたほうがいいですし。
私も以前、人のコードを見たとき、同じ感想を持ちました・・・それなのに・・・ごにょごにょ(笑)
>ByRef を指定するのは、メソッドで、クライアントのオブジェクト参照がほかのオブジェクトへの参照に置き換わる場合のみです。
なるほどー
メソッド内で違うものにSetしなおすならByRefの方がいいということでしょうか。
というか内部的にByRefは単純なアドレス参照ではなさそうですね。
書き換えるたびにゴッソリコピーみたいな感じなんでしょうか
面白そうなので、今度もうちょっと調べてみようっと。
ツイート | ![]() |