[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]
『クラスモジュールの勉強』(稲葉)
↑のスレッドで便利そうだなと思い、クラスの勉強も兼ねて、 Mookさんのコードを手本にポップアップメニュー表示用のクラスを書いてみました。
で、プロパティも一つもなくこれクラスにする必要ないんじゃない?と何となく思えてきて・・・
そこで、クラスはどのような処理をするときに向いているのか教えていただけませんか?
自分で分かる範囲で、抽象的ですがこんなことが便利なんじゃないの?と思っています。 1)インスタンスを複数持つことが出来る 値を入れる他、入れた値を計算し、結果を持つことが出来るなどコレクション等のオブジェクトを拡張したよう な独自のオブジェクトが作れる
2)ループの処理をまとめられるので視認性がよくなる?
しかし具体的にどういうときに使ったらいいのか分かりません。
'標準モジュール Sub test() Dim Pmenu As clsPopup Set Pmenu = New clsPopup With Pmenu .AddItem Title:="選択A", 子ID:=0, Action:="A", FaceID:=0 .AddItem Title:="選択B", 子ID:=0, Action:="B", FaceID:=0 .AddItem Title:="選択C", 子ID:=0, Action:="C", FaceID:=0 .AddPop Title:="選択D", 子ID:="D" .AddPop Title:="選択E", 子ID:="E" .AddItem Title:="選択D-1", 子ID:="D", Action:="D1", FaceID:=0 .AddItem Title:="選択E-1", 子ID:="E", Action:="E", FaceID:=0 .AddItem Title:="選択D-2", 子ID:="D", Action:="D2", FaceID:=0 .Rgst End With End Sub Sub Separator(ByVal GetData) Select Case GetData Case "A" ActiveCell.Value = 10 Case "B" ActiveCell.Value = 100 Case "C" ActiveCell.Value = 1000 End Select End Sub
'シートモジュール Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean) If Target.CountLarge <> 1 Then Exit Sub test Cancel = True End Sub
'クラスモジュール 'clsPopup Private Popup As Object Private 子 As Collection Private Sub Class_Initialize() Set Popup = CommandBars.Add(Position:=msoBarPopup) Set 子 = New Collection End Sub Public Sub Rgst() Popup.ShowPopup Popup.Delete End Sub Public Sub AddItem(ByVal Title As String, ByVal 子ID As String, ByVal Action As String, Optional ByVal FaceID As Long = 0) Dim tmpPop As Object If FaceID = 0 Then FaceID = 483 If 子ID = "0" Then Set tmpPop = Popup Else On Error GoTo 0 Set tmpPop = 子(子ID) If Err > 0 Then MsgBox "存在しないIDです": Exit Sub End If With tmpPop With .Controls.Add .Caption = Title .OnAction = "'Separator """ & Action & """ '" .FaceID = FaceID End With End With End Sub Public Sub AddPop(ByVal Title As String, ByVal 子ID As String) With Popup On Error Resume Next 子.Add .Controls.Add(Type:=msoControlPopup), CStr(子ID) If Err > 1 Then MsgBox "既に子IDが追加されています。": Exit Sub On Error GoTo 0 子(子ID).Caption = Title End With End Sub
で実際使って行きたいと思いますので、コードもこうした方がいいんじゃない?など 色々な書き方を教えていただけたらありがたいです。
< 使用 Excel:Excel2007、使用 OS:WindowsXP >
とりあえず、雑感まで。
面白そうですけれど、メニューの構築の部分をどう考えるかでしょうか。 このあたりは ichinose さんが得意そうですね。
知らないだけかもしれませんが、メニューの途中に挿入するのが出来れば ある程度 Class 化のメリットが出来そうな気がします。 イメージとしては XML のツリー操作のようなイメージでしょうか。
あるノード以下の追加、削除、変更、コピー などがあると便利そうです。
(Mook) 2014/09/26(金) 21:39
Additemではコントロールを追加せず、配列に引数とIdを振って、 ならび順は別の変数に設定し、Rgstで一気にコントロール追加してしまえば 並び順の問題解決できそうです!
そうすれば、Rgst時に引数でId渡して、そのIdのコントロールだけ実装なども出来そうですね
XMLのツリー操作は、、、分からないので勉強しておきます!
(稲葉) 2014/09/26(金) 22:00
>プロパティも一つもなくこれクラスにする必要ないんじゃない?と何となく思えてきて・・・ >そこで、クラスはどのような処理をするときに向いているのか教えていただけませんか?
クラスモジュールって、オブジェクトの設計書で、そのオブジェクトとは、 データとアルゴリズムを隠蔽化したもの ですよね?
このクラスとかオブジェクト指向などという言葉を耳にする以前から、このような構造のプログラムを 作るようにしなさい という指導を受けていました。
モジュールを評価する指標に 強度と結合度 というものがあります。 強度を強く、結合度が弱くなるようにモジュールを作りなさいという設計法があります。 (マイヤーズの複合設計法)。この設計法で、
検索してみると、強度の例で情報的強度というモジュールの構造を紹介していますが、これが正にこのオブジェクトの定義 そのものの構造を指していて、強度の強いモジュールだと評価しています。
以下は、私がプログラマ一年生のときに最初に作らされた情報的強度のモジュールです。 実際には、VBAでは、ありませんが、VBAで記述すれば、このようなものだという例です。 内容は、テキストファイルの読み込みを一括管理するモジュールです。
Option Explicit Private fno As Long Function f_open(ByVal fname As String) As Long fno = FreeFile() On Error Resume Next Open fname For Input As #fno f_open = Err.Number On Error GoTo 0 End Function Function f_get(mydata As Variant) As Variant On Error Resume Next If EOF(fno) Then f_get = 1 Else Line Input #fno, mydata f_get = Err.Number End If On Error GoTo 0 End Function Sub f_close() On Error Resume Next Close #fno On Error GoTo 0 End Sub
Fnoというデータを共有する処理をこのモジュールで一括管理するようにしています。
この構造を情報的強度のモジュールと評価しています。 稲葉さんが提示押されたクラスモジュールの構造と同じですよね? データとアルゴリズムを纏めて一つのモジュールにしたもの 言い換えれば、「データとアルゴリズムを隠蔽化したもの」ですよね?
この構造になっていれば、クラスモジュールに入れとけば、便利です。 理由は、仰れているように、インスタンスを複数持つことが出来る これだけとっても、同時に複数のオブジェクトを作成したい時など、クラスにしておけば 配列を作成するだけで済みます。クラスを使わないで同じことをしようとすれば、アルゴリズムが 複雑になりますからねえ!!
ですから、現時点でプロパティがないというのは、関係ないと思いますよ
このPopupメニューについては、ユーザーフォームのテキストボックス等では、 右クリックで切り取り、コピー、貼付け というメニューが出ませんよね? これを実現させるために
こんな投稿をしたことがありました。
コードを拝見して、さすがですね、私は、大筋良いと思いますよ!!
細かいところで気になった点は・・・、
1 Rgstメソッドについて
Popup.ShowPopup Popup.Delete とありますが、何故? という印象をもちました。 せっかく愛をはぐ組んできた男女が 一夜明けたら 別れの朝(高橋真梨子)が聞こえてくるような印象が頭を駆け巡りました。 例題コードでは 100件ぐらい登録すると、表示時に一瞬ためらった後の表示のような間がありました。
ユーザーフォーム表示中に使うのとは、違ってクラスモジュールの心配は、理由が不明な変数の初期化というバグ(仕様)が発見されていることです。 コードでActivexコントロールをシートに生成した後など変数が初期化されるという現象が確認されています。
変数の初期化については、私も何度か理由が不明な事象で確認しています。 よって、あまり長い時間インスタンスを保持した状態にしないという仕様にしているのかもしれません。 私は、これに関しては、クラスモジュールをアドン化してしまう方法をとっています。 運用もそのアドインに対して参照設定はしない手法です。 この方法だと今のところ、変数の初期化の再現がありません。
いずれにせよ、ちょっとこの一回でさよなら という仕様が気になりました。
2 AddItemメソッドの オプション Action について
.OnAction = "'Separator """ & Action & """ '" このコードですが、呼び出すモジュールをSeparator と限定してしまうと このSeparatorというプロシジャーとの結合度が強くなり、汎用性が狭まりますから、 全部をパラメータ化してしまえば どうでしょうか?
細かい事ですが、ちょっとだけ気になりました。
( ichinose) 2014/09/27(土) 11:00
ichinoseさん コメントありがとうございます。 返事が遅くなり申し訳ございません。
>マイヤーズの複合設計法 こちら検索してみました。 自分は正直申しますと、文系且つメーカー職なのでしっかり勉強したことがなく、ただ 「みんなが便利になればいいなー」程度の気持ちで取り組んでいます。 ですので職業プログラマさんに申し訳ないと思いつつ質問させていただいています。
本題ですが、オブジェクト指向という括りの中の、構造化プログラミングがわかってないと、効果的な オブジェクト指向プログラムは書けない、という理解に落ち着きました。 これを理解したうえで、 >2 AddItemメソッドの オプション Action について の「結合度が強い」は、戻り値や引数が他のプロシージャ(Separator)に依存しているので、 なるべく依存しないように工夫しましょうということ、、、でいいんですかね?
>[[20100930194658]] >こんな投稿をしたことがありました。 こちらも拝見いたしました。 参照設定で「システム レジストリへのアクセスでエラーが発生しました。」 http://blog.livedoor.jp/ikasabo/archives/51594432.html で転んで、 「Microsoft Forms2.0 Object Library」が見つからず http://www.relief.jp/itnote/archives/017881.php
やっと試せるぞ! と思ったらhttp://office.microsoft.com/ja-jp/excel-help/HA010342745.aspx#BMcontrols_on_the_forms_toolbar現在参照不可
2010では結局できないみたい?・・・ 別PCの2007で試します!
>1 Rgstメソッドについて >変数の初期化については、私も何度か理由が不明な事象で確認しています。 これは初めて知りました(汗 そんなにたくさん入れるつもりではなかったので、考慮に入れる必要はなさそうです。 各々のPC環境に依存しないブックを目指しているので、ブックごとにクラス設定したいと思います。 Mookさんのご指摘と合わせて、もう一度書き直してみます。
ありがとうございました!
(稲葉) 2014/09/28(日) 00:08
このスレッドで紹介させていただいたおかげでバグが発見できました。修正しました。 ここで久しぶりに確認しなかったら、気がつかなかったかもしれません。
ただ、
>2010では結局できないみたい? 修正前でも Excel2010でも例として投稿したコード(シート上にActiveXコントロールのテキストボックス を使った例)は、正常に作動していますよ!!
これ、アドインにしているので、同時に開いている二つのブックがあった場合、また、それぞれが ActiveXコントロールのテキストボックスを使用している場合、切り取り、コピー、貼付けメニューを 表示しなければならないのですが、その箇所に不具合がありました。(修正済み)
>Sheet1にコントロールツールボックスのテキストボックスを二つ作成してください(TextBox1、TextBox2)。
が、わかりにくかったでしょうか?
これ、ActiveXコントロールのテキストボックスです。
これをご紹介したのは、アドイン化した例と もう一つ CommandbarButtonがクリックされた時の 処理が稲葉さんの事例とは違っていたので 参考・比較していただくために投稿しました。
稲葉さん事例だと、クリックした場合は、OnActionプロパティを使ってその後の処理をさせる プロシジャー名を登録していますよね?
投稿したcpypst.xlaでは、CommandbarButtonが提供しているイベントMouseUpで処理を行っています。 しかも、このcpypst.xlaは、機能的に切り取り、コピー、貼付け という機能に特化しているので、 すべてアドイン側(クラスモジュール内)で処理しています。
>マイヤーズの複合設計法 ソフトウエア関係のマニュアルって、わかりづらいですよね!! 私も書物だけでは、理解は出来なかったと思います。 その手の会社ですから、教えてくれる方がいましたからねえ
クラスモジュールを使う場合、この強度(情報的強度)と結合度を意識すれば、良いオブジェクトが作成できると思いますよ
>「結合度が強い」は、戻り値や引数が他のプロシージャ(Separator)に依存しているので、 >なるべく依存しないように工夫しましょうということ、、、でいいんですかね?
そういうことになります。汎用的なメニューなので 項目が決定した後の処理は、このオブジェクトを使用している 元のプログラムが決めればよいですよね?
>1 Rgstメソッドについて
変数の初期化を気にしていないのだとすれば、
Popup.ShowPopup Popup.Delete
せっかく Addpop Additemを使って構築したメニューを 一回の表示で削除してしまうのは、 どうしてなのでしょうか?
クラスのTerminateイベントなどで 削除するのがよいと思いますけどね!!
ということを
> せっかく愛をはぐ組んできた男女が 一夜明けたら 別れの朝(高橋真梨子)が聞こえてくるような印象が頭を駆け巡りました。
なんて記述したのですが、わかりにくかったですね、失礼しました。
色々、私にもメリットがありました。
( ichinose) 2014/09/28(日) 07:53
>>2010では結局できないみたい? >修正前でも Excel2010でも例として投稿したコード(シート上にActiveXコントロールのテキストボックス >を使った例)は、正常に作動していますよ!! 修正前はなぜか右クリックが反応しておりませんでしたが、修正後で動きました。 理屈は、すみません、もっと基本を勉強しないとすぐに理解できそうにありません。
しかし、 >稲葉さん事例だと、クリックした場合は、OnActionプロパティを使ってその後の処理をさせる >プロシジャー名を登録していますよね? >投稿したcpypst.xlaでは、CommandbarButtonが提供しているイベントMouseUpで処理を行っています。 この点については理解できました! ありがとうございます。
>ソフトウエア関係のマニュアルって、わかりづらいですよね!! 私も書物だけでは、理解は出来なかったと思います。 >その手の会社ですから、教えてくれる方がいましたからねえ >クラスモジュールを使う場合、この強度(情報的強度)と結合度を意識すれば、良いオブジェクトが作成できると思いますよ 職場内では私以外VBA触れないので、独自オブジェクトを使ったメンテナンスフリーのプログラムを残して いきたいと思います!
ご指摘いただいた別れの朝と結合度の2点について、自分なりに書き直してみました。 Mookさんから頂いた指摘については、コレクション化した情報の順序でネスト先の順序も考慮しようとして どのようにコレクションに情報を入れておくか混乱してしまったので、後日また考え直します!
ActionにStringでプロシージャ名と引数渡そうとすると、「"」ばっかりになり、視認性が悪くなってしまう ので、動的配列として渡そうと考えました。 この考え方はありですかね・・・? TextToColumnsのFieldInfoのイメージです。
'クラスモジュール 'clsPopup Private Popup As Object Private 子 As Collection Private Sub Class_Initialize() Set Popup = CommandBars.Add(Position:=msoBarPopup) Set 子 = New Collection End Sub Private Sub Class_Terminate() '//別れの朝回避 Popup.Delete End Sub Public Sub Rgst() Popup.ShowPopup End Sub
Public Sub AddItem(ByVal Title As String, ByVal 子ID As String, ByVal Action As Variant, Optional ByVal faceID As Long = 0) Dim tmpPop As Object '//Action = Array(プロシージャ名,引数,引数,引数・・・) Dim Proc As String, Arg As String, Act For Each Act In Action If Proc = "" Then Proc = "'" & Act Else Arg = Arg & IIf(Arg = "", "", ",") & Chr(34) & Act & Chr(34) End If Next Act Proc = Proc & " " & Arg & " '"
'//エラー処理 If faceID = 0 Then faceID = 483 If 子ID = "0" Then Set tmpPop = Popup Else Set tmpPop = 子(子ID) If Err > 0 Then MsgBox "存在しないIDです": Exit Sub End If
'//コンントロールの追加 With tmpPop With .Controls.Add .Caption = Title .OnAction = Proc .faceID = faceID End With End With End Sub Public Sub AddPop(ByVal Title As String, ByVal 子ID As String, Optional ByVal Nest As String = "") Dim tmpPop As Object If Nest = "" Then Set tmpPop = Popup Else On Error Resume Next Set tmpPop = 子(Nest) If Err > 1 Then MsgBox "ネストさせる子IDがありません": Exit Sub On Error GoTo 0 End If With tmpPop On Error Resume Next 子.Add .Controls.Add(Type:=msoControlPopup), CStr(子ID) If Err > 1 Then MsgBox "既に子IDが追加されています。": Exit Sub On Error GoTo 0 子(子ID).Caption = Title End With End Sub
Dim Pmenu As clsPopup '標準モジュール Sub test() If Pmenu Is Nothing Then Set Pmenu = New clsPopup With Pmenu .AddItem Title:="色塗り", 子ID:=0, Action:=Array("abc", 50), faceID:=0 .AddPop Title:="入れ子1", 子ID:="D" .AddPop Title:="入れ子2", 子ID:="E", Nest:="D" .AddItem Title:="計算", 子ID:="D", Action:=Array("aiu", 10, 20), faceID:=0 .AddItem Title:="ハロウィン", 子ID:="E", Action:=Array("XYZ", "とりっくおあとりーと"), faceID:=0 .AddItem Title:="メニュークリア", 子ID:=0, Action:=Array("メニュー刷新"), faceID:=0 .Rgst End With Else Pmenu.Rgst End If End Sub Sub メニュー刷新() Set Pmenu = Nothing End Sub Sub abc(ID As Long) ActiveCell.Interior.ColorIndex = ID End Sub Sub XYZ(ID As String) ActiveCell.Value = ID End Sub Sub aiu(a As Long, b As Long) MsgBox a + b End Sub
( 稲葉) 2014/09/28(日) 10:12
[ 一覧(最新更新順) ]
YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki.
Modified by kazu.