C# と VB.NET の質問掲示板

わんくま同盟

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

ツリー一括表示

リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/21(Mon) 16:15) #89928
Re[1]: リッチテキストボックスでカラー情報をコピーする方法 /とっちゃん (19/01/21(Mon) 16:29) #89929
│└ Re[2]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/21(Mon) 18:26) #89930
│  └ Re[3]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/22(Tue) 18:53) #89939
│    └ Re[4]: リッチテキストボックスでカラー情報をコピーする方法 /Azulean (19/01/23(Wed) 06:41) #89940
│      └ Re[5]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/23(Wed) 10:52) #89947
Re[1]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/23(Wed) 06:59) #89941
Re[1]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/27(Sun) 13:31) #89980
  └ Re[2]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/27(Sun) 13:49) #89981
    ├ Re: リッチテキストボックスでカラー情報をコピーする方法 /ユーフォー (19/01/28(Mon) 15:30) #89986
    └ Re[3]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/28(Mon) 17:06) #89988
      └ Re[4]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/28(Mon) 17:32) #89989
        └ Re[5]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/28(Mon) 19:05) #89991
          └ Re[6]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/28(Mon) 19:13) #89992
            └ Re[7]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/28(Mon) 19:44) #89993
              └ Re[8]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/28(Mon) 20:16) #89994
                └ Re[9]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/28(Mon) 20:33) #89995
                  └ Re[10]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/29(Tue) 10:54) #89998
                    └ Re[11]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/29(Tue) 12:24) #90000
                      └ Re[12]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/29(Tue) 12:41) #90001
                        ├ Re[13]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/29(Tue) 12:45) #90002
                        └ Re[13]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/29(Tue) 13:11) #90004
                          └ Re[14]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/29(Tue) 14:02) #90005
                            └ Re[15]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/29(Tue) 14:24) #90006
                              └ Re[16]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/29(Tue) 14:44) #90007
                                └ Re[17]: リッチテキストボックスでカラー情報をコピーする方法 /魔界の仮面弁士 (19/01/29(Tue) 15:57) #90008
                                  └ Re[18]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/01/30(Wed) 12:30) #90011
                                    └ Re[19]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/02/07(Thu) 13:26) #90086
                                      └ Re[20]: リッチテキストボックスでカラー情報をコピーする方法 /イエメン (19/02/07(Thu) 13:28) #90087


親記事 / ▼[ 89929 ] ▼[ 89941 ] ▼[ 89980 ]
■89928 / 親階層)  リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (1回)-(2019/01/21(Mon) 16:15:06)

分類:[.NET 全般] 

Excel上でセル内の文字列の一部の色を別に変えた状態で
セルをコピーしWord上にペーストすると
その色情報や下線、ボールドなどのフォント情報を保持したまま
貼り付けることができます。

しかし、VBで作成したプログラムの
リッチテキストボックス上で同じことをしようとしても
これらの情報を保持されず、
文字しかペーストされません、

どうすればカラーなどの情報も同時に貼り付けることができますか?


[ □ Tree ] 返信 編集キー/

▲[ 89928 ] / ▼[ 89930 ]
■89929 / 1階層)  Re[1]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ とっちゃん (571回)-(2019/01/21(Mon) 16:29:10)
No89928 (イエメン さん) に返信
> どうすればカラーなどの情報も同時に貼り付けることができますか?
>
Paste( DataFormats.Rtf ) はどうでしょうか?


[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89929 ] / ▼[ 89939 ]
■89930 / 2階層)  Re[2]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (3回)-(2019/01/21(Mon) 18:26:09)
ご回答ありがとうございます。

しかし、
Paste( DataFormats.Rtf )

というのはどこで使えば良いのでしょうか・・・?
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89930 ] / ▼[ 89940 ]
■89939 / 3階層)  Re[3]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (4回)-(2019/01/22(Tue) 18:53:56)
どなたかご回答ください・・・。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89939 ] / ▼[ 89947 ]
■89940 / 4階層)  Re[4]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ Azulean (1027回)-(2019/01/23(Wed) 06:41:42)
2019/01/23(Wed) 06:46:03 編集(投稿者)

No89939 (イエメン さん) に返信
> どなたかご回答ください・・・。

最近、わんくまのサーバーが不安定なようなので回答がつかないのはそういう事情があることも考慮しておいてください。


