プロが教える店舗&オフィスのセキュリティ対策術

Excel VBAを使っていて
512×512の二次元配列をクリップボードにコピーして
シート上でペーストすることでシートに貼り付けられるようにしたいのですが
どうすれば良いですか?


https://oshiete.goo.ne.jp/qa/5650002.html

検索すると単一の変数のクリップボードへの転送方法に関しては
このページなどにたくさん見つかるのですが
配列を転送方法について書かれたページが見つかりませんでした。

とりあえず、

Open filepath3 For Output As #1

でタブ区切りのファイルとして一時保存した後に


.SetText FSO.GetFile(filepath3).OpenAsTextStream.ReadAll
.PutInClipboard

Readallで読み込むことで所望の操作を行うことができました。

しかし、HDDに一時ファイルを生成せずに
直接配列からクリップボードにコピーする方法があれば教えてください。

さんざん検索しても分かりませんでした。

A 回答 (2件)

こんにちは。



おやおや回答しようとしたら削除されてましたね。
せっかく書いていたので、少しの加筆だけで投稿します。
(少々文脈が乱れますがご容赦)

> Excel VBAを使っていて
> 512×512の二次元配列をクリップボードにコピーして
> シート上でペーストすることでシートに貼り付けられるようにしたいのですが
> どうすれば良いですか?

ちょっとこれだけでは何とも答え難いですが、
https://oshiete.goo.ne.jp/qa/8944391.html
でのご質問の延長、ということでしたら、
hairetuが取得出来ているとして、
' ' ///
Dim nYSize As Long, nXSize As Long
  nYSize = UBound(hairetu) - LBound(hairetu) + 1
  nXSize = UBound(hairetu, 2) - LBound(hairetu, 2) + 1
  ' ' 以下、セル範囲への出力(B2を左上にして512*512のセル範囲)
  Cells(2, 2).Resize(nYSize, nXSize).Value = hairetu
' ' ///
のように、そのまんま配列をセル範囲に出力すればいいのでは?
出力先のセル範囲に既存のデータがある場合は、一旦、
range.ClearContents で空にしてから出力した方が
遅くなる原因を減らして速くなる場合が多いです。
その他、セル範囲への出力の際の定番、
  Application.ScreenUpdating = False ' 描画更新停止
  ' ' セル範囲への出力処理
  Application.ScreenUpdating = True
とか、
  Application.Calculation = xlCalculationManual ' 再計算停止
  ' ' セル範囲への出力処理
  Application.Calculation = xlCalculationAutomatic
とか、
  Application.EnableEvents = False ' イベント停止
  ' ' セル範囲への出力処理
  Application.EnableEvents = True
など、必要に応じて書き加えます。

二次元配列変数の値をセル範囲へ出力するだけなら、
上記の方法は一般的、です。
ただ、バイナリをそのままセル範囲に出力、というのは、
私個人は実験以外に経験ないので、もし勘違いでもあればすみません。

前スレの、、、
> ワークシートのセルの内容をタブ区切りのテキストデータとして出力するプログラム

上記の方法でセル範囲への出力が出来たとして、
' ' ///
  range.Copy ' ←セル範囲を指定すること
Dim oDTO As MSForms.DataObject
  Set oDTO = New MSForms.DataObject
oDTO.GetFromClipboard
  sBuf = oDTO.GetText
  Set oDTO = Nothing
' ' ///
のようにします。
hairetuが取得出来ているなら、
最初に提示した方法でそのままセル範囲に出力して、続けて
この方法でタブ区切りのテキストにすることも出来るということです。
タブ区切りのテキストさえ出来てしまえば、
Open filename For Output As #
とか、色んな方法で出力できますね。

