Borland C++ Builder 5を使用してStringGridの内容をクリップボードにCOPYする方法

このQ&Aのポイント
  • Borland C++ Builder 5で、StringGridの内容をクリップボードにCOPYするプログラムを作成していますが、処理が非常に遅いです。
  • 現在の方法では、2,000行や3,000行といった大量のデータの場合に待たされることがあります。
  • より効率的にスマートにCOPYする方法はあるのか、教えていただきたいです。
回答を見る
  • ベストアンサー

StringGridの内容をクリップボードにCOPYしたい

Borland C++ Builder 5 を使っています。 StringGridの内容をクリップボードにCOPYするプログラムを作っています。 Excelに貼り付けるのが目的なので、Tab区切りのデータにしています。 下に示したソースで実現できましたが、非常に遅いのです。 100行とか200行ならアッという間なのですが、2,000行、3,000行となるとかなり待たされます。 時間を食っているのは(2)の部分のようです。 もう少しスマートに、短時間でCOPYしたいのですが、方法はないものでしょうか? ◆ソースの解説 StringGridの21列分を、行数だけクリップボードにCOPYします。 (1) StringGridの各行、各列をLOOPしてセルに格納されている文字列長の合計を求めます。 Tab区切りにするため、各セルごと1バイト加算します。 また、各行ごと改行を入れるため、これも1バイト加算します。 (2) 合計容量が計算できたら、メモリーを動的確保し、もう一度LOOPをしながら、文字列をCOPYします。 セルごとにTab、行ごとに改行も追加します。 (3) 最後にクリップボードをクリアしてCOPYします。 int cnt = StringGrid1->RowCount; int size = 0; //StringGridのサイズ(文字長)をカウントする ------ (1) for(i=0;i<cnt;i++){ for(k=0;k<21;k++){ size += strlen(StringGrid1->Cells[k][i].c_str()) + 1; } size++; } //メモリーを確保して、StringGridをCOPYする -------- (2) cb = new char[size]; strcpy(cb,""); for(i=0;i<cnt;i++){ for(k=0;k<21;k++){ strcat(cb,StringGrid1->Cells[k][i].c_str()); strcat(cb,"\t"); //Tab区切りの文字列にする } strcat(cb,"\n"); } Clipboard()->Clear(); // -------- (3) Clipboard()->AsText = cb; なお、サイズがintに収まるかというチェックとか、メモリーの解放をする、といったことも必要ですが、記述を省略しました。

  • CLMN
  • お礼率80% (62/77)

質問者が選んだベストアンサー

  • ベストアンサー
回答No.1

strcatで毎回連結しているようですが、質問内容のソースコードでは毎回'\0'を探し出して、その後に文字列を連結しているため処理効率が落ちてしまいます。 以下のようにしてはどうでしょう。 追加宣言 int mcnt,mlp; (2)の部分のソースコード cb = new char[size]; cb[0] = '\0'; mcnt = 0; for(i=0;i<cnt;i++){ for(k=0;k<21;k++){ for(mlp=0;mlp<strlen(StringGrid1->Cells[k][i].c_str());mlp++){ cb[mcnt] = StringGrid1->Cells[k][i].c_str()[mlp]; mcnt++; } //Tab区切りの文字列にする cb[mcnt] = '\t'; mcnt++; } //行ごとに改行する。 cb[mcnt] = '\n'; mcnt++; } //最後に'\0'を付加。 cb[mcnt] = '\0'; mcnt++; 申し訳ありませんが、試してはいません。

CLMN
質問者

お礼

hiro_knighさん、ありがとうございました。 >strcatで毎回連結しているようですが、質問内容のソースコードでは毎回'\0'を探し出して、その後に文字列を連結しているため処理効率が落ちてしまいます どうもそのようです。 試しに、次のようなstrcatのテストプログラムを作ってみました。 char Tmem[400001]=""; char moji[]="0123456789"; int i; for(i=0;i<20000;i++) strcat(Tmem,moji); 20,000回のLOOPで、約3秒かかりますが、倍の40,000回のLOOPでは、11秒もかかります。(ストップウォッチによる手動計測) 回数を倍にしただけなのに、時間は4倍弱掛かっています。 '\0'を探し出すのに時間が掛かっているようです。 アドバイスを参考に、kのLOOPを次のようにしました。 len = strlen(StringGrid1->Cells[k][i].c_str()); strncpy(&cb[st],StringGrid1->Cells[k][i].c_str(),len); cb[st + len] = '\t'; st = st + len +1; その結果、手動計測では測定不可能なほど早くなりました。 ありがとうございました。

関連するQ&A

  • テキストボックスに入力された内容をクリップボードにコピー

    プログラミング初心者です。少し教えていただけないでしょうか? 3*3で配置したテキストボックスに入力された内容をクリップボードにコピーするツールを作ろうと思っています。  受付番号  名前    備考 1[TextboxA1][Textbox12][Textbox13] 2[TextboxA2][Textbox22][Textbox23] 3[TextboxA3][Textbox32][Textbox33] [実行ボタン] 受付番号は入力の簡素化のため"No."という文字列を入力したいと思っています。もっと効率的な方法があると思いますが 実行ボタンを押したときに下記のプログラムを実行すれば 一応クリップボードにコピーできることが分かりました。 Dim MsgAll as string MsgALL = "No." & Textbox1.text & Textbox12.text & Textbox13.text & vbCrLf &TextboxA2.text (以下Textbox33.textまで) Clipboard.SetDataObject(MsgAll) ただし、3*3のテキストボックスは必ずしも全て入力されるわけではないので空白行の場合はその行をジャンプしたいのです。 各行の受付番号のテキストボックスに入力があるかどうかを判断させて空白だった場合はクリップボードにコピーさせなければよいのでは?と考えています。 色々ネットで調べた結果あらかじめ各行の内容を配列に代入しておき、 テキストボックスのコントロール名を取得してFOR文で処理を繰り返す方法を考えました。 lines(1) = "No." & TextboxA1.text & Textbox12.text & Textbox13.text & vbCrLf lines(2) ="No." & TextboxA2.text & Textbox22.text & Textbox23.text & vbCrLf lines(3) ="No." & TextboxA3.text & Textbox32.text & Textbox33.text & vbCrLf  For i = 1 To 3   ControlName = "TextBox_top" & i   If Me.Controls(ControlName).Text = "" Then    Else     MsgAll = MsgAll + lines(i)     Clipboard.SetDataObject(MsgAll) End If Next 以上のようなプログラムで動くかどうか不安でしたので 新たにプロジェクトを作り直し試みたところ動作したので ほんとうのプログラムにこの部分のロジックを組み込んで動作させたところ ”オブジェクト参照がオブジェクト インスタンスに設定されていません。”のエラーが返り正常に動作しませんでした。 テキストボックス名などがテストプログラムなどとは異なりますが 他に異なる部分はありません。 なぜこのようなエラーが発生してしまうのでしょうか? また、もっと効率のよい方法がある場合はその方法もご教示願えないでしょうか? 大変お手数ですがよろしくお願いいたします。

  • CSVを閉じるとき、「クリップボードに大きな情報があります」を出させないようにするには?

     Excelのマクロで、表.csvをExcelの「データ貼り付け」シートに貼り付ける際に、「クリップボードに大きな情報があります。」と出ます。下記の4行目でです。これを出させないようにするにはどうしたらいいでしょうか?  情報は、10列で最大で200行位(不明)です。 Workbooks.Open ("D:\表.csv") Range("B2:N3000").Select Selection.Copy ActiveWorkbook.Saved = True ActiveWorkbook.Close Sheets("データ貼り付け").Select Range("A1").Select ActiveSheet.Paste

  • 空の文字が含まれているファイル入出力について

    VC++を使用しています。 ファイル形式は、タブ区切りです。 1行ずつ読み込んでいき、 以下の2行目、2列目のように、空の場合、 どのように読み込めばよいでしょうか? 1行目 1as[Tab]2rt[Tab]333 2行目 erts[Tab][Tab]555 3行目 eeety[Tab]444[Tab]888 よろしくお願いします。

  • シートCopyを行った時のエラーについて

    エクセルシートの***にはA4横ページで縦に約20ページが並んでいます。 この***シートを別ブックにコピーしてCallで確認プロシージャーを呼び出して、印刷行の確認を行っています。(本来はそれ以外にも実行していますが、原因を探して行くとこの部分が残りました。) しかし、この状態で「確認」を実行すると9ページ前後でプログラムが「インデックスが有効範囲にありません」とメッセージが出て、停止しています。停止した状態でデバックを行い(MsgBox ActiveSheet.HPageBreaks(i).Location.Rowの箇所が示されます)、継続実行を行うと後は問題なく実行されます。 各種On Errorを入れて試しましたが、やはり上手く行きません。 しかし、「確認」を単独で実行したり、「移動開始」の.Copyを.Moveに換えると問題なく実行されます。.COPYした時のクリップボード情報の何かが、問題を起こしているのかと思い、WEB見つけたクリップボードをクリアーにするプロシージャーを追加しましたが、やはり上手く行きません。 .Move後に.Copyで戻すという手も考えましたが、もう少しスマートな方法は無いでしょうか? 原因と回避の方法がありましたらご教示をお願い致します。 Sub 移動開始() Sheets("***").Copy ActiveWorkbook.Sheets("***").Select Call 確認 End Sub Sub 確認() For i = 1 To ActiveSheet.HPageBreaks.Count MsgBox ActiveSheet.HPageBreaks(i).Location.Row Next i End Sub

  • ムービークリップのインスタンス名を変数で扱う

    Flash初心者で、レベルの低い質問だとは思いますが申し訳ありません。単純なシンタックスに関する質問です。 Panel.Panel0Cont ~ Panel.Panel10Cont という11個のムービークリップがあります。 それぞれのムービークリップを一挙に指定のフレームへgotoAndPlayさせる際に、ムービークリップの名前を変数で代入してforループで回したいのですが、変数への代入の仕方が解りません。例えば、 for (i=0; i>10; i++) { var mc:MovieClip = "Panel.Panel"+i+"Cont"; mc.gotoAndPlay(JumpNum); } mcはムービークリップですから、単純な文字列を代入しても当然タイプエラーになってしまいます。ムービークリップのインスタンス名のプロパティに、文字列を変数を使って代入するやり方があるのだと思います。 そのやり方をご教示頂けませんか。 ※参考書を2冊ひっくりかえしてもにわかには見つかりませんでした。

    • ベストアンサー
    • Flash
  • VBA Copy/Paste メソッド

    エクセル2002使用です。 sheet1のA7からD19セルの値を sheet2のB列の一列に転記をしたいのですが、 コピーが上手くできません。 Copy、Pasteメソッドを使用するときの セルの選択が良くわからないのですが、 よろしくお願いします。 Sub tenki() Dim i As Integer Dim j As Integer For i = 7 To 19 For j = 1 To 4 Cells(i, j).Copy Worksheets("sheet2").Activate Range("B65536").End(xlUp).Select ActiveCell.past ←ここでエラー(注) Next j Next i End Sub (注) エラー  オブジェクトは、このプロパティーまたはメソッドをサポートしていません。

  • MATLAB 256列以上の配列格納について

    こんにちわ。 現在、matlabで行971、列971程度の配列を用いて画像化したいと考えています。 しかし、列が256を超えるとエラーが出てしまい、処理できません。 ソースは下記の通りです。 971×971の正方形の画面にするので、1列(971×971)行などのように分割に全部入れて処理もするわけには行かないと思います。 よってなんとか256以上の列を使っていかなければならないです。 どうか、わかる方がいればお願いいたします。 //////////////////////////////////////////////////////////////// clear all; j=971; jj=5; test=[1:j,1:j]; for k=0:jj test=load(sprintf('APW%04d.csv',k)');%kの値を%04dに上書き end for i=1:j test(:,i) = abs(test(:,i)/j);%データを0~1に補正 end /////////////////////////////////////////////////////////////// エラー内容は下記の通りです。 //////////////////////////////////////////////////////////////// ??? Attempted to access test(:,257); index out of bounds because size(test)=[971,256]. エラー ==> Copy_of_Gzousyori at 14 test(:,i) = abs(test(:,i)/j);データを0~1に補正 ////////////////////////////////////////////////////////////////

  • C言語 文字列格納

    テキストファイルから整数データ又は文字列を読み込んで配列に格納する動作についての質問です。 テキストファイルが1行区切りの整数型なら1次元配列で for(i = 0; i < maxSize; i++) { fscanf(fp,"%d", &data[i]); } テキストファイルが1行区切りの文字列なら2次元配列で for(i = 0; i < MAXSIZE; i++) { if (fscanf(fp,"%s", &data[i][300]) == EOF) break; } for(j = 0; j < i; j++) printf("%s\n", data[j]); みたいな具合に格納できたんですが、 テキストファイルが1行区切りのデータではなく、空白文字区切りの文字データだった場合、それぞれどのようにして配列に格納すればいいかがわかりません。 イメージとしては、1文字目から見ていって空白が出ればそこで切って格納していくというかんじなのですが・・・ 質問の内容がわかりにくいかもしれませんが、是非教えてください。お願いします。

  • For Next構文を使ったVBA

    こんにちは、VBAについて質問をさせてください!(>_<) 同じブックにシート「テスト」と「Sheet1」があり、「テスト」にはデータの入力欄、「Sheet1」には「テスト」に入力するためのデータが入っています。「テスト」の入力欄は「Sheet1」のデータの並び順と同じですが、入力したデータ同士に4行3列ずつデータを入力しないセルを作らなくてはなりません。 また、データを入力するセルは「テスト」の5列目8行目=「Sheet1」3列目2行目~「テスト」の20列目8行目=「Sheet1」8列目2行目のように、まず列番号を増やし、列番号が最大になったら行番号が増え、列番号はまた初期値から増えます。したがって、次は「テスト」の5列目9行目=「Sheet1」の3列目3行目~「テスト」の20列目9行目=「Sheet1」の8列目3行目になります。 上記を踏まえてVBAを作成してみたのですが、このままではi,j,k,l全ての値がNextで増えてしまいます。Ifを使ったりするのかと色々ネットで調べて考えてみましたが、行き詰まってしまいました。どなたかご教授いただけるととても嬉しいです。説明が長く申し訳ないです、わかりづらければ補足させていただくので、おっしゃってください! Dim i, j, k, l As Integer For i = 5 To 20 Step 3 'シート「テスト」の列 For j = 8 To 116 Step 4 'シート「テスト」の行 For k = 3 To 8 'シート「Sheet1」の列 For l = 2 To 39 'シート「Sheet1」の行 Cells(j, i).Value = Sheets("Sheet1").Cells(l, k).Value Next l Next k Next j Next i

  • データに「,」があると「"」でくくられます。

    タブ区切りのデータファイルaaa.txtがあり、これをMySQLに読み込んでdatabaseというテーブルを作成したいのです。 これを実行すると、1行目は 1 concon コンコン とデータを読んでくれるのですが、2行目のようにカンマがあると 2 "con,con" コンコン のように両端に"がつくのです。 con,conと表示させるにはどのようにすればよいのでしょうか。 aaa.txt(スペースはタブ区切り) 1 concon コンコン 2 con,con コンコン $fp = fopen("aaa.txt","r"); $cnt = 0; while (!feof($fp)) { $record[$cnt] = fgets($fp, 1024); $cnt += 1; } fclose($fp); $sql="create table database(no int not null primary key auto_increment,dat1 varchar(200),dat2 varchar(200))"; $rst=mysql_query($sql,$con); for ($i=0; $i<$cnt-1; $i++) { $str[$i] = explode("\t", $record[$i]); $sql="insert into database(no,dat1,dat2)values('".$str[$i][0]."','".$str[$i][1]."','" .$str[$i][2]."')"; (続く)

    • ベストアンサー
    • PHP