[[20170116012224]] 『momoさんのツールをいじってみました』 (マリオ)  >>BOT

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『momoさんのツールをいじってみました』 (マリオ)

エクセルの学校で、momoさんの「SheetlayoutToClipBord」
大変重宝して使わせてもらっています。
今回クリップボードではなくて、テキストに書き込むバージョンの「Sheetlayout_To_Text」を作ってみました。

[[20110209184943]]

 『[談]シートレイアウトの投稿どうしてますか?』(momo)
 ごく最近、Windows8.1からWindows10にバージョンアップしたのですが、
 クリップボードに文字を貼り付けられなくなってました。エクセルはExcel2013を使用してます。
 Debug.Print Join(AryTxt, vbCrLf)は表示されるのになぜ?
 '****************************************
  With GetObject("new:" & DataObjectID)
      .SetText Join(AryTxt, vbCrLf)
      .PutInClipboard
  End With
 '****************************************
 の部分で、クリップボードにうまく貼り付いていないみたいです。
 貼り付けても「??」の文字が貼り付くのみでした。
 ★Windows10で、クリップボードに文字を貼り付けるやりかた、分かる方がおられましたら、
 ご教授願います。「SetText」と「PutInClipboard」は使えないみたいです??

 VBのScript(txtに文字を書き込んだ後、拡張子をvbsに変えて実行できるScript)では、
 '**************************************************************
 Dim cmd , str
 cmd = "cmd.exe /c ""echo あいうえお| clip"""
 CreateObject("WScript.Shell").Run cmd, 0, False
 '**************************************************************
 で、コマンドプロンプトを経由して、クリップボードに、「あいうえお」を書き込めました。
 知識不足で、断念しました。

 過去にβさんも同じようなことを言っていました。