とっちゃんさんのコメントは、貼り付け処理を自作している・自作に置き換えるケースを想定されているとは思います。(実際には DataFormats.Rtf と単に書くのではなく、DataForamts.GetFormat(DataFormats.Rtf)) のようですが)
もっとも、Excel 2010 をコピー元として様子を見る限り、形式を選択して貼り付けで「リッチテキスト形式」を選んでも色がつかないので、残念ながらこの方法では解決しない模様です。

Word は形式を選択して貼り付けのデフォルトである HTML 形式での貼り付けで実現しているようです。
残念ながら RichTextBox は HTML 形式での貼り付けをサポートしていないようなので、自分でクリップボードの中身を解釈し、RichTextBox.Rtf プロパティに設定する…といった非現実的な作業が必要なので「諦める」が第一選択肢になると思われます。

// https://stackoverflow.com/questions/2627991/how-to-show-html-contents-with-a-richtextbox みたいな力業…?
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89940 ] / 返信無し
■89947 / 5階層)  Re[5]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2018回)-(2019/01/23(Wed) 10:52:43)
2019/01/23(Wed) 12:01:15 編集(投稿者)

No89928 (イエメン さん) に返信
> どうすればカラーなどの情報も同時に貼り付けることができますか?

(案1)Excel からコピーした内容を Word に貼り、それを再コピーして RichTextBox に貼る

(案2)Excel の書式情報(Biff12 等)を解析して Rtf 書式に再構築するコードを自力実装する

(案3)Excel オートメーションで、一文字ずつ書式情報を読み取って処理していく
 http://hanatyan.sakura.ne.jp/vbhlp/Excel13.htm

(案4)有償/無償の RTF コンバーターを探してきて利用する
 https://www.sautinsoft.com/convert-excel-xls-to-pdf/xlsx-to-rtf-dotnet-csharp.php
 https://convertio.co/ja/xlsx-rtf/



No89940 (Azulean さん) に返信
> Excel 2010 をコピー元として様子を見る限り、形式を選択して貼り付けで「リッチテキスト形式」を選んでも色がつかない

こんな情報もあったので、Excel のバージョンを上げれば
マシになるかな…と思いきや、やっぱり駄目でした。無念。

『Excel 2016 でリッチ テキストを使用すると、文字書式設定が失われる』
「この問題は、バージョン 1708 (8431.2109) で修正されています。」
https://support.office.com/ja-jp/article/e0536ed1-b339-45fa-b665-917fe165d957


とりあえず、手持ちの Excel 2016 ver1812 でコピー操作を行ってみて、
その時にクリップボードに送られる形式を調べてみました。
先頭の○×は、RichTextBox に貼ることができるかどうかを示したものです。


クリップボード内容の確認には、フリーソフトの「クリップ見え窓」を利用しました。



《色情報を含むが、OLE 埋め込みや OLE リンクになるもの》
○ "Embed Source" ※ 貼り付け後にダブルクリックすると編集用の Excel が起動する
○ "Link Source" ※ コピー元の Excel ファイルを編集すると RichTextBox 側も自動で書き換わる


《色情報を含むが、画像形式となってしまうもの》
△ "EnhancedMetafile" (CF_ENHMETAFILE = 14) ※ 拡張メタファイル形式。
○ "MetfaFilePict" (CF_METAFILEPICT = 3) ※ メタファイル形式。
× "Bitmap" (CF_BITMAP = 2) ※ ビットマップ形式。System.Drawing.Bitmap として得られた。


《色情報を含められる形式だが、色情報が記録されていなかった物》
○ "Rich Text Format"


《色情報を含む形式で、色情報が記録されていた物》
× "SymblicLink" (CF_SYLK = 4) ※ Microsoft SYLK 形式。
× "Biff12" ※ Excel 2007 形式。
× "Biff8" ※ Excel 97〜2003 形式。
× "Biff5" ※ Excel 95 形式。
× "XML Spreadsheet" ※ Office XML 形式。
× "HTML Format" ※ HTML 形式。


《そもそも色情報を含まない形式の物》
× "DataInterchangeFormat" (CF_DIF = 5) ※ VisiCalc 形式。
○ "UnicodeText" (CF_UNICODETEXT = 13) ※ UTF-16 なタブ区切りテキスト。
○ "Text" (CF_TEXT = 1) ※ 既定のコードページによるタブ区切りテキスト。
× "Csv" ※ ANSI コードページによるカンマ区切りテキスト。