さて、
DataObject .SetText .PutInClipboard の組合わせを
用いる利点があるとすれば、
Excelシートのデータを整形して外部アプリケーションに送る時や、
HTML/XMLテーブルをソースから直接読込んでExcelシートに貼り付ける時、
とかに限定されるように思います。
データベーステーブルの体裁を持ったファイルなら、adodb経由で
adodb.recordset.GetRows とか、
adodb.recordset.GetString とか、
excel.range.CopyFromRecordset みたいな、
用途に見合った形の配列の扱い方が用意されている場合もあります。
部分的な手法に目を向けるよりも、やろうとしている処理内容を
基準に調べた方が吉、という場合もあるのかもしれませんね。
でも、申し訳ないけど、全体として何をやりたいのか解りませんし、
私がどこまで役に立てるかもわかりませんから、
直接にはあまり示唆的なことを書けないような気がします。。

> 配列を転送方法について書かれたページが見つかりませんでしたので
> どうか教えてください。

> しかし、HDDに一時ファイルを生成せずに
> 直接配列からクリップボードにコピーする方法があれば教えてください。

結論としては、配列変数の値を直接的にクリップボードに送るような方法は
用意されていません。
(APIとか.NetFrameWorkとか使えば出来るのかも?ですが私の守備範囲外ですし、
 出来たとしても「直接」とは言い難いし、そこまでする必要もなさそうと判断しています。)
期待通りのものではないでしょうけれど、
普通に文字列処理をするだけのベタな方法です。
速さを意識するのなら、
現行のExcelでは、[貼付け]に要する時間が大きめなので、
期待外れに終るような気もします。
っていうか、本当にこのプロセスが必要だとは思っていないのです。
最初に書いたGetFromClipboardまでの処理の流れの方を
薦めているつもりですが、ココでは一応お求めのまま。

' ' /// ダミー配列変数の値をタブ区切りCrLf改行のプレーンテキストとしてクリップボードへ出力 ///
Dim sTempLine As String
Dim sBuf As String
Dim i As Long, j As Long
  For i = 1 To nYSize
    sTempLine = ""
    For j = 1 To 512
      sTempLine = sTempLine & vbTab & hairetu(i, j)
    Next j
    sBuf = sBuf & vbCrLf & Mid$(sTempLine, 2)
  Next i
  sBuf = Mid$(sBuf, 3) ' タブ区切りテキスト作成完了

Dim oDTO As MSForms.DataObject
  Set oDTO = New MSForms.DataObject
  oDTO.SetText sBuf, 1
  oDTO.PutInClipboard ' タブ区切りテキストをクリップボードへ出力
  Set oDTO = Nothing
' Cells(2, 2).PasteSpecial
' ' ///

再度、
> しかし、HDDに一時ファイルを生成せずに

抵抗感があるのは何となく理解できますけれど、
上級者さんの感覚では、ただ単にHDDのメモリを借用するだけ、
どこのメモリを使うかの違いだけ、なのかも、です。
ファイル操作処理に限らず、メモリを大量に食うような処理では、
tempファイルを使うことは一般的なことですし、
必要以上に難しく考えなくてもいいのかな、とは思います。
ただ、今回の設問の限りでは、そこまでの必要はない、ですね。

とりあえず、以上です。
お訊ねの内容と、関連した私の解答に関する補足質問にはお応えします。
    • good
    • 0
この回答へのお礼

ありがとうございます。
うまくいきました。

お礼日時:2015/03/25 18:50

こんにちは。



前回のやりとりから読んでいました。失礼かもしれませんが、そんなに高度の話ではなさそうなのに、さっぱり、意図が分からずじまいで、そのやりとりの取っ掛かりさえ見当つきませんでした。私のマクロをみて、ローテクしかないと、揶揄する方もいるかもしれませんが、いくつかの疑問点を、もう少し状況を教えていただけませんか?だから、私などお話にならないとお思いでしたら、無視なさっても結構です。

なお、クリップボードに入れるワザとしては、この私でさえ、いくつか知っておりますが、ただ、どれもExcelにしろオブジェクトを使う作業過程で、オブジェクトの実体化の実質的な時間を加味すれば、[512*512]程度のファイルでは、よほどのことがない限りは、その差は大きくないはずです。1秒が1時間のように感じるなら別ですが。某氏が別の掲示板で、「(マクロの)実行は3秒、その開発は3日。」けだし名言です。

