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

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

ただいまの
回答率

90.34%

  • VBA

    1909questions

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

後で使いまわしやすい プロシージャ の書き方

解決済

回答 4

投稿 編集

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

kamikazelight

score 126

 後で使いまわしやすい プロシージャ の書き方

過去の質問で教えて頂いた情報を基にクリップボードを使わないで
コピペのコードを書いてみたのですが...
また 脳内選択肢が多すぎで困ってます。

とりあえず書いたコードを載せます。

Option Explicit
Option Private Module

  'Paste情報と縦横サイズ
  Private XML As String
  Private RowSize As Long
  Private ColumnSize As Long


Sub MyCopy(ByVal CopyRng As Range, Optional ByVal PasteRng As Range)
'セルの 大体の書式と 値を Copy

  Dim VType As XlRangeValueDataType

    VType = xlRangeValueXMLSpreadsheet

    'Copy
    RowSize = CopyRng.Rows.Count
    ColumnSize = CopyRng.Columns.Count
    XML = CopyRng.Value(VType)

    'Paste
    If Not PasteRng Is Nothing Then
        PasteRng.Resize(RowSize, ColumnSize).Value(VType) = XML
    End If
End Sub


Sub MyPaste(ByRef PasteRng As Range, Optional ByVal CopyRng As Range)
'セルの 大体の書式と 値を Paste

  Dim VType As XlRangeValueDataType

    VType = xlRangeValueXMLSpreadsheet

    'Copy
    If Not CopyRng Is Nothing Then
        RowSize = CopyRng.Rows.Count
        ColumnSize = CopyRng.Columns.Count
        XML = CopyRng.Value(VType)
    End If

    'Paste
    PasteRng.Resize(RowSize, ColumnSize).Value(VType) = XML
End Sub

 悩んでいる内容

  Dim VType As XlRangeValueDataType
    VType = xlRangeValueXMLSpreadsheet


まず、これはValueの引数がそのままだと候補が出てこなかったので
候補が出てくるように入れたのですが
なんとコメントを入れたらいいのか...
そもそもこういうことをしてもいいのかが分かりません。

次にコマンドの機能自体ですがコピーコマンドといえば
コピー元とコピー先を指定したらコピーできるのが基本だと
思ったので、ペーストの機能も含んだ内容で作りました。
そのあとに連続貼付けの為にペーストコマンドを作ったのですが
対になった方がいいかなと思いコピーの機能を含みにしました。
当然ですがその結果はほぼおんなじコードになるわけなのですが
こういう場合はコピーとペーストは完全に分けたほうがいいのでしょうか
いっそのことCopyPasteとしてくっつけてしまった方がいいのでしょうか

他にも何かあれば指摘して頂きたいです。
よろしくお願い致します。

 蛇足 ~見やすいコードが書きたい~

最近 作る内容が複雑になってきて過去に作ったコードを再利用出来る様に
したいと思い始めました。
現状 コードがぐちゃぐちゃで探すよりも書き直した方が早いという感じで
再利用が出来ません。
書籍を買って読んだりしていますが
知識が増える度に選択肢の多さに迷い
手が止まります。
最終目標は判断基準の確立と
コードの使いまわしが出来るようにすることです。
宜しくお願い致します。

ベストアンサー選択後の追記

いろいろ意見を頂き
ホントにコピーとペーストそれぞれ必要なのか
再度考えてみました、
ペーストは同じ内容を連続で貼付けするために
足したのですが、今回は今のところ必要なさそうなので
やめることにしました。
それに伴い値の保持の必要もなくなったので
変数はプロシージャ内へ移動、
また、PasteRngは必ず指定しなければいけなくなるので
Optional をやめ Pasteの実行判断のIfもやめました。
クラスにする必要性も低くなったと思うので標準モジュールのままで

Option Explicit
Option Private Module


Sub MyCopy(ByVal CopyRng As Range, ByVal PasteRng As Range)
'セルの 大体の書式と 値を Copy

  Dim XML As String
  Dim RowSize As Long
  Dim ColumnSize As Long
  Const ValueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet

    'Copy
    RowSize = CopyRng.Rows.Count
    ColumnSize = CopyRng.Columns.Count
    XML = CopyRng.Value(ValueDataType)

    'Paste
    PasteRng.Resize(RowSize, ColumnSize).Value(ValueDataType) = XML