《その他の形式》
× "DataObject"
× "Hyperlink"
× "Object Descriptor"
× "Link Source Descriptor"
× "Link"
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89928 ] / 返信無し
■89941 / 1階層)  Re[1]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2017回)-(2019/01/23(Wed) 06:59:05)
2019/01/23(Wed) 07:00:41 編集(投稿者)

No89928 (イエメン さん) に返信
> これらの情報を保持されず、
> 文字しかペーストされません、

Excel / Word / RichTextBox それぞれに対して、Ctrl + C で『コピー』を行い、
その直後、下記のコードを実行してみてください。

クリップボード内に、どの形式のデータがどの順番で保持されているかを
DataGridView 上に簡易列挙させるためのコードです。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
 Dim data = Clipboard.GetDataObject()
 DataGridView1.DataSource = data.GetFormats(False).ToDictionary(Function(s) s, Function(s) data.GetData(s)).ToArray()
End Sub


これにより、各アプリケーションが、どのフォーマットを「コピー」するのかを把握したら、
次に、『ペースト』先のアプリケーションが、どの形式のデータをサポートしているかを
調査していきます。(たとえば、メモ帳に画像は貼れないですよね)


RichTextBox の場合、サポート可能な形式かどうかを CanPaste メソッドで判定できます。
そして「形式を指定して貼り付け」のために、引数付の Paste メソッドが用意されています。


先のコードに下記を加えてみます。上記のコードで DataGridView にクリップボード内のデータを
展開したのち、DataGridView のセルをダブルクリックすると、該当行のデータが
RichTextBox の CanPaste / Paste メソッドを通じてペーストされるようにしています。

Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellContentDoubleClick
 Dim fmtName = CStr(DataGridView1("Key", e.RowIndex).Value)
 Dim fmt = DataFormats.GetFormat(fmtName)
 If Not RichTextBox1.CanPaste(fmt) Then
  MessageBox.Show("サポートされていない形式です。:" & fmtName, "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
 Else
  Clipboard.Clear()
  Clipboard.SetData(fmtName, DataGridView1("Value", e.RowIndex).Value)
  Application.DoEvents()
  RichTextBox1.Paste(fmt)
  MessageBox.Show("ペーストしました。", "", MessageBoxButtons.OK, MessageBoxIcon.Information)
 End If
End Sub


> Excel上でセル内の文字列の一部の色を別に変えた状態で
> セルをコピーしWord上にペーストすると

これは、Excel のデータを Word に貼る場合の話ですね。
Excel のバージョンによって、クリップボードに送られるフォーマットに差があります。


> しかし、VBで作成したプログラムの
> リッチテキストボックス上で同じことをしようとしても

「同じこと」が何を指しているのか曖昧ですね。(^^;

RichTextBox のデータを RichTextBox に貼るのでしょうか。
Excel のデータを RichTextBox に貼るのでしょうか。
Word のデータを RichTextBox に貼るのでしょうか。
RichTextBox のデータを Excel に貼るのでしょうか。
RichTextBox のデータを Word に貼るのでしょうか。
それとも…?
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89928 ] / ▼[ 89981 ]
■89980 / 1階層)  Re[1]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2021回)-(2019/01/27(Sun) 13:31:51)
No89928 (イエメン さん) に返信
> どうすればカラーなどの情報も同時に貼り付けることができますか?

VB ではなく C# ですが、No78716 に類似のやり取りがあったので紹介しておきます。

> エクセルのセルに設定された文字列の取得で、文字毎の色まで取り込みたいです。
> 最終的にはRichTextBoxに表示できればよいのですが。

http://bbs.wankuma.com/index.cgi?mode=al2&namber=78716&KLOG=133
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89980 ] / ▼[ 89986 ] ▼[ 89988 ]
■89981 / 2階層)  Re[2]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (5回)-(2019/01/27(Sun) 13:49:21)
ありがとうございます。

まだ、他のコードを試すことができていませんが、
とりあえず、このコードなら一発でできそうなので
試してみました

