文字列型の列挙体?
文字列型の列挙体?
かつて、
こんなことを試みたことがあった。
しかし、PredeclaredId
をTrue
にしたクラスモジュールを用いていたために、必ずクラス名を記述しなくてはいけなかった。
これはイマイチである。
XlLineStyle
列挙体を用いるときに、必ずXlLineStyle.xlContinuous
と書かねばならんようなものだからである。
チャクラ開く
ちょっと待てよ……。
クラスモジュールを使うから、クラス名記述の強制という問題が起こるのだ。……ということは、
標準モジュール使えばよくね?
ええ、おチャクラ開きましたとも。
標準モジュールのPropertyを使う
標準モジュールを挿入して、オブジェクト名をWaruguchi
にする。
で、次のコードを記述。
標準モジュール Waruguchi
Option Explicit Public Property Get wgAho() As String wgAho = "アホ" End Property Public Property Get wgBoke() As String wgBoke = "ボケ" End Property Public Property Get wgKasu() As String wgKasu = "カス" End Property Public Property Get wgSuttokoDokkoi() As String wgSuttokoDokkoi = "スットコドッコイ" End Property
列挙体の要素っぽい名前にして、全部Property Get
にしたったw
使ってみる
別の標準モジュールで利用しようとしてみる。
おお! いい感じではないか!
出来上がったのが次のコード。
リスト1 標準モジュール
Private Sub test() Call MsgBox(wgAho) End Sub
これだけ。
こいつを実行すると、
うむ。すばらしい。
ちょっと待て!
なるほど、標準モジュールの場合、名前かぶりさえなければ、親モジュールの記載がなくてもメソッドやプロパティを呼ぶことができる。だから、このようなことができた。
しかし!
列挙体のメリットは、一族をまとめるだけに非ず。引数や返り値の型に指定できるところにあるのだ。
標準モジュールは「型」ではなかった……orz
おわりに
……というわけで、派手に頓挫。
まあ、たとえば、Waruguchi
モジュールのコードを
Option Explicit Public Enum WgWaruguchi wgAho = 1 wgBoke wgKasu wgSuttokoDokkoi End Enum Public Property Get Waruguchies( _ ByVal kindOfWaruguchi As WgWaruguchi) As String Dim ret As String ret = "ち~んw" Select Case kindOfWaruguchi Case wgAho: ret = "アホ" Case wgBoke: ret = "ボケ" Case wgKasu: ret = "カス" Case wgSuttokoDokkoi: ret = "スットコドッコイ" End Select Waruguchies = ret End Property
にしておいたら、
Call MsgBox(Waruguchies(wgSuttokoDokkoi))
みたいにして呼べるけど、これもあんまりキレイじゃないしね。
……というわけで、派手に頓挫したのでした。ニンニン……。
UTF-8のテキストファイルを操作するクラス
UTF-8のテキストファイルを操作するクラス
作った。
何のために?
foobar2000のプレイリストファイルのドライブレター部分を一括して書き換えるために。
決して仕事のためではない。
だから、全然「働き方改革」とは関係ない。許せ。
UTF8TextFileクラスのコード
めんどくさいので、コードを一気に公開。
使ってみたい、という酔狂な方がいらっしゃいましたら、クラスモジュールを挿入して、オブジェクト名をUTF8TextFile
にした上で、次のコードをコピペしてくださいまし。長いよ。
クラスモジュール UTF8TextFile
Option Explicit '### Microsoft Active X Data Objects Library X.Xを参照設定 ###' '### Microsoft Scripting Runtimeを参照設定 ###' 'Module Level Variables' Private adoObj As New ADODB.Stream Private fsObj As New FileSystemObject 'Constants' Private Const ERR_NUMBER_BASE As Long = 45000 Private Enum ErrorCode ecIndexOutOfBound = 1 ecFileNotExists ecUnknown = 10 End Enum 'Field Variables' Private lines_() As String Private fullName_ As String 'Constructor' Private Sub Class_Initialize() '行番号に合わせるため、配列は1始まり' ReDim lines_(1 To 1) lines_(1) = "" End Sub 'Properties' Public Property Let FullName(ByVal argValue As String) Const ERR_SRC As String = _ "UTF8TextFile Class, Property Let FullName" If Not fsObj.FileExists(argValue) Then _ Call raiseError(ecFileNotExists, ERR_SRC) fullName_ = argValue End Property Public Property Get FullName() As String FullName = fullName_ End Property Public Property Get Path() As String Const ERR_SRC As String = _ "UTF8TextFile Class, Property Get Path" Dim ret As String ret = "" If Not fsObj.FileExists(fullName_) Then GoTo Finalizer Dim arr() As String arr = Split(fullName_, "\") '" Dim i As Long For i = LBound(arr) To UBound(arr) - 1 ret = ret & arr(i) & "\" '" Next ret = Left(ret, Len(ret) - 1) Finalizer: Path = ret End Property Public Property Let Lines(ByVal lineNum As Long, _ ByVal lineText As String) Const ERR_SRC As String = _ "UTF8TextFile Class, Property Get Lines" '引数チェック' If lineNum < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If lineNum > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) 'ファイル存否確認' If Not fsObj.FileExists(fullName_) Then _ Call raiseError(ecFileNotExists, ERR_SRC) '行の書き換え' lines_(lineNum) = lineText 'ファイルに書き込む' Call setLines(fullName_) End Property Public Property Get Lines(ByVal lineNum As Long) As String Const ERR_SRC As String = _ "UTF8TextFile Class, Property Get Lines" Dim ret As String ret = "" '引数チェック' If lineNum < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If lineNum > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) ret = lines_(lineNum) Finalizer: Lines = ret Exit Property ErrorHandler: Call raiseError(ecUnknown, ERR_SRC) End Property Public Property Get LinesCount() As Long Const ERR_SRC As String = _ "UTF8TextFile Class, Property Get LinesCount" On Error GoTo ErrorHandler LinesCount = UBound(lines_) Exit Property ErrorHandler: Call raiseError(ecUnknown, ERR_SRC) End Property 'Methods' 'テキストファイルの各行のデータを配列にセット' Public Sub getLines(Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, getLines Method" If targetFilePath <> "" Then fullName_ = targetFilePath If Not fsObj.FileExists(fullName_) Then _ Call raiseError(ecFileNotExists, ERR_SRC) On Error GoTo ErrorHandler With adoObj .Charset = "UTF-8" Call .Open Call .LoadFromFile(fullName_) Dim n As Long n = 1 Do Until .EOS ReDim Preserve lines_(1 To n) lines_(n) = .ReadText(adReadLine) n = n + 1 Loop Call .Close End With Exit Sub ErrorHandler: Call adoObj.Close Call raiseError(ecUnknown, ERR_SRC) End Sub '配列に格納したデータをUTF-8テキストファイルに書き込んで保存' Private Sub setLines(Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, setLines Method" On Error GoTo ErrorHandler If targetFilePath <> "" Then fullName_ = targetFilePath With adoObj .Charset = "UTF-8" Call .Open Dim i As Long For i = LBound(lines_) To UBound(lines_) Call .WriteText(lines_(i), adWriteLine) Next Call .SaveToFile(fullName_, adSaveCreateOverWrite) Call .Close End With Exit Sub ErrorHandler: Call adoObj.Close Call raiseError(ecUnknown, ERR_SRC) End Sub '行を追加' Public Sub appendLine(ByVal targetText As String, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, appendLine Method" If targetFilePath <> "" Then fullName_ = targetFilePath Dim n As Long n = UBound(lines_) + 1 ReDim Preserve lines_(1 To n) lines_(n) = targetText 'ファイルに書き込む' Call setLines(fullName_) End Sub 'テキストを追加' Public Sub appendText(ByVal targetText As String, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, appendText Method" If targetFilePath <> "" Then fullName_ = targetFilePath Dim n As Long n = UBound(lines_) lines_(n) = lines_(n) & targetText 'ファイルに書き込む' Call setLines(fullName_) End Sub '行を書き換え' Public Sub replaceLine(ByVal targetLine As Long, _ ByVal replaceText As String, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, replaceLine Method" '存在しない行ならエラー' If targetLine < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If targetLine > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) 'ファイル名が指定されていたらセット' If targetFilePath <> "" Then fullName_ = targetFilePath '行の書き換え' lines_(targetLine) = replaceText 'ファイルに書き込む' Call setLines(fullName_) End Sub '行の挿入' Public Sub insertLine(ByVal targetLine As Long, _ ByVal targetText As String, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, insertLine Method" '存在しない行ならエラー' If targetLine < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If targetLine > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) 'ファイル名が指定されていたらセット' If targetFilePath <> "" Then fullName_ = targetFilePath '行の挿入' '配列の拡張' Dim n As Long n = UBound(lines_) + 1 ReDim Preserve lines_(1 To n) '配列の要素を挿入地点まで一つづつ後ろへずらす' Dim i As Long For i = UBound(lines_) To targetLine + 1 Step -1 lines_(i) = lines_(i - 1) Next '挿入する地点に新しいテキストを追加' lines_(targetLine) = targetText 'ファイルに書き込む' Call setLines(fullName_) End Sub '行の削除' Public Sub deleteLine(ByVal targetLine As Long, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, deleteLine Method" '存在しない行ならエラー' If targetLine < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If targetLine > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) 'ファイル名が指定されていたらセット' If targetFilePath <> "" Then fullName_ = targetFilePath '行の削除' '配列の要素を一つづつ詰めていく' Dim i As Long Dim n As Long n = UBound(lines_) - 1 For i = targetLine To n lines_(i) = lines_(i + 1) Next '配列の縮小' ReDim Preserve lines_(1 To n) 'ファイルに書き込む' Call setLines(fullName_) End Sub '行のテキストの置換' Public Sub replaceText(ByVal targetLine As Long, _ ByVal FindString As String, _ ByVal ReplaceString As String, _ Optional ByVal targetFilePath As String) Const ERR_SRC As String = _ "UTF8TextFile Class, replaceText Method" '存在しない行ならエラー' If targetLine < LBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) If targetLine > UBound(lines_) Then _ Call raiseError(ecIndexOutOfBound, ERR_SRC) 'ファイル名が指定されていたらセット' If targetFilePath <> "" Then fullName_ = targetFilePath '行のテキストの置換' lines_(targetLine) = Replace(lines_(targetLine), _ FindString, _ ReplaceString) 'ファイルに書き込む' Call setLines(fullName_) End Sub Public Sub replaceLines(ByVal findStr As String, _ ByVal replaceStr As String, _ Optional ByVal targetFilePath As String) 'ファイル名が指定されていたらセット' If targetFilePath <> "" Then fullName_ = targetFilePath '全ての行について置換を実行' Dim i As Long For i = LBound(lines_) To UBound(lines_) lines_(i) = Replace(lines_(i), findStr, replaceStr) Next 'ファイルに書き込む' Call setLines(fullName_) End Sub 'エラー発生用' Private Sub raiseError(ByVal errCode As ErrorCode, _ ByVal errSource As String) Dim msg As String Select Case errCode Case ecIndexOutOfBound msg = "Index is out of bound..." Case ecFileNotExists msg = "File is not found..." Case ecUnknown msg = "Some error has occurred..." End Select msg = msg & vbCrLf & errSource Call Err.Raise(Number:=ERR_NUMBER_BASE + errCode, _ Source:=errSource, _ Description:=msg) End Sub
長いなーーー。
まあ、エラー対応とかも作り込んでしまったから、しょうがない。許してちょんまげ。
メソッドとかプロパティを列挙するのはめんどくさいので、
オブジェクト ブラウザーの画像でどうぞ。
何か、プロが作ったクラスっぽくないっすか?
使ってみる
さて、本来の目的は、そう、
Foobar2000のプレイリストファイルのドライブレター書き換え
であった。
初期状態が
コチラ。楽曲ファイルのあるドライブがO
ドライブになっている。
これを、F
ドライブに変えてみせようホトトギス。
リスト1 標準モジュール
Private Sub testUTF8TextFileClass() Const SAMPLE_FILE As String = _ "X:\個人用\はてなブログ用\PlayListEditor\NowPlaying" Dim txtFile As UTF8TextFile '……(1)' Set txtFile = New UTF8TextFile Call txtFile.getLines(SAMPLE_FILE & ".m3u8") '……(2)' Call txtFile.replaceLines("O:\Music", _ "F:\Music", _ SAMPLE_FILE & "_.m3u8") '……(3)' End Sub
(1)の
Dim txtFile As UTF8TextFile Set txtFile = New UTF8TextFile
で、わがUTF8TextFile
クラスのインスタンスを作る。
(2)の
Call txtFile.getLines(SAMPLE_FILE & ".m3u8")
で、getLines
メソッドを実行し、PlayListEditor
フォルダにあるNowPlaying.m3u8
というファイルを読み込む。
あとは、(3)の
Call txtFile.replaceLines("O:\Music", _ "F:\Music", _ SAMPLE_FILE & "_.m3u8")
でreplaceLines
メソッドを実行。第1引数に"O:\Music"
、第2引数に"F:\Music"
を渡しているので、ファイル内のO
ドライブの記述をF
ドライブに改めることになる。
また、第3引数で渡すファイルパスでは、拡張子の前に「_
」(アンダースコア)を追加しているので、置換後、別のファイル名(すなわち、NowPlaying_.m3u8
)で保存されることになる。
実行結果
リスト1を実行すると、
新しいファイルNowPlaying_.m3u8
が出来ていて、中身は
このとおり。文字化けもなく、無事に置換できている。
おわりに
さて、このUTF8TextFile
クラス、他に使いどころはあるかのう……?
Shift_JIS と UTF-8 に悩まされた話
文字コードェ……
Foobar2000のプレイリストファイルは、拡張子が「.m3u8
」というけったいなもの。こいつをエディタで開くと、
こんなふうに、登録した楽曲データのフルパスを書き込んでいるだけだった。
ただ、うっとうしいのがドライブ名がジカ書きなところ。
これでは、ドライブレターが変更になったら読み込めなくなってしまう。
で、かつて作成したTextFile
クラスを利用して編集してはどうか、と考えた。
ちなみに、TextFile
クラスのコードはコチラ。
TextFileクラスを用いてプレイリストファイルを編集する
「TextFile
クラスを用いて」と言っても、TextFile
クラス自体はFileSystemObject
クラスをラップしただけのクラスなので、「FileSystemObject
を用いてプレイリストファイルを編集する」と言った方が正しいんですけどね。
リスト1 標準モジュール
Private Sub testTextFileClass() Const SAMPLE_FILE As String = _ "X:\個人用\はてなブログ用\PlayListEditor\NowPlaying" Dim txtFile As TextFile Set txtFile = New TextFile Call txtFile.init(SAMPLE_FILE & ".m3u8") With txtFile Dim i As Long For i = 1 To .LineCount Call .replaceLine(i, Replace(.Line(i), "O:\Music", "F:\Music")) Next End With End Sub
改めて見直すと、TextFile
クラスのメソッド名、プロパティ名の付け方がイマイチやなあ……。
ま、それはさておき、自作TextFile
クラスのreplaceLine
メソッドに、各行のテキストを渡し、組み込みのReplace
関数で「O:\Music
」を「F:\Music
」に置換してファイルに書き込み直している。
んで、こいつをNowPlaying.m3u8
というプレイリストファイルに対して実行した。
実行後
ぐえっ!!!!!!!!
何と、.m3u8
ファイルよ、キサーマはUTF-8
だったのか……orz
おわりに
再生情報を表すXMLがフツーにFileSystemObject
で編集できたので完全に油断しておりました。
なお、現在は既にUTF-8
のテキストファイルを編集するためのクラス(UTF8TextFile
クラス)を作成済みなので、この問題は解決済みです。
UTF8TextFile
クラスについては、またコチラでご紹介する機会もあろうかと……。
PC初心者なので、ここへ来て初めて文字コードに悩まされましたw
UTF8TextFileクラスについて
コチラをどうぞ。
あえて組み込みオブジェクトを低機能化させる
あえて組み込みオブジェクトを低機能化させる
組み込みオブジェクトは優秀である。
プロが作ったものなのだから、当り前である。
しかし、素人にとっては「優秀すぎて良さがわからない」こともしばしば。
そこで、初心者のうちは、
あえて低機能化させたクラス/メソッドを作る
ことをオススメする。
FileDialogオブジェクトの場合
たとえば、Application.FileDialog
オブジェクトというものがある。
ファイルやフォルダを選択するとき、「名前を付けて保存」とかするときに出てくるあのウインドウだ。
今でこそApplication.FileDialog
オブジェクトの使い方もそこそこわかるので、便利だなーと思うこともできるのだが、初心者の頃はとにかく
な、何てややこしいんだ……
などと思っていたものである。
詳しいことはコチラに譲るとして、とにかくやれメソッドだ、プロパティだ、と、初心者にはわけがわからないはずである。
使いたい機能を絞り込む
そこで、たとえば、
とにかく、ファイル選択ダイアログを表示して、ユーザーにファイルを選ばせる。んで、選んだファイルのフルパスが取得できたらいい。
と、目標を絞るのである。
ユーザーが選んだファイルのフルパスを取得するメソッド
使用者(コードを書く人。つまり自分)が設定するのは、せいぜい〈デフォルトのフォルダパス〉と〈ダイアログのタイトル〉ぐらいにしておくと楽だ。あとはメソッドの中に封印してしまえば良い。
そのような考え方で書いたメソッドが次のもの。
リスト1 標準モジュール
Option Explicit Private fsObj As New FileSystemObject Public Function getSelectedFilePath( _ Optional ByVal defaultFolderPath As String, _ Optional ByVal Title As String) As String Const DEFAULT_TITLE As String = "ファイルを選べやぼけーーー" '第1引数省略または存在しないフォルダパスなら既定のフォルダにする' If defaultFolderPath = "" Or _ Not fsObj.FolderExists(defaultFolderPath) Then defaultFolderPath = ThisWorkbook.Path & "\" '" Else If Right(defaultFolderPath, 1) <> "\" Then _ defaultFolderPath = defaultFolderPath & "\" End If '第2引数省略なら既定の値に' '(引数リストに書くと長くなるのでプロシージャ内に記述)' If Title = "" Then Title = DEFAULT_TITLE Dim ret As String ret = "" Dim fileDialog_ As FileDialog Set fileDialog_ = Application.FileDialog( _ msoFileDialogFilePicker) Dim hasSelected As Boolean hasSelected = False With fileDialog_ .Title = Title .InitialFileName = defaultFolderPath .AllowMultiSelect = False hasSelected = .Show If hasSelected Then ret = .SelectedItems(1) End With getSelectedFilePath = ret End Function
引数が省略されたときにとりあえずマクロを書いたブックのあるフォルダを指定するとか、複数ファイルの選択を不許可にするとか、ユーザーが何も選ばなかったときの対応とか、そういううっとうしい設定はメソッド内に吸収してしまっている。
したがって、このgetSelectedFilePath
メソッドの使用者(つまり自分)は、そういうことを何にも考えずに、ただデフォルトのフォルダパスとダイアログのタイトルだけ渡してやれば(何ならそれすら渡さなくても)、ユーザーが選んだファイルのフルパスを取得することができるのだ。
その後どうするか
上で紹介したgetSelectedFilePath
メソッドの場合、本来非常に多くの機能を備えているApplication.FileDialog
オブジェクトをメソッドの中に封印し、そのうちのごく一部の機能だけを使用者(つまり自分)に公開するというやり方をとった。
こうすることで、単に〈ユーザーにファイルを選ばせ、そのファイルのフルパスを取得したい〉というだけなら、もはやApplication.FileDialog
の使い方など一切意識する必要がなくなる。
しかし、少し考えたらわかるように、これは単なる〈逃げ〉に過ぎない。
では、どうするか。
ときどき見直す
これである。
実にあほらしいことのように見えるかも知れないが、これが大切である。
今回の場合なら、getSelectedFilePath
メソッドのコードを読み返して処理を追いかけてみるのである。
かならずどこかで、
おおお! FileDialogオブジェクトとはそういうものだったのか!
となるときが来る。必ず来る。絶対に来る。
そうなると強い。
今度は、さらに痒いところに手が届くようにアレンジしたくなる。
これを繰り返すうちに、「あれ? Application.FolderDialog
オブジェクトを直接使った方が早くね?」というときが来る。これは、まだ私は経験していないので断言しにくいが、きっと来る。
そのときが、Application.FolderDialog
オブジェクトを極めたときなのだと思う。
おわりに
……というわけで、がんばりましょう。
最初は借り物のコードでいいんです。でも、ときどき見返して理解するようにしようぜ!
PropertyとSetter/Getter
PropertyとSetter/Getter
「Propertyプロシージャって、よく考えたら何なんやろ???」と思った。
現に、JavaなんかにはPropertyという仕組みはない。
比較
次のように、ParentHoge
クラス、ChildHoge
というクラスを作った。
ParentHoge
クラスには、ChildHoge
オブジェクトを返すChild
プロパティがあり、ChildHoge
クラスにはName
プロパティがある、という設計。
クラスモジュール ParentHoge
Option Explicit Private child_ As ChildHoge 'Properties' Public Property Set Child(ByVal argObj As ChildHoge) Set child_ = argObj End Property Public Property Get Child() As ChildHoge Set Child = child_ End Property 'Setter/Getter' Public Sub setChild(ByVal argObj As ChildHoge) Set child_ = argObj End Sub Public Function getChild() As ChildHoge Set getChild = child_ End Function
見ての通り、Child
プロパティのProperty Set
とProperty Get
を持たせる一方、同じ機能を提供するSetter/Getterメソッドも実装している。
クラスモジュール ChildHoge
Option Explicit Private name_ As String 'Properties' Public Property Let Name(ByVal argValue As String) name_ = argValue End Property Public Property Get Name() As String Name = name_ End Property 'Setter/Getter' Public Sub setName(ByVal argValue As String) name_ = argValue End Sub Public Function getName() As String getName = name_ End Function
こちらもName
プロパティのProperty Let
とProperty Get
を持たせる一方、同じ機能を提供するSetter/Getterメソッドを実装している。
使ってみる
ParentHoge
のインスタンスから、配下のChild
オブジェクトのName
にアクセスする。
標準モジュール
Private Sub test02() '(1) Propertyを使用' Dim p1 As ParentHoge Set p1 = New ParentHoge Set p1.Child = New ChildHoge p1.Child.Name = "ち~んw" Debug.Print p1.Child.Name '(2) Setter/Getterを使用' Dim p2 As ParentHoge Set p2 = New ParentHoge Call p2.setChild(New ChildHoge) Call p2.getChild.setName("( ´_ゝ`)フーン") Debug.Print p2.getChild.getName End Sub
(1)、(2)ともに、やっている内容は同じ。よって、実行すると、イミディエイト ウインドウには
このように表示される。
おわりに
少なくとも、利用側のコードの可読性という点では、圧倒的にPropertyを使うやり方が上回っていると思う。
何となくSetter/Getterの方がカッコよく思えてしまうのですがw
削除しても復活するワークシートw
削除しても復活するシート
先に断っておきますが、アイディアは、ノンプロ研で出会った id:FukuCyndiP さんのものです。私はただパクっただけw
ただ、某ウ〇ブカツのアホと違って、自己申告するところが人格者でしょ?
閑話休題。
このマクロの挙動
元々のプロジェクト エクスプローラーは
この状態。
んで、三つあるシートのうち、Sh01Aho
(シート名はaho
)、Sh03Kasu
(シート名はkasu
)の二つは、削除しても復活するようにした。
で、それぞれのシートの削除を試みた様子がコチラ。
んで、上の動画の一連の動作をした後のプロジェクト エクスプローラーは
この状態。
おわりに
面白いでしょ?
コードはまたヒマなときにうpしますw
インターフェースを実装したインターフェースを実装する
インターフェースを実装したインターフェースを実装する
何言ってんだか、わかんねえだろ? おれもよくわかっていねえんだ。
インターフェースを実装したインターフェース
まず、一つインターフェースを作る。
リスト1 クラスモジュール IA
Option Explicit Public Sub aa() End Sub
実験用だから、全てが投げやり。IA
というインターフェースで、aa
というメソッドを指定している。
で、次に、このインターフェースIA
を実装したインターフェースを作る。
リスト2 クラスモジュール IB
Option Explicit Implements IA Public Sub IA_aa() End Sub Public Sub bb() End Sub
インターフェースIA
を実装したのだから、IA_aa
メソッドは必須。さらに、bb
メソッドを指定した。
これでインターフェースの準備は完了。
インターフェースを実装したインターフェースを実装したクラスを作る
では、上で作成したインターフェースIA
を実装したインターフェースIB
を実装したクラスを作る。
リスト3 クラスモジュール Hoge
Option Explicit Implements IB Public Sub IB_IA_aa() Call MsgBox("ち~んw") End Sub Public Sub IB_bb() Call MsgBox("(゚∀゚)アヒャ") End Sub
実装したインターフェースはIB
。ゆえに、インターフェースIB
が指定している二つのメソッドIA_aa
とbb
を装備すれば良いはずだ。
インターフェース名をメソッド名の頭にスネーク記法で付けるのがルールなので、IB_IA_aa
、IB_bb
とすれば、まさに万全。鉄壁の布陣。八門金鎖の陣を敷いた曹仁も驚きだろう。
Hogeクラスを使ってみる
標準モジュールに次のコードを書いてHoge
クラスを使ってみる。
リスト4 標準モジュール
Private Sub test01() Dim b As IB Set b = New Hoge Call b.IA_aa Call b.bb End Sub
コーディング中には、
こんなふうにヒントも出る。
いやが上にも胸が高鳴るではないか!!!!!!!!!!!!!!!!!
実行
震える手で実行ボタンをクリック……
あえなくコンパイル エラー……。
(´・ω・`)ショボーン
おわりに
何がいけないのでしょう……。