End Sub


回答してくださった方ありがとうございました。
また、次も宜しくお願い致します。

  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+2

コーディングの問題でなく、設計の問題だと思います。
機能分割がうまく整理できていないかと。

コピーとペーストが同じ動きをするなら、そもそもプロシージャを2つ作る意味がないです。

コードの使いまわし出来るようにする

単純にいうと、使いまわしをしたければ、コードでやることを小さくすることです。
subルーチンを沢山作るのでなく、functionを使って小さい部品を作り、それらを組み合わせて(コードの使いまわし)
subを構築すると、すっきりするかと思います。

古い本ですが「UNIXという考え方」が薄いわりにためになるので、読んでみることをお勧めします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/20 19:11

    ググってみると、いろいろ書評とか内容でてくるので、拾い読みしてはどうでしょう。

    キャンセル

  • 2018/07/21 18:01

    返答ありがとうございます。
    書籍で「プリンシプルオブプログラミング」等を読んでいるのですが
    そちらにも 引用? で同じ内容が出てきています。
    考え方自体は理解できるのですが「小さい部品を作り」とあってもどこまで
    小さく、細かく しても良いのかが分からないのです....
    質問の内容でいうと 「ペースト」と「コピー」の機能を完全に切り離して
    小さな部品にするとペーストのコードが極端に短い気がして、それでいいのか不安になります。

    キャンセル

+2

imihitoさんも言われてるように、標準モジュールのパブリック変数にコピーデータを格納するというのはバグの元ですのて避けたいです。

ということで、クラスにしてコピーデータは完全に隠蔽してみました。
せっかくクラスにするので、メソッドは Copy, Paste だけでなく Cut を追加しました。
また、書式込み(PasteAll)か 値のみ(PasteValues)かの選択をできるようにしてみました。

クラスモジュール MyCopyRange

Option Explicit

Private XML As String
Private ary() As Variant
Private RowCount As Long
Private ColumnCount As Long
Const valueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet

Public Enum myPasteType
    PasteAll = 0 '既定値
    PasteValues = 1
End Enum

Private Sub GetData(ByRef MyRange As Range)
    With MyRange
        XML = .Value(valueDataType)
        ary = .Value
        RowCount = .Rows.Count
        ColumnCount = .Columns.Count
    End With
End Sub

Public Sub Copy(ByRef CopyRange As Range, _
                Optional ByRef Destination As Range, _
                Optional PasteType As myPasteType)
    GetData CopyRange
    If Not Destination Is Nothing Then
        Paste Destination, PasteType
    End If
End Sub

Public Sub Cut(ByRef CutRange As Range, Optional ByRef Destination As Range, Optional PasteType As myPasteType)
    GetData CutRange
    CutRange.Clear
    If Not Destination Is Nothing Then
        Paste Destination, PasteType
    End If
End Sub

Public Sub Paste(ByVal Destination As Range, Optional PasteType As myPasteType)
    With Destination.Resize(RowCount, ColumnCount)
        If PasteType = myPasteType.PasteValues Then
            .Value = ary
        Else
            .Value(valueDataType) = XML
        End If
    End With
End Sub

使用例 

Public Sub Test1()
'コピーして連続ペースト 書式も含めて(規定値 PasteAll)
    Dim myCopy As New MyCopyRange
    With myCopy
        .Copy Range("B1:C4")
        .Paste Range("E1")
        .Paste Range("E6")
    End With
End Sub

Public Sub Test2()
'コピー&ペースト 値のみ
    Dim myCopy As New MyCopyRange
    myCopy.Copy Range("B1:C4"), Range("E1"), PasteValues
End Sub

Public Sub Test3()
'カット&ペースト 書式も含めて
    Dim myCopy As New MyCopyRange
    myCopy.Copy Range("B1:C4"), Range("E1"), PasteAll
End Sub