VBに翻訳してみたのですが、


    Private Sub Button11_Click(sender As Object, e As EventArgs) Handles Button11.Click


        Dim wApp = Activator.CreateInstance(Type.GetTypeFromProgID("Word.Application"))
        Dim docs = wApp.Documents
        Dim doc = docs.Add()
        Dim rngWord = doc.Range

        Clipboard.Clear()
        rngExcel.Copy

        rngWord.PasteExcelTable(LinkedToExcel:=False, WordFormatting:=False, RTF:=False)
        rngWord.Copy

        RichTextBox1.Paste(DataFormats.GetFormat(DataFormats.Rtf))

        Marshal.ReleaseComObject(rngWord)
        Marshal.ReleaseComObject(doc)
        Marshal.ReleaseComObject(docs)
        Dim oApp As Object = wApp
        wApp.Quit(SaveChanges:=False)
        Marshal.FinalReleaseComObject(oApp)




    End Sub




        Dim docs = wApp.Documents
        wApp.Quit(SaveChanges:=False)
のところで、Option Strict Onでは遅延バインディングを使用できません
というエラーが出ます。
rngExcel
が宣言されていないので
rngExcel.Copy
でもエラーが出ます

どのように改善したら宜しいでしょうか?


[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89981 ] / 返信無し
■89986 / 3階層)  Re: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ ユーフォー (1回)-(2019/01/28(Mon) 15:30:06)
2019/01/28(Mon) 16:25:36 編集(投稿者)

メッセージの通りです。
遅延バインディングを使用する場合は、Option Strict Offにする必要があります。
プロジェクトでOption Strict Onにしている場合は対象VBファイルの先頭にOption Strict Offと書けばよいです。
プロジェクトでOption Strict Onにしていない場合は、VBファイル先頭にOption Strict OnがなければOKです。

後、rngExcelについては、恐らく、魔界の仮面弁士様が例示した質問では元からExcelが開いていたのでしょう。
ちょっと僕では今回の例でExcelがどのように使われるか分からないので、仮面様の書き込みを待ちましょうか...
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89981 ] / ▼[ 89989 ]
■89988 / 3階層)  Re[3]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2023回)-(2019/01/28(Mon) 17:06:46)
No89981 (イエメン さん) に返信
> VBに翻訳してみたのですが、

これでどうでしょう。


Option Explicit On
Imports System.Runtime.InteropServices
Public Class Form1

 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
  Dim oldCursor = Cursor.Current
  Cursor.Current = Cursors.WaitCursor

  ' クリップボードの内容確認
  Dim cb = Clipboard.GetDataObject()
  Dim fmt = cb.GetFormats(False).FirstOrDefault(Function(f) f Like "Biff#")

  If String.IsNullOrEmpty(fmt) Then
   ' Excel 書式ではないので、そのまま貼り付け
   RichTextBox1.Paste()
  Else
   Dim oldCaption = Text
   Text = "Excel 書式の取得中..."

   ' Excel 書式を維持するため、Word 経由で貼り付け
   Dim wApp As Object = Nothing
   Dim wDocs As Object = Nothing
   Dim wDoc As Object = Nothing
   Dim wRng As Object = Nothing
   Try
    wApp = CreateObject("Word.Application")
    wDocs = CallByName(wApp, "Documents", CallType.Get)
    wDoc = CallByName(wDocs, "Add", CallType.Method)
    wRng = CallByName(wDoc, "Range", CallType.Method)
    CallByName(wRng, "PasteExcelTable", CallType.Method, False, False, False)
    CallByName(wRng, "Copy", CallType.Method)
    Try
     RichTextBox1.Paste(DataFormats.GetFormat(DataFormats.Rtf))
    Catch
     RichTextBox1.Paste()
    End Try
   Catch
   Finally
    If wRng IsNot Nothing AndAlso Marshal.IsComObject(wRng) Then Marshal.ReleaseComObject(wRng)
    If wDoc IsNot Nothing AndAlso Marshal.IsComObject(wDoc) Then Marshal.ReleaseComObject(wDoc)
    If wDocs IsNot Nothing AndAlso Marshal.IsComObject(wDocs) Then Marshal.ReleaseComObject(wDocs)
    If wApp IsNot Nothing AndAlso Marshal.IsComObject(wApp) Then
     CallByName(wApp, "Quit", CallType.Method, False)
     Marshal.FinalReleaseComObject(wApp)
    End If
   End Try
   Text = oldCaption
  End If

  Cursor.Current = oldCursor
 End Sub