[[20160326092004]]
 『xl2013 での momoさんのレイアウトアップユーティリティ』(β) 

 そこで、クリップボードは、あきらめて
 テキストファイルに、Excelのシートレイアウトを書き込んで
 デスクトップに出力するように、momoさんのコードをいじってみました。

 '・
 '・
 '・
 '・
 '↓コードは、ココから 
 '*******************************************************************************
  '=====================================================
  ' 投稿用シートレイアウトをtxtファイルに記述
  '                    作成者(マリオ)
  '
  ' デスクトップに「txtファイルを作成」
  '=====================================================

 Option Explicit

 Sub Sheetlayout_To_Text()
 '★区切り文字
  Const BrkStr As String = "|"
  'Const BrkStr As String = "  "
  Cells.Columns.AutoFit

 '--------- セル範囲を選択する ----------------------------------------------------
  Dim myRng As Range, rngFormula As Range, rngBuf As Range, msg As String
  Dim tbl() As Variant, AryTxt() As String, StrBuf As String
  Dim i As Long, j As Long, AryWidth() As Long, LenBuf As Long, flag_num As Integer
      flag_num = 0
     '****************************************************
      On Error GoTo myError
         msg = "取得したい範囲を選択してください。"
         Set myRng = Application.InputBox(msg, Type:=8)
      On Error GoTo 0
     '****************************************************
      msg = "数式として表示したい範囲はありますか?"
  If MsgBox(msg, vbYesNo) = vbYes Then
    Do
     '****************************************************
      On Error GoTo myError
      msg = "数式として表示したい範囲を選択してください。"
      Set rngBuf = Application.InputBox(msg, Type:=8, Default:=myRng.Address)
      On Error GoTo 0
     '****************************************************
      If rngFormula Is Nothing Then
        Set rngFormula = rngBuf
      Else
        Set rngFormula = Application.Union(rngFormula, rngBuf)
      End If
      Set rngBuf = Nothing
      msg = "さらに数式として表示したい範囲がありますか?"
    Loop While MsgBox(msg, vbYesNo) = vbYes
  End If
 '------------------------------------------------------------------------

 '------------ 文字列操作 -----------------------------------------------------------------
  ReDim tbl(1 To myRng.Rows.Count, 1 To myRng.Columns.Count)
  ReDim AryWidth(1 To UBound(tbl, 2))
  For i = 1 To myRng.Rows.Count
    For j = 1 To myRng.Columns.Count
      tbl(i, j) = myRng.Cells(i, j).Text
      If Not rngFormula Is Nothing Then
        If Not Application.Intersect(myRng.Cells(i, j), rngFormula) Is Nothing Then
          tbl(i, j) = myRng.Cells(i, j).Formula
        End If
      End If
      LenBuf = Application.Evaluate("LENB(""" & Replace(tbl(i, j), """", vbTab) & """)")
      If AryWidth(j) < LenBuf Then
        AryWidth(j) = LenBuf
      End If
    Next j
  Next i
  ReDim AryTxt(UBound(tbl, 1))
  AryTxt(0) = String(Len(myRng.Rows(myRng.Rows.Count).Row) + 3, " ")
  For i = 1 To UBound(tbl, 2)
    StrBuf = "[" & Split(myRng.Columns(i).EntireColumn.Address(False, False), ":")(0) & "]"
    If AryWidth(i) > Len(StrBuf) Then
      AryTxt(0) = AryTxt(0) & BrkStr & StrBuf & String(AryWidth(i) - Len(StrBuf), " ")
    Else
      AryTxt(0) = AryTxt(0) & BrkStr & StrBuf
      AryWidth(i) = Len(StrBuf)
    End If
  Next i
  For i = 1 To UBound(tbl, 1)
    AryTxt(i) = " [" & myRng.Rows(i).Row & "]" & _
                String(Len(myRng.Rows(myRng.Rows.Count).Row) - Len(myRng.Rows(i).Row), " ")
    For j = 1 To UBound(tbl, 2)
      LenBuf = Application.Evaluate("LENB(""" & Replace(tbl(i, j), """", vbTab) & """)")
      If IsNumeric(tbl(i, j)) Then
        AryTxt(i) = AryTxt(i) & BrkStr & String(AryWidth(j) - LenBuf, " ") & tbl(i, j)
      Else
        AryTxt(i) = AryTxt(i) & BrkStr & tbl(i, j) & String(AryWidth(j) - LenBuf, " ")
      End If
    Next j
  Next i
 '----------------------------------------------------------------------------------------

 '------- Desktopにtxtファイルを作成して、テキストを書き込む ------
  Dim fname As String, fso, objTxtfil, objShells, Path
  Dim rc As Integer, msg2 As String
  fname = "Excel - Sheetlayout.txt" '★ファイル名
  Set fso = CreateObject("Scripting.FileSystemObject")
  Set objShells = CreateObject("WScript.Shell")
  Path = objShells.SpecialFolders("Desktop") & "\" & fname

  If fso.FileExists(Path) = True Then
     msg = " 既に、同名ファイルが存在します"
     msg2 = "上書きしますか?" _
            & vbCr & vbCr & Path
     rc = MsgBox(msg2, vbOKCancel, msg)
     If rc = vbCancel Then
        GoTo myError
     Else
        flag_num = 2
     End If
  Else
        flag_num = 1
  End If

  Set objTxtfil = fso.CreateTextFile(Path, 2, True)
  objTxtfil.Write Join(AryTxt, vbCrLf)
  objTxtfil.Close
 '-----------------------------------------------------------------

 If flag_num = 2 Then
    msg = "上書きしました"
 ElseIf flag_num = 1 Then
    msg = "新規作成しました"
 End If
 rc = MsgBox(Path, vbOKOnly, msg)

myError:

  If flag_num = 0 Then
     MsgBox "何もせずに終了します"
  End If
  Set myRng = Nothing
  Set rngBuf = Nothing
  Set rngFormula = Nothing
  Set fso = Nothing
  Set objShells = Nothing
  Set objTxtfil = Nothing
 End Sub
 '*******************************************************************************
 '↑コードは、ココまで

< 使用 Excel:Excel2013、使用 OS:Windows10 >


 マリオさん

 ご健在のようで何よりです。

 いつかはMSが対応してくれるかなと思っていましたが、まだ同じ現象になるんですね。

 当方、[[20160326092004]] でも触れましたけど、必要な時には Win7(xl2010)側で処理していたんですが、あまりにも面倒なので
 当該部分を API 対応 したものに切り替えて使っています。

 ★ただし、私の場合、win8.1(xl2013) で、すでにだめでした。

 コードはネットで拾ったものなので、ここに掲載していいのかどうか、悩みますが、でも、ネットでも
 無断流用掲載はダメ ということは書いてなかった(ような記憶)ので以下に書いておきます。

 (本来は URL を紹介すべきでしょうけど、どれだったかがわからなくなっていて・・)

 まず、momoさんのコードの最後の部分、

  With GetObject("new:" & DataObjectID)
    .SetText Join(AryTxt, vbCrLf)
    .PutInClipboard
  End With

 これを

    CopyText Join(AryTxt, vbCrLf)

 に変更。

 で、別モジュールを挿入して、

 Private Declare Function OpenClipboard Lib "user32" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32" () As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function SetClipboardData Lib "user32" (ByVal uFormat As Long, ByVal hData As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal uFlag As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
'本来はC言語用の文字列コピーだが、2つ目の引数をStringとしているので変換が行われた上でコピーされる。
Private Declare Function lstrcpy Lib "kernel32" Alias "lstrcpyA" (ByVal lpString1 As Long, ByVal lpString2 As String) As Long

 '定数宣言
Private Const GMEM_MOVEABLE As Long = &H2
Private Const GMEM_ZEROINIT As Long = &H40
Private Const GHND As Long = (GMEM_MOVEABLE Or GMEM_ZEROINIT)
Private Const CF_TEXT As Long = 1
Private Const CF_OEMTEXT As Long = 7

 Function CopyText(str As String) As Boolean
    Dim hGlobal As Long
    Dim length As Long
    Dim p As Long

    '戻り値をとりあえず、Falseに設定しておく。
    CopyText = False
    If OpenClipboard(0) <> 0 Then
        If EmptyClipboard() <> 0 Then
            '長さの算出(本来はUnicodeから変換後の長さを使うほうがよい)
            length = LenB(str) + 1
            'コピー先の領域確保
            hGlobal = GlobalAlloc(GHND, length)
            p = GlobalLock(hGlobal)
            '文字列をコピー
            Call lstrcpy(p, str)
            'クリップボードに渡すときにはUnlockしておく必要がある
            Call GlobalUnlock(hGlobal)
            'クリップボードへ貼り付ける
            Call SetClipboardData(CF_TEXT, hGlobal)
            'クリップボードをクローズ
            Call CloseClipboard
            'コピー成功
            CopyText = True
        End If
    End If
End Function

(β) 2017/01/16(月) 06:59


 >>βさん
 すごい、クリップボードに貼り付きました。
 コード、ありがとうございます。

(マリオ) 2017/01/21(月) 20:29


 最後のほうの、momoさんのコードでいえば

  With GetObject("new:" & DataObjectID)
    .SetText Join(AryTxt, vbCrLf)
    .PutInClipboard
  End With

 マリオさんがまとめてくれている Sheetlayout_To_ClipBoard でいえば

  CopyText Join(AryTxt, vbCrLf) と 別モジュールの組み合わせ に加え

 以下のようなコードでもコピペができますね。

    With ActiveSheet.OLEObjects.Add("Forms.TextBox.1")
        With .Object
        .MultiLine = True
        .Value = Join(AryTxt, vbCrLf)
        .SelStart = 0
        .SelLength = .TextLength
        .Copy
        End With
        .Delete
    End With

(β) 2017/02/13(月) 00:09


 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
 ファイルを置いておきます。
 ■シートレイアウト To Text_To ClipBord_02.xls 
http://d.kuku.lu/f4c13f676f
 ★アゲマシタ(2017/03/3 19:44)
 〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓
(マリオ) 2017/03/03(金) 19:47

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.