クラス名がいまいちなのがあれですが(-_-;)
クラスにするとき名前にいつも悩みます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/22 12:10

    クラス名は、CopyWithoutClipboard というような使用目的をあらわすものの方がいいかも。

    キャンセル

  • 2018/07/23 09:14

    >標準モジュールのパブリック変数にコピーデータを格納するというのはバグの元ですのて避けたいです。
    との事ですが
    変数は パブリックではなくちゃんとプライベートに してあります。
    発生が考えられるバグはどんなものがあるのでしょうか
    ユーザーが実行してしまう恐れ は
    Option Private Module をモジュールの最初に入れてあるので
    VBEからでないと実行できないですし
    変数もプライベートにしてあるので
    他のモジュールから変更される恐れはないと思っているのですが...
    私の中で、考えられる問題は全てのプログラムの実行が終わっても値が残ってしまうので
    別のプロシージャでCopyの記述を忘れてPasteだけ実行してしまったときに
    想定外の内容(前回保存値)がPasteされてしまう事等ですが、
    そういった内容の事でしょうか、それともほかにもっと大きな問題が
    あるのでしょうか?
    教えて頂きたいです。

    キャンセル

  • 2018/07/23 09:36

    kamikazelightさんのコードに対してのことでなく一般論としてです。
    kamikazelightさんのコードがそのようになっているいう意味ではまったくありません。

    キャンセル

  • 2018/07/23 09:41

    すみません。
    勘違いをしました。
    他にもいろいろ教えて頂きたいことが出来ましたが、
    別質問にて出そうと思います。
    またよろしくお願い致します。

    キャンセル

  • 2018/07/23 09:51

    一つ問題点をあげるとすれば、
    私やimihitoさんのコードだと、コピーデータのスコープは、宣言した変数(構造体 Or クラス)のスコープと同じになりまので、スコープの範囲をプログラマが制御できます。
    kamikazelightさんのコードだと、コピーデータは共有なので、CopyとPasteをわけて実行するとき、サブルーチン等で変更されている可能性があるということをプログラマは意識する必要があります。ただ、Excel標準のCopyメソッドも同じことなので、プログラマが意識していれば済む話ですが。

    キャンセル

  • 2018/07/23 10:46

    そうですね...
    後で修正入れる時とか他の人が直すときにプログラマが意識しないといけなくなってしまうのですね。
    一人なので 記憶があるうちはサブルーチン等で変更が ある or ない ことが分かっているので
    変更されている可能性など 意識していませんでした。
    そういった 積み重ねで 私のコードは直しにくくなってるのでしょうね
    ありがとうございました。

    キャンセル

checkベストアンサー

+1

私の場合、標準モジュールというどこからもアクセス出来る場所には、状態を持たせたくないです。

MyCopyだけで用は足りるのでひとまとめにしてしまって良いと思います。

'セルの 大体の書式と 値を CopyPaste
Sub MyCopy(ByVal CopyRng As Range, ByVal PasteRng As Range)

    Const valueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet

    With CopyRng
        PasteRng.Resize(.Rows.Count, .Columns.Count) _
                .Value(valueDataType) = .Value(valueDataType)
    End With 'CopyRng

End Sub

コピーとペーストで役割を分離させるという事で、以下のコードも考えてみました。
正直なところ無駄に複雑な感が強いですが。

'コピーした情報
Public Type RangeXmlValue
    XML As String
    RowCount As Long
    ColumnCount As Long
End Type

'コピー相当
Property Get XmlValueOf(ByVal Target As Range) As RangeXmlValue
    With XmlValueOf
        .XML = Target.Value(Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet)
        .RowCount = Target.Rows.Count
        .ColumnCount = Target.Columns.Count
    End With 'XmlValueOf
End Property

'ペースト相当
Property Let XmlValueOf(ByVal Target As Range, pasteData As RangeXmlValue)
    Target.Resize(pasteData.RowCount, pasteData.ColumnCount) _
          .Value(Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet) _
            = pasteData.XML
End Property

コピーした情報はモジュールに持たせたくないので、ユーザー定義型に入れて返す形とします。
コピーとペーストで表記を合わせるためにPropertyプロシージャを使っています。

以下のように使用します。

'その場でコピペ
XmlValueOf(ActiveCell.Offset(, 1)) = XmlValueOf(ActiveCell)


'コピーしてからペースト
Dim copyData As RangeXmlValue
copyData = XmlValueOf(ActiveCell)

XmlValueOf(ActiveCell.Offset(1)) = copyData

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/21 17:46

    クラスを使うことは考えてましたが
    メソッドとして実装する方法しか考えていませんでした。
    ユーザー定義型を使うと
    プロパティはそういう使いかたも出来るのですね
    ありがとうございます。

    キャンセル

0

見やすいコードが書きたい

Option Explicit

Private Sub MyCopy(ByVal CopyRng As Range, Optional ByVal PasteRng As Range)
    On Error Resume Next
    CopyRng.Copy PasteRng
End Sub

Private Sub MyPaste()
    If Application.CutCopyMode Then
        ActiveSheet.Paste Selection
    End If
End Sub

エクセルのコピーやペーストの機能を使うなら、
敢えてMyCopyなどという自作のメソッドっぽいものを作らなくても、エクセルに任せればよいです。
サブルーチンに書き出したところで、モジュールを汚すだけです。

連続して、選択→貼付を繰り返すなら、手動ですればよいだけ。
マクロを書いたところで、同じような操作になるだけでしょう。
マクロを書かなくても、
セル範囲を選択→Ctrl+C → 貼り付けたいセルを選択 →Ctrl+V
を繰り返すだけでしょう。

敢えてマクロでどうのこうのする必要が全く見えてこないです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/07/21 12:37

    質問者さんの過去質問をみると、クリップボードを使いたくないらしいです。クリップボード履歴が鬱陶しいとの上司から指示で。

    キャンセル

  • 2018/07/21 14:47

    え!?

    ちょまって。。。クリップボード履歴ってどうやってみるんですか?
    そんなもん使ったことないし簡単に見れましたっけ?
    ということで逆に隠したらいいだけでは????

    キャンセル

  • 2018/07/21 16:35 編集

    下記を参考に。
    Office クリップボードを使用したコピー/貼り付け - Office サポート
    https://support.office.com/ja-jp/article/office-%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%82%B3%E3%83%94%E3%83%BC-%E8%B2%BC%E3%82%8A%E4%BB%98%E3%81%91-714a72af-1ad4-450f-8708-c2931e73ec8a
    質問者さんに代わってこたえるのもなんですが、たぶん、その上司さんは普段からクリップボード履歴を使用していて、システムでのコピー処理の履歴が勝手に追加されるのを嫌っているだと思います。

    キャンセル

  • 2018/07/21 17:52

    hatena19 様 説明 ありがとうございました。
    過去の質問 URL↓
    https://teratail.com/questions/136468
    で出していた内容なので質問文で「過去の質問で教えて頂いた情報を基に」と書いただけで
    URLも何も載せておらず説明が不足しておりました。
    mattuwan 様 すみませんでした。

    キャンセル

  • 2018/07/21 21:08

    過去質問に関連する質問をするときは、過去質問のリンクを張っておいた方がいいですね。
    今からでも、質問を編集してリンクを追加しておいてください。
    あとから見に来た人にとっても親切だと思います。

    キャンセル

  • 2018/07/22 15:06

    すみません。
    教えてください。
    「システムでのコピー処理」とは何でしょう?
    あと、クリップボードを使うと何回か前のコピーしたものも貼り付けられってことですか?

    キャンセル

  • 2018/07/22 15:31

    正確には「Office クリップボード」で、OSのクリップボードは1つしか保存できないですが、「Office クリップボード」は過去の履歴を保存できて、何回か前のコピーも貼り付けられます。Excel、Word、AccessなどOfficeアプリで共通で使えます。
    システムでのコピーとは、自作システムでVBAでCopyメソッドなどでデータの転記処理をした場合のことで、それが履歴に出てしまうのを避けたいという希望だと理解してます。

    キャンセル

  • 2018/07/23 16:52

    なるほど、操作者が意図的に操作したコピー以外の履歴を隠したいということですね。
    了解です。

    解決後ですが、
    ならば、自作のクリップボードっぽいものを作ってはいかがでしょう。。。。
    作れるかどうかわかりませんが。。。

    キャンセル

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

  • VBA

    1909questions

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