End Class
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89988 ] / ▼[ 89991 ]
■89989 / 4階層)  Re[4]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (6回)-(2019/01/28(Mon) 17:32:03)
素晴らしいコードをありがとうございます。
ばっちりうまくいきました。

ところで、ExcelのデータをRichTextBoxに貼り付けた後、
そのテキストの一部をCtrl+cでコピーし再度フォーマットを保ったままで
Excelに貼り付けたいのですがフォーマットが維持されません。
Wordには貼り付けられるのですが・・・
この場合もWord経由で貼り付ける必要があるのでしょうか?

できればコードを提示いただけないでしょうか?
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89989 ] / ▼[ 89992 ]
■89991 / 5階層)  Re[5]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2025回)-(2019/01/28(Mon) 19:05:20)
No89989 (イエメン さん) に返信
> ばっちりうまくいきました。
残念ながら、条件付き書式は受け継がれないようですけれどね。


> ところで、ExcelのデータをRichTextBoxに貼り付けた後、
> そのテキストの一部をCtrl+cでコピーし再度フォーマットを保ったままで
> Excelに貼り付けたいのですがフォーマットが維持されません。

Excel 側が RTF フォーマットをサポートしていないので、
プレーンテキストで貼りついてしまう模様。

"HTML Format" 形式のデータを設けてやれば、Excel 側に書式情報を届けられましたが、
やはり自前で処理するのは面倒そう……。

Dim htmlBinary As Byte() = 『RichTextBox1 の選択範囲を "HTML Format" 化した UTF-8 バイナリ』
Clipboard.Clear()
Clipboard.SetData(DataFormats.Html, New System.IO.MemoryStream(htmlBinary))



> この場合もWord経由で貼り付ける必要があるのでしょうか?
> できればコードを提示いただけないでしょうか?

ということで、毎度おなじみ Word 経由で。

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
 Dim oldCursor = Cursor.Current
 Cursor.Current = Cursors.WaitCursor

 Clipboard.Clear()
 RichTextBox1.Copy()

 Dim oldCaption = Text
 Text = "Excel 書式の取得中..."

 ' Excel 書式を維持するため、Word 経由で複写
 Dim wApp As Object = Nothing
 Dim wDocs As Object = Nothing
 Dim wDoc As Object = Nothing
 Dim wRng As Object = Nothing
 Try
  wApp = CreateObject("Word.Application")
  wDocs = CallByName(wApp, "Documents", CallType.Get)
  wDoc = CallByName(wDocs, "Add", CallType.Method)
  wRng = CallByName(wDoc, "Range", CallType.Method)
  CallByName(wRng, "Paste", CallType.Method)
  CallByName(wRng, "Copy", CallType.Method)
 Catch
 Finally
  If wRng IsNot Nothing AndAlso Marshal.IsComObject(wRng) Then Marshal.ReleaseComObject(wRng)
  If wDoc IsNot Nothing AndAlso Marshal.IsComObject(wDoc) Then Marshal.ReleaseComObject(wDoc)
  If wDocs IsNot Nothing AndAlso Marshal.IsComObject(wDocs) Then Marshal.ReleaseComObject(wDocs)
  If wApp IsNot Nothing AndAlso Marshal.IsComObject(wApp) Then
   CallByName(wApp, "Quit", CallType.Method, False)
   Marshal.FinalReleaseComObject(wApp)
  End If
 End Try
 Text = oldCaption
 Cursor.Current = oldCursor
End Sub
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89991 ] / ▼[ 89993 ]
■89992 / 6階層)  Re[6]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (7回)-(2019/01/28(Mon) 19:13:43)
ありがとうございます。

試してみたのですが、
なぜか不思議な挙動をします。

Excelのセルをコピー(ABCDEFGH)
RichTextBoxにペースト
RichTextBoxの一部を選択しコピー(CDEF)
そして、Excel上でペーストしても、(CDEF)ではなく(ABCDEFGH)となってしまいます。
再度、RichTextBoxで文字列を選択しなおし、
Excel上にペーストすると2回目だとうまくいきます。

1回目であっても、Excelだとうまくいきませんが、
同じくRichTextBox上だと正常にペーストできます。

これは一体なぜなのでしょうか?




[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89992 ] / ▼[ 89994 ]
■89993 / 7階層)  Re[7]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2026回)-(2019/01/28(Mon) 19:44:08)
No89992 (イエメン さん) に返信
> 試してみたのですが、
> なぜか不思議な挙動をします。

電車移動中で、手元に試せる環境が無いのですが、
コピー元のエクセルが、コピー中の状態(セルが点滅する破線で囲まれた状態)になっていないでしょうか。
※Excel の 2017/05 月次更新版で仕様変更があった気がしますが、うろ覚え。

もし点滅破線が表示されていたら、Excel データを Word / RichTextBox に貼った後で、Excel 上で Esc キーを押してコピー状態をキャンセルしてみてください。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89993 ] / ▼[ 89995 ]
■89994 / 8階層)  Re[8]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (9回)-(2019/01/28(Mon) 20:16:26)
仰るとおり、Escキーを押すとうまくペーストできました。
ただ、コピーする前に押さないといけないのですね。

できれば、このExcelのコピー状態をキャンセルすることも
プログラム上でできないでしょうか?

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89994 ] / ▼[ 89998 ]
■89995 / 9階層)  Re[9]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2027回)-(2019/01/28(Mon) 20:33:17)
No89994 (イエメン さん) に返信
> このExcelのコピー状態をキャンセルすることも
> プログラム上でできないでしょうか?

コピー元 Excel の CutCopyMode プロパティに False を代入してみてください。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89995 ] / ▼[ 90000 ]
■89998 / 10階層)  Re[10]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (10回)-(2019/01/29(Tue) 10:54:50)
ありがとうございます。


Dim xlApp = CreateObject("Excel.Application")
CallByName(xlApp, "CutCopyMode", CallType.Method, False)

これをどこかに入れれば良いのでしょうか?

Clipboard.Clear()の前に入れるとエラーが出て実行できず、
Tryの後に入れると、エラーは出ないけれど
コピー状態をキャンセルできないのですが、

どのようにしたら良いですか?

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 89998 ] / ▼[ 90001 ]
■90000 / 11階層)  Re[11]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2029回)-(2019/01/29(Tue) 12:24:57)
No89998 (イエメン さん) に返信
> Dim xlApp = CreateObject("Excel.Application")
起動済みのインスタンスを拾うので、
 Dim xlApp = GetObject( , "Excel.Application")
にしておいてください。

GetObject がエラーになる場合は、そもそも Excel が起動していない状態なので
その場合はそもそも、CutCopyMode を操作する必要がありません。


もしも複数の Excel.Application インスタンスが生成されていた場合には、
それらを区別して取得するために、IRunningObjectTable から得る必要が
あるかも知れませんが……大抵は GetObject だけでなんとかなるはず。



> CallByName(xlApp, "CutCopyMode", CallType.Method, False)
それだと
 xlApp.CutCopyMode(False)
相当の意味になってしまいますね。

必要なのは
 xlApp.CutCopyMode = False
に相当する呼び出しなので、Option Strict On で書くなら
 CallByName(xlApp, "CutCopyMode", CallType.Let, False)
です。

処理後は xlApp の COM オブジェクト解放も忘れずに。



> これをどこかに入れれば良いのでしょうか?
「Excel からコピーして Word に貼り付けた後」もしくは
「RichTextBox からコピーして Word に貼り付ける前」のタイミングですかね。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90000 ] / ▼[ 90002 ] ▼[ 90004 ]
■90001 / 12階層)  Re[12]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (12回)-(2019/01/29(Tue) 12:41:07)
ありがとうございます。


RichTextBox1.Copy()
の後に

Dim xlApp = GetObject(, "Excel.Application")
CallByName(xlApp, "CutCopyMode", CallType.Let, False)
If xlApp IsNot Nothing AndAlso Marshal.IsComObject(xlApp) Then Marshal.ReleaseComObject(xlApp)

を入れたのですが、
コピーすることで、Excel上でセルを選択している表示は解除されることを確認できました。
しかし、Excel上でペーストしてもデータが代入されません、

再度、コピーをやり直すとうまくいくのですが・・・

なぜ1回でうまくいかないのでしょうか?

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90001 ] / 返信無し
■90002 / 13階層)  Re[13]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (13回)-(2019/01/29(Tue) 12:45:09)

Clipboard.Clear()
の前に入れたところ、
1回目で文字列は代入されるようになったのですが、
カラーフォントなどがペーストされず、書式無しの文字列になってしまいます。

そして2回目ペーストすると今度はなぜかうまくいくのですが・・・
一体なぜでしょうか?
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90001 ] / ▼[ 90005 ]
■90004 / 13階層)  Re[13]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2030回)-(2019/01/29(Tue) 13:11:26)
No90001 (イエメン さん) に返信
> コピーすることで、Excel上でセルを選択している表示は解除されることを確認できました。
> しかし、Excel上でペーストしてもデータが代入されません、

Excel に対する CutCopyMode のキャンセル処理と
RichTextBox からのコピー処理を、
同じイベント内に続けて記載していませんか?

メッセージループが回らないと、クリップボードは処理されませんので、
CutCopyMode を操作するためのボタンだけを、単独で配置してみてください。


一回のボタン操作で行われるようにしたいのなら、
CutCopyMode を操作した後のクリップボード処理を遅延実行させてみてください。

たとえば Application.Idle イベントで処理させるようにするとか、
Control.BeginInvoke なり Task.ContinueWith メソッドなりに分けるとか。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90004 ] / ▼[ 90006 ]
■90005 / 14階層)  Re[14]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (14回)-(2019/01/29(Tue) 14:02:16)
ありがとうございます。

Thread.Sleep(100)
を入れるとうまくいきました。

ただ、文字列のサイズによっては100 msecでは足りない時があるかも知れません。

ちなみになのですが

たとえば Application.Idle イベントで処理させるようにするとか、
Control.BeginInvoke なり Task.ContinueWith メソッドなりに分けるとか。

これらはどのようにして使用するものなのでしょうか?
この方法なら、操作が終わるまで待機するようなことが可能なのでしょうか?

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90005 ] / ▼[ 90007 ]
■90006 / 15階層)  Re[15]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2031回)-(2019/01/29(Tue) 14:24:48)
2019/01/29(Tue) 14:28:45 編集(投稿者)

No90005 (イエメン さん) に返信
> Thread.Sleep(100)
> を入れるとうまくいきました。

UI スレッドで Sleep を呼びだすことは避けてください。



> これらはどのようにして使用するものなのでしょうか?

たとえば BeginInvoke ならこうかな。
掲示板に直接書いたので未検証ですけど。


Private Sub ButtonX_Click(…
 Dim oldCursor = Cursor.Current
 Cursor.Current = Cursors.WaitCursor

 Dim xlApp As Object = Nothing
 Try
  xlApp = GetObject(, "Excel.Application")
  CallByName(xlApp, "CutCopyMode", CallType.Let, False)
 Catch
 Finally
  If xlApp IsNot Nothing AndAlso Marshal.IsComObject(xlApp) Then Marshal.ReleaseComObject(xlApp)
 End Try
 BeginInvoke(Sub()
  Try
   Clipboard.Clear()
   RichTextBox1.Copy()

   Dim wApp As Object = Nothing
   '中略
   Try
    wApp = CreateObject("Word.Application")
    '中略
    CallByName(wRng, "Paste", CallType.Method)
    CallByName(wRng, "Copy", CallType.Method)
   Catch
   Finally
    '中略
   End Try
  Catch
  Finally
   Cursor.Current = oldCursor
  End Try
 End Sub)
End Sub
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90006 ] / ▼[ 90008 ]
■90007 / 16階層)  Re[16]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (15回)-(2019/01/29(Tue) 14:44:40)
ありがとうございます。

以下のようにしてみましたが、やはり1回目ではうまくいかず2回ペーストする必要があります。

BeginInvokeは非同期でバックグラウンドプロセスからフォアグラウンドプロセスに指令を投げるものだと思いますが、
GUIから使っても良いのでしょうか?
そして、それで遅延が発生するのでしょうか?

            Dim oldCursor = Cursor.Current
            Cursor.Current = Cursors.WaitCursor

            Dim xlApp As Object = Nothing
            Try
                xlApp = GetObject(, "Excel.Application")
                CallByName(xlApp, "CutCopyMode", CallType.Let, False)
            Catch
            Finally
                If xlApp IsNot Nothing AndAlso Marshal.IsComObject(xlApp) Then Marshal.ReleaseComObject(xlApp)
            End Try
            BeginInvoke(Sub()

                            Clipboard.Clear()
                            RichTextBox1.Copy()


                            ' Excel 書式を維持するため、Word 経由で複写
                            Dim wApp As Object = Nothing
                            Dim wDocs As Object = Nothing
                            Dim wDoc As Object = Nothing
                            Dim wRng As Object = Nothing

                            Try

                                wApp = CreateObject("Word.Application")
                                wDocs = CallByName(wApp, "Documents", CallType.Get)
                                wDoc = CallByName(wDocs, "Add", CallType.Method)
                                wRng = CallByName(wDoc, "Range", CallType.Method)
                                CallByName(wRng, "Paste", CallType.Method)
                                CallByName(wRng, "Copy", CallType.Method)
                            Catch
                            Finally
                                If wRng IsNot Nothing AndAlso Marshal.IsComObject(wRng) Then Marshal.ReleaseComObject(wRng)
                                If wDoc IsNot Nothing AndAlso Marshal.IsComObject(wDoc) Then Marshal.ReleaseComObject(wDoc)
                                If wDocs IsNot Nothing AndAlso Marshal.IsComObject(wDocs) Then Marshal.ReleaseComObject(wDocs)
                                If wApp IsNot Nothing AndAlso Marshal.IsComObject(wApp) Then
                                    CallByName(wApp, "Quit", CallType.Method, False)
                                    Marshal.FinalReleaseComObject(wApp)
                                End If
                            End Try

                            Cursor.Current = oldCursor

                        End Sub)

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90007 ] / ▼[ 90011 ]
■90008 / 17階層)  Re[17]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ 魔界の仮面弁士 (2032回)-(2019/01/29(Tue) 15:57:06)
No90002 (イエメン さん) に返信
> 1回目で文字列は代入されるようになったのですが、
> カラーフォントなどがペーストされず、書式無しの文字列になってしまいます

うまくいかない「1 回目」の時に、クリップボード内に
"HTML Format" なデータは含まれていましたか?


"HTML Format" が含まれていない場合は、Debug.WriteLine 等を仕込んで、
Word 側の呼び出しコードが呼び出されているかどうかを確認してみてください。


"HTML Format" が含まれているのに、それでも正しく受け渡せないなら、
クリップボードの格納順や内容が、1 回目と 2 回目でどのように変化しているか
確認してみてください。


ひとまず Sleep や DoEvents を入れた方が安定するのなら、
幾許かの待機処理は入れておいた方が良いのかも。



No90007 (イエメン さん) に返信
> やはり1回目ではうまくいかず2回ペーストする必要があります。

何も貼れないときは、クリップボード操作がエラーになっているのかな…。

Word を操作しても "HTML Format" が含まれていないようなら、
Word 側へのペースト&コピーが失敗して Catch 句を通過していないかをチェックしてみてください。
※例: ExternalException (0x800401D0 = CLIPBRD_E_CANT_OPEN)

もしエラーになるようなら、引数 4 個な Clipboard.SetDataObject メソッドの実装のように、
失敗時に一定間隔で再試行するような実装を設ける必要があるかもしれません。


# 今ちょっと、試せる環境が手元に無い…。
[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90008 ] / ▼[ 90086 ]
■90011 / 18階層)  Re[18]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (16回)-(2019/01/30(Wed) 12:30:38)
また、お時間ある時に試していただけないでしょうか?
宜しくお願いいたします。



[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90011 ] / ▼[ 90087 ]
■90086 / 19階層)  Re[19]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (17回)-(2019/02/07(Thu) 13:26:16)
ちなみに、この方法だとフォントサイズをコピーすることができないのですが、
なぜでしょうか?
Excel→Word→Excelだと
うまくサイズも移行できるのですが。

[ 親 89928 / □ Tree ] 返信 編集キー/

▲[ 90086 ] / 返信無し
■90087 / 20階層)  Re[20]: リッチテキストボックスでカラー情報をコピーする方法
□投稿者/ イエメン (18回)-(2019/02/07(Thu) 13:28:34)
気のせいでした
うまくいきました

[ 親 89928 / □ Tree ] 返信 編集キー/


管理者用

- Child Tree -