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

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

新規登録して質問してみよう
ただいま回答率
85.50%
VBA

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

Q&A

解決済

4回答

7219閲覧

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

kamikazelight

総合スコア305

VBA

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

1グッド

2クリップ

投稿2018/07/20 08:51

編集2018/07/23 01:30

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

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

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

VBA

1Option Explicit 2Option Private Module 3 4 'Paste情報と縦横サイズ 5 Private XML As String 6 Private RowSize As Long 7 Private ColumnSize As Long 8 9 10Sub MyCopy(ByVal CopyRng As Range, Optional ByVal PasteRng As Range) 11'セルの 大体の書式と 値を Copy 12 13 Dim VType As XlRangeValueDataType 14 15 VType = xlRangeValueXMLSpreadsheet 16 17 'Copy 18 RowSize = CopyRng.Rows.Count 19 ColumnSize = CopyRng.Columns.Count 20 XML = CopyRng.Value(VType) 21 22 'Paste 23 If Not PasteRng Is Nothing Then 24 PasteRng.Resize(RowSize, ColumnSize).Value(VType) = XML 25 End If 26End Sub 27 28 29Sub MyPaste(ByRef PasteRng As Range, Optional ByVal CopyRng As Range) 30'セルの 大体の書式と 値を Paste 31 32 Dim VType As XlRangeValueDataType 33 34 VType = xlRangeValueXMLSpreadsheet 35 36 'Copy 37 If Not CopyRng Is Nothing Then 38 RowSize = CopyRng.Rows.Count 39 ColumnSize = CopyRng.Columns.Count 40 XML = CopyRng.Value(VType) 41 End If 42 43 'Paste 44 PasteRng.Resize(RowSize, ColumnSize).Value(VType) = XML 45End Sub

悩んでいる内容

VBA

1 Dim VType As XlRangeValueDataType 2 VType = xlRangeValueXMLSpreadsheet

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

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

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

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

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

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

VBA

1Option Explicit 2Option Private Module 3 4 5Sub MyCopy(ByVal CopyRng As Range, ByVal PasteRng As Range) 6'セルの 大体の書式と 値を Copy 7 8 Dim XML As String 9 Dim RowSize As Long 10 Dim ColumnSize As Long 11 Const ValueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet 12 13 'Copy 14 RowSize = CopyRng.Rows.Count 15 ColumnSize = CopyRng.Columns.Count 16 XML = CopyRng.Value(ValueDataType) 17 18 'Paste 19 PasteRng.Resize(RowSize, ColumnSize).Value(ValueDataType) = XML 20End Sub

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

hihijiji👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

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

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

クラスモジュール MyCopyRange

VBA

1Option Explicit 2 3Private XML As String 4Private ary() As Variant 5Private RowCount As Long 6Private ColumnCount As Long 7Const valueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet 8 9Public Enum myPasteType 10 PasteAll = 0 '既定値 11 PasteValues = 1 12End Enum 13 14Private Sub GetData(ByRef MyRange As Range) 15 With MyRange 16 XML = .Value(valueDataType) 17 ary = .Value 18 RowCount = .Rows.Count 19 ColumnCount = .Columns.Count 20 End With 21End Sub 22 23Public Sub Copy(ByRef CopyRange As Range, _ 24 Optional ByRef Destination As Range, _ 25 Optional PasteType As myPasteType) 26 GetData CopyRange 27 If Not Destination Is Nothing Then 28 Paste Destination, PasteType 29 End If 30End Sub 31 32Public Sub Cut(ByRef CutRange As Range, Optional ByRef Destination As Range, Optional PasteType As myPasteType) 33 GetData CutRange 34 CutRange.Clear 35 If Not Destination Is Nothing Then 36 Paste Destination, PasteType 37 End If 38End Sub 39 40Public Sub Paste(ByVal Destination As Range, Optional PasteType As myPasteType) 41 With Destination.Resize(RowCount, ColumnCount) 42 If PasteType = myPasteType.PasteValues Then 43 .Value = ary 44 Else 45 .Value(valueDataType) = XML 46 End If 47 End With 48End Sub

使用例

vba

1Public Sub Test1() 2'コピーして連続ペースト 書式も含めて(規定値 PasteAll) 3 Dim myCopy As New MyCopyRange 4 With myCopy 5 .Copy Range("B1:C4") 6 .Paste Range("E1") 7 .Paste Range("E6") 8 End With 9End Sub 10 11Public Sub Test2() 12'コピー&ペースト 値のみ 13 Dim myCopy As New MyCopyRange 14 myCopy.Copy Range("B1:C4"), Range("E1"), PasteValues 15End Sub 16 17Public Sub Test3() 18'カット&ペースト 書式も含めて 19 Dim myCopy As New MyCopyRange 20 myCopy.Cut Range("B1:C4"), Range("E1"), PasteAll 21End Sub

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

投稿2018/07/21 11:27

編集2019/05/31 10:30
hatena19

総合スコア33620

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hatena19

2018/07/22 03:10

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

2018/07/23 00:14

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

2018/07/23 00:36

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

2018/07/23 00:41

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

2018/07/23 00:51

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

2018/07/23 01:46

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

0

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

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

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

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

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

投稿2018/07/20 10:06

momon-ga

総合スコア4820

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

momon-ga

2018/07/20 10:11

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

2018/07/21 09:01

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

0

ベストアンサー

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

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

vba

1'セルの 大体の書式と 値を CopyPaste 2Sub MyCopy(ByVal CopyRng As Range, ByVal PasteRng As Range) 3 4 Const valueDataType = Excel.XlRangeValueDataType.xlRangeValueXMLSpreadsheet 5 6 With CopyRng 7 PasteRng.Resize(.Rows.Count, .Columns.Count) _ 8 .Value(valueDataType) = .Value(valueDataType) 9 End With 'CopyRng 10 11End 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プロシージャを使っています。

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

vba

1'その場でコピペ 2XmlValueOf(ActiveCell.Offset(, 1)) = XmlValueOf(ActiveCell) 3 4 5'コピーしてからペースト 6Dim copyData As RangeXmlValue 7copyData = XmlValueOf(ActiveCell) 8 9XmlValueOf(ActiveCell.Offset(1)) = copyData

投稿2018/07/21 04:43

編集2018/07/21 11:59
imihito

総合スコア2166

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamikazelight

2018/07/21 08:46

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

0

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

VBA

1Option Explicit 2 3Private Sub MyCopy(ByVal CopyRng As Range, Optional ByVal PasteRng As Range) 4 On Error Resume Next 5 CopyRng.Copy PasteRng 6End Sub 7 8Private Sub MyPaste() 9 If Application.CutCopyMode Then 10 ActiveSheet.Paste Selection 11 End If 12End Sub

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

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

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

投稿2018/07/21 03:31

mattuwan

総合スコア2136

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hatena19

2018/07/21 03:37

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

2018/07/21 05:47

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

2018/07/21 07:37 編集

下記を参考に。 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 質問者さんに代わってこたえるのもなんですが、たぶん、その上司さんは普段からクリップボード履歴を使用していて、システムでのコピー処理の履歴が勝手に追加されるのを嫌っているだと思います。
kamikazelight

2018/07/21 08:52

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

2018/07/21 12:08

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

2018/07/22 06:06

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

2018/07/22 06:31

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

2018/07/23 07:52

なるほど、操作者が意図的に操作したコピー以外の履歴を隠したいということですね。 了解です。 解決後ですが、 ならば、自作のクリップボードっぽいものを作ってはいかがでしょう。。。。 作れるかどうかわかりませんが。。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問