疑問点として
・バイナリデータとお書きになっていたけれど、
 「二次元配列データが入ったバイナリデータを読み込んで」
 まさか、バイナリファイルでもないでしょうし、バイナリデータを他に変換しているわけでもないはずです。その最初の取っ掛かりの部分が明らかになっていないように思います。こちらは、0から255までの数値の入った[512 * 512]のデータを想定しています。ここらが、最初のモヤモヤの発端です。
 
・タブ区切りのファイルとして一時保存
 [512 * 512]のファイルを出力するなど、インポートも、エクスポートも、一瞬に近いはずです。それを入れ出しするというものなのでしょうか。CSVであろうが、TSVであろうが、あまり問題はないと思います。

 それに、インポート方法もいろいろあるはずです。[512 * 512]のデータのインポートなど、それほどに時間が掛かるはずもないし、テンポラリーファイルの何が問題なのかも不明です。加工があるというなら別ですが。

・HDDに一時ファイルを生成せずに直接配列からクリップボードにコピーする方法
 仮に、テンポラリファイルであろうが、ファイル自体は存在しているし、クリップボードに格納する場合は、そのファイル自体を、クリップボードのとば口に持ってこなくてはいけなくてはいません。VBA等で、名指しでファイルに命令して、そんなに手間が掛かるとは思えません。

[オブジェクト生成](一部はの方法は、OS側が保持、しかし、命令手順が必要]
「クリップボード・オブジェクト」<- データ [インポート]
[物理的移動]
[命令]-[ペーストのオブジェクトを確保]
「クリップボード・オブジェクト」->- データ [エクスポート]

このような手間を考えるなら、Excelへのインポートは、QueryTableひとつで十分だと思います。
Test1.txt (TSVファイル) サイズ 約1M 弱
出力はいうまでもありません。シートコピー・保存で十分です。(後に、多少の違いは見つかりました)

計測データ(timeGetTimeによる)
Import: 488 /1000 sec (以下 1000 secは省略)
Emport: 456
二度目
EmportFile: 486
ImportFile: 540
'//
Sub ImportFile()
Dim Fname As String
Dim objQT As QueryTable
Fname = "TEXT;" & ThisWorkbook.Path & "\Test1.txt"
 Set objQT = ActiveSheet.QueryTables.Add(Fname, Range("A1"))
   With objQT
   .Name = "Test1"
   .TextFilePlatform = xlWindows '2
   .TextFileColumnDataTypes = Array(1)
   .Refresh BackgroundQuery:=False
  End With
  objQT.Delete
End Sub
'//
Sub ExportFile() '※
 Dim myPath As String
  myPath = ThisWorkbook.Path & "\"
  ActiveSheet.Copy
  With ActiveWorkbook
   .SaveAs myPath & "Test2.Txt", xlText
   .Close False
   End With
End Sub
'//

※再計算(Calculate)の他、Event についても注意が必要。割り込みさせられないようにする)

以下のような事は不要だと思います。
しかし、時間を計測すると、QueryTableの10分の1ぐらい速いけれど、これを判別するのは神の領域ではないでしょうか。
ClipBoardTest1: 62

'//
Sub ClipBoardTest1()
'VBEditor 画面は必ず閉じてください。
 Dim Filename As String
 Dim buf 'Stringにはしないこと
 Filename = ThisWorkbook.Path & "\" & "Test1.txt"
 Set obj = CreateObject("HTMLfile")
 With CreateObject("Scripting.FileSystemObject").OpenTextFile(Filename)
  buf = .ReadAll
  .Close
 End With
 obj.parentWindow.clipboardData.SetData "text", buf
  Range("A1").Select
 Application.SendKeys "^v"
End Sub
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

>512*512]程度のファイルでは、よほどのことがない限りは、その差は大きくないはずです。

実行回数が一回なら大差ないですが
1万回ループでこなすのならどうですか?
また一回実行して終わりではなく、何回も何回もパラメータを変えながら
実行しないといけないとなると、少しでも短くしたくなるでしょ?

お礼日時:2015/03/25 18:51

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています