質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • VBA

    1906questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1637questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。

ExcelVBAのフォームで同じような処理をまとめたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 359

morutemu

score 33

ExcelVBAにてフォームを作成し、いくつかテキストボックスがあるのですが、
その値が変わったときに関数が動くようなプログラムを作ったのですが、
プログラム全体を見てみると同じような処理がただ並んでいます。
これらをまとめたいのですが、どのようにしたらよいでしょうか?

'回転数チェンジ関数_01
Private Sub RotationSpeedTextBox01_Change()
    IntermediateProc ("RotationSpeed")
End Sub

'回転数チェンジ関数_02
Private Sub RotationSpeedTextBox02_Change()
    IntermediateProc ("RotationSpeed")
End Sub

'周速チェンジ関数_01
Private Sub PeripheralVelocityTextBox01_Change()
    IntermediateProc ("PeripheralVelocity")
End Sub

'周速チェンジ関数_02
Private Sub PeripheralVelocityTextBox02_Change()
    IntermediateProc ("PeripheralVelocity")
End Sub

'R長さチェンジ関数_01
Private Sub FilletLengthTextBox01_Change()
    '中間処理
    IntermediateProc ("FilletLength")
End Sub

'R長さチェンジ関数_02
Private Sub FilletLengthTextBox02_Change()
    '中間処理
    IntermediateProc ("FilletLength")
End Sub

*追加
その他処理

'-- 関数 --
'初期化関数
Public Sub Initialization()
    WarningLabel = ""
End Sub

'計算関数
Public Sub Calculation(strVal)
    Select Case strVal
        '回転数
        Case "RotationSpeed"
            'テキストボックスが空ではない場合の処理
            If RotationSpeedTextBox01 <> "" And RotationSpeedTextBox02 <> "" Then
                '周速・ワーク直径を変数に代入
                PeripheralVelocity = RotationSpeedTextBox01
                WorkDiameter = RotationSpeedTextBox02

                '回転数(min-1)の計算
                RotationSpeed = PeripheralVelocity / (WorkDiameter * PI) * 1000

                '回転数(min-1)をテキストボックスに表示
                RotationSpeedTextBox03 = RotationSpeed
            End If

        '周速
        Case "PeripheralVelocity"
            'テキストボックスが空ではない場合の処理
            If PeripheralVelocityTextBox01 <> "" And PeripheralVelocityTextBox02 <> "" Then
                '回転数・ワーク直径を変数に代入
                PeripheralVelocity = PeripheralVelocityTextBox01
                WorkDiameter = PeripheralVelocityTextBox02

                '周速の計算
                PeripheralVelocity = PeripheralVelocity * WorkDiameter * PI / 1000

                '周速をテキストボックスに表示
                PeripheralVelocityTextBox03 = PeripheralVelocity
            End If

        'R長さ
        Case "FilletLength"
            'テキストボックスが空ではない場合の処理
            If FilletLengthTextBox01 <> "" And FilletLengthTextBox02 <> "" Then
                'R(半径)・角度を変数に代入
                R = FilletLengthTextBox01
                Angle = FilletLengthTextBox02

                '長さの計算
                Length = ((R * 2 * PI) / 360) * Angle

                '長さをテキストボックスに表示
                FilletLengthTextBox03 = Length
            End If

        '表面粗さ
        Case "SurfaceTexture"
            'テキストボックスが空ではない場合の処理
            If SurfaceTextureTextBox01 <> "" And SurfaceTextureTextBox02 <> "" Then
                '送り・ノーズRを変数に代入
                Feed = SurfaceTextureTextBox01
                NoseR = SurfaceTextureTextBox02

                '表面粗さ(Rz)の計算
                SurfaceTextureRz = ((Feed ^ 2) / (8 * NoseR)) * 1000

                '表面粗さ(Ra)の計算
                SurfaceTextureRa = (((Feed ^ 2) / (8 * NoseR)) * 1000) / 4

                '表面粗さ(Rz)をテキストボックスに表示
                SurfaceTextureTextBox03 = SurfaceTextureRz

                '表面粗さ(Ra)をテキストボックスに表示
                SurfaceTextureTextBox04 = SurfaceTextureRa

            End If

        'ドリル
        Case "Drill"
            'テキストボックスが空ではない場合の処理
            If DrillTextBox01 <> "" And DrillTextBox02 <> "" And DrillTextBox03 <> "" _
            And DrillTextBox04 <> "" Then
                '切削長・穴数・回転数・送りを変数に代入
                CuttingLength = DrillTextBox01
                NumberOfHoles = DrillTextBox02
                RotationSpeed = DrillTextBox03
                Feed = DrillTextBox04

                'サイクルタイムの計算
                CycleTime = ((CuttingLength * NumberOfHoles) / (RotationSpeed * Feed)) * 60

                'サイクルタイムをテキストボックスに表示
                DrillTextBox05 = CycleTime
            End If

        'サイクルタイム
        Case "CycleTime"
            'テキストボックスが空ではない場合の処理
            If CycleTimeTextBox01 <> "" And CycleTimeTextBox02 <> "" And CycleTimeTextBox03 <> "" Then
                '切削長・回転数・送りを変数に代入
                CuttingLength = CycleTimeTextBox01
                RotationSpeed = CycleTimeTextBox02
                Feed = CycleTimeTextBox03

                'サイクルタイムの計算
                CycleTime = (CuttingLength * 60) / (RotationSpeed * Feed)

                'サイクルタイムをテキストボックスに表示
                CycleTimeTextBox04 = CycleTime
            End If

        'エンドミル
        Case "EndMill"
            'テキストボックスが空ではない場合の処理
            If EndMillTextBox01 <> "" And EndMillTextBox02 <> "" Then
                '長さ・テーブル送りを変数に代入
                Length = EndMillTextBox01
                TableFeed = EndMillTextBox02

                '時間の計算
                TimeCal = Length * 60 / TableFeed

                '時間をテキストボックスに表示
                EndMillTextBox03 = TimeCal
            End If

        'テーブル送り
        Case "TableFeed"
            'テキストボックスが空ではない場合の処理
            If TableFeedTextBox01 <> "" And TableFeedTextBox02 <> "" Then
                '送り量(mm/rev)・回転数を変数に代入
                FeedAmount = TableFeedTextBox01
                RotationSpeed = TableFeedTextBox02

                'テーブル送り(mm/min)の計算
                TableFeed = FeedAmount * RotationSpeed

                'テーブル送り(mm/min)をテキストボックスに表示
                TableFeedTextBox03 = TableFeed
            End If

        '毎回転送り
        Case "TransferEveryTime"
            'テキストボックスが空ではない場合の処理
            If EveryRotationAndMinuteTextBox01 <> "" And EveryRotationAndMinuteTextBox02 <> "" Then
                '毎分送り(mm/min)・回転数を変数に代入
                FeedEveryMinute = EveryRotationAndMinuteTextBox01
                RotationSpeed = EveryRotationAndMinuteTextBox02

                '毎回転送り(mm/rev)の計算
                TransferEveryTime = FeedEveryMinute / RotationSpeed

                '毎回転送り(mm/rev)をテキストボックスに表示
                EveryRotationAndMinuteTextBox03 = TransferEveryTime
            End If

        '毎分送り
        Case "FeedEveryMinute"
            'テキストボックスが空ではない場合の処理
            If EveryRotationAndMinuteTextBox04 <> "" And EveryRotationAndMinuteTextBox05 <> "" Then
                '毎回転送り(mm/rev)・ノーズRを変数に代入
                TransferEveryTime = EveryRotationAndMinuteTextBox04
                NoseR = EveryRotationAndMinuteTextBox05

                '毎分送り(mm/min)の計算
                FeedEveryMinute = TransferEveryTime * NoseR

                '毎分送り(mm/min)をテキストボックスに表示
                EveryRotationAndMinuteTextBox06 = FeedEveryMinute
            End If

        'ねじ
        Case "Screw"
            'テキストボックスが空ではない場合の処理
            If ScrewTextBox01 <> "" And ScrewTextBox02 <> "" Then
                '回転数・ピッチを変数に代入
                RotationSpeed = ScrewTextBox01
                Pitch = ScrewTextBox02

                'ねじ予備動作の計算
                ScrewPreliminaryMotion = (RotationSpeed * Pitch) / 1800

                'ネジ予備動作をテキストボックスに表示
                ScrewTextBox03 = ScrewPreliminaryMotion
            End If

        '図面比率
        Case "DrawingRatio"
            'テキストボックスが空ではない場合の処理
            If DrawingRatioTextBox01 <> "" And DrawingRatioTextBox02 <> "" _
            And DrawingRatioTextBox04 <> "" Then
                '図面長さ①・計測長さ①・計測長さ②を変数に代入
                DrawingLength01 = DrawingRatioTextBox01
                MeasurementLength01 = DrawingRatioTextBox02
                MeasurementLength02 = DrawingRatioTextBox04

                '図面長さ②の計算
                DrawingLength02 = (DrawingLength01 * MeasurementLength02) / MeasurementLength01

                '図面長さ②をテキストボックスに表示
                DrawingRatioTextBox03 = DrawingLength02
            End If

        '中央長さ
        Case "CenterLength"
            'テキストボックスが空ではない場合の処理
            If CenterLengthTextBox01 <> "" And CenterLengthTextBox02 <> "" Then
                '外側・内側を変数に代入
                Outside = CenterLengthTextBox01
                Inside = CenterLengthTextBox02

                '中央の計算
                Center = (Outside + Inside) / 2

                '中央をテキストボックスに表示
                CenterLengthTextBox03 = Center
            End If
    End Select
End Sub

'エラー振り分け関数
Public Sub ErrorAllocation(ErrNum)
    Select Case ErrNum
        'オーバーフローした場合
        Case OVERFLOW_ERROR
            'WarningLabelにエラーを表示する
            WarningLabel = OVERFLOW_ERROR_WARNING

        '0で除算した場合
        Case DIVISION_BY_ZERO_ERROR
            'WarningLabelにエラーを表示する
            WarningLabel = DIVISION_BY_ZERO_ERROR_WARNING

        '型が一致しない場合
        Case TYPE_ERROR
            'WarningLabelにエラーを表示する
            WarningLabel = TYPE_ERROR_WARNING
    End Select
End Sub

'キャンセルコマンド関数
Private Sub CancelCommandButton_Click()
    Unload Me
End Sub

Private Sub MultiPage_Change()
    '初期化
    Initialization
End Sub

'中間処理
Public Sub IntermediateProc(CalItem)
    'エラーハンドリング
    On Error GoTo ErrorHandler

    '初期化
    Initialization

    '計算関数
    Calculation (CalItem)

    'エラーがない場合はここで終了
    Exit Sub

'エラーハンドラー
ErrorHandler:
    'エラーごとに振り分ける
    ErrNum = Err.Number
    ErrorAllocation (ErrNum)
End Sub
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mts10806

    2018/06/06 10:15

    振っているところよりも振り先の方が大事ですし、最初のコードだけだと何をしたいのか分かりません。全体提示が基本と思います。 確認したところ「似たような処理」ではありますが、全く同じではないのでまとめるのは結構難しいのではと思うのですが、いかがでしょうか?どの程度まとめるなど目標としているところがあれば追記してください。

    キャンセル

  • morutemu

    2018/06/06 10:27 編集

    了解しました。もう追記できないようなのでこちらで失礼します。まとめたいところなのですが、IntermediateProc ("???")ここの処理です。。。
    もしかすると、クラス化しないといけない感じでしょうか?

    キャンセル

  • mts10806

    2018/06/06 10:34

    どうしてもクラス化をしたいようですけど、したいならしてみても良いかとは思うのですが、例えば前の質問のttyp03さんの回答は参考になりそうに思うのですが、いかがでしょうか。 https://teratail.com/questions/129409

    キャンセル

回答 1

checkベストアンサー

+2

興味があったので、こちらのサイトを参考に実装してみました。

まず共通のイベント処理を実現するためのクラスを作ります。
名前はCommTextBoxとしてください。

Private WithEvents tb As MSForms.TextBox
Private item As String

' 情報登録
Public Sub NewClass(ByVal t As MSForms.TextBox, ByVal i As String)
    Set tb = t
    item = i
End Sub

' Changeイベント
Private Sub tb_Change()
    Call IntermediateProc(item)
End Sub

フォーム側の処理。

' 作成したクラスをテキストボックスの個数分インスタンス化
Private ctb(0 To 5) As New CommTextBox

' フォームの初期化イベント
Private Sub UserForm_Initialize()
    ' クラスに情報登録 テキストボックスの名前とそのテキストボックスで使用したいIntermediateProcの引数
    ctb(0).NewClass RotationSpeedTextBox01, "RotationSpeed"
    ctb(1).NewClass RotationSpeedTextBox02, "RotationSpeed"
    ctb(2).NewClass PeripheralVelocityTextBox01, "PeripheralVelocity"
    ctb(3).NewClass PeripheralVelocityTextBox02, "PeripheralVelocity"
    ctb(4).NewClass FilletLengthTextBox01, "FilletLength"
    ctb(5).NewClass FilletLengthTextBox02, "FilletLength"
End Sub

変数名等は適当に書いているので適宜修正してください。

感想。
思ったよりはスッキリしました。
ただフォーム内で収まってた処理がクラス側に分散してしまうので、可読性は落ちますね。
そこをどう捕らえるか。
私なら現状維持で、無駄に一つにまとまっているCalculation関数なんかを分割したり、そういうところに力を注ぐかと思います。
そもそもCalculation関数の引数が文字列ってところから受け付けられません。
余談でした。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/06 11:28

    回答ありがとうございました。
    一つ質問お願いします。
    >そもそもCalculation関数の引数が文字列ってところから受け付けられません。
    とありますが、通常引数は、数字などでしょうか??

    キャンセル

  • 2018/06/06 11:38

    この場合の引数の意味って、処理を振り分ける識別のためだけの引数ですよね。
    文字列自体に意味があるわけではない。
    今の時代のPCならこの程度のことで速度(文字列の比較は遅くなる)とかリソース(数値を渡すよりより多くのメモリが必要)とか気にする必要はないのでしょうけど、コーディングとしてはあまりお勧めはできません。
    なので、私なら引数用の列挙型を定義して使いますね。
    こんな感じで。
    Enum CALITEM
     ROTATION_SPEED
     PERIPHERAL_VELOCITY
     FILLE_LENGTH
    End Enum

    Call IntermediateProc(CALCITEM.FILLE_LENGTH)

    キャンセル

  • 2018/06/06 11:58

    Enumはじめて知りました。
    VBAも見よう見まねで作っているので、
    色々聞いてしましました。
    ありがとうございました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • VBA

    1906questions

    VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

  • Excel

    1637questions

    Excelは、マイクロソフト社が開発しているデータ集計や分析を行う表計算ソフトの一つです。文書作成や表計算、資料作成などの多彩な機能を備えており、統合パッケージであるMicrosoft Officeに含まれています。