プログレスバーの表示について・・・(MFC)

[戻る]
MIYUKI [E-Mail] 2001/05/15(火) 15:18:06
テキスト変換(バイナリからテキスト形式へ)のプログラムをコーディングしてます。
突然ですが、私、みゆきと申します。 開発環境は「Windows2000」「VC++6,0」
「MFC」のダイアログベースで作成しています。めちゃくちゃの初心者なので、どうか
宜しくお願いします。
え・・書き込み(ループ)最中にその進捗状況に適応したプログレスバー
を表示したいと思っています。(プログレスダイアログで)

先程、初めてプログレスバーを表示することに成功しましたが
CProgressDlg dlg;
dlg.Create();
for(int i = 0 ; i < 10 ; i++){
  if(dlg.CheckCancelButton()){
    return;
  };
   dlg.StepIt();
   Sleep(500);
  }
   
これを今度はファイル変換時のループで処理したいと思ってます。
(途中を抜粋しました)
//SetWindowText("只今保存中");
    //CWaitCursor wait;
    while(fread(&ch,1,1,stream)){
    if(icnt == 0 || icnt == 16){
         fprintf(stream2,"\n%04d: ",16*indcnt);
          indcnt++;
           icnt = 0;
     }
       if(icnt == 8){
       fprintf(stream2,"- ");
       }
       fprintf(stream2,"%02x ",ch);
       ch = 0;
       icnt++;
       } 
       fclose(stream);
       fclose(stream2);
      //SetWindowText("保存終了");
  }

色々MSDNやHPなどで検索するのですが、初心者の私には理解に難いかと・・・。
こんな未熟者の私ですが、宜しくお願いします。(こんな稚拙な説明ですみませんでした)

2001/05/16(水) 13:46:25
1バイトずつ変換しファイルに保存しているのなら

・最初に変換する全データバイト数を調べる。
・プログレスバーの最小値(恐らく0)、最大値(全データバイト数)を設定する。

・1バイト書き込む毎にプログレスバーを更新する。

こんな感じでいいんじゃないでしょうか。

後、whileループ中にプリエンプティブな機構にしなければ、
プログレスバーが更新されないような気がしますがどうでしょう?

MIYUKI [E-Mail] 2001/05/16(水) 15:15:54
重さん。 ありがとうございます。
私も今日はずっと「最初に元ファイルのバイト数を取得して」→
「Setronge(0,100)の関数を使って」→「Setpos(カウント
された変数)」で・・・・などと、無い頭絞って考えてたところ
なんです。
え? プリエンプティブな機構・・・? プログレスバーの更新ですか・・・。
良く「更新されない」などHPで拝見しますが、一体どういう事をいうのでしょうか?

void CHenkan2Dlg::OnOK() 
{
 // TODO: この位置にその他の検証用のコードを追加してください
  CFileDialog filedlg(FALSE, "", "",
      OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
      "テキスト(*.txt)|*.txt|ビトマップ(*.bmp)|*.bmp|データ(*.data)|*.data|すべてのファイル(*.*)|*.*||", this);

  CString filepath,filename;
  FILE *stream;
  FILE *stream2;
  char *ch;
  if( filedlg.DoModal() == IDOK){
  filepath = filedlg.GetPathName();
  filename = filedlg.GetFileName();
  if(strlen(filename)>20){
    MessageBox("ファイル名OVERです",NULL,MB_ICONWARNING);
    return;
  }
  if((ch = strrchr(filename,'.')) == NULL){
    MessageBox("拡張子が見付かりません",NULL,MB_ICONWARNING);
    return;
  }
  else{
    *ch = '\0';
    strcat(ch,".txt");
  }

 この時にファイルのサイズを取得したいのですが、MSDNやHPでは良く
理解できません・・・。
 GetFileSizeなの? Getstatusなの?といった感じです。
GetFileSize関数の第一引数の意味合いもわかりません。(ハンドル)
HANDLE hFile = CreateFile("ここはどうしたら良いのでしょう?", GENERIC_READ, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);

見よう見真似でやってみたのですが、ダメでした。
今後そのファイルサイズを変数に代入して、
 int count;
 count = ( 100,0 * ( 1 / ファイルサイズ))
としていきたいと思ってるので、アドバイス宜しくお願いします。(私の勝手な解釈ですね。きっと)
 かなり重さんのアドバイス「更新されないのでは・・・」が気になっちゃってるのですが。

2001/05/16(水) 19:13:13
> HANDLE hFile = CreateFile("ここはどうしたら良いのでしょう?", GENERIC_READ, 0, NULL, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
CreateFileの最初の引数はファイル名を持つ文字列へのポインタです。

> GetFileSizeなの? Getstatusなの?といった感じです。
GetFileSizeで良いはずです。

> int count;
> count = ( 100,0 * ( 1 / ファイルサイズ))
> としていきたいと思ってるので、
SetRangeはありませんでした?
最小値、最大値を設定出来れば自分で計算しなくてもMFCがやってくれます。

> かなり重さんのアドバイス「更新されないのでは・・・」が気になっちゃってるのですが。
勘違いでした。m(__)m
ダイアログにプログレスバーを付けて試してみたらループ中でも更新されます。

プリエンプティブな機構にしないとボタンの入力は受け付けてくれません。
(”中止”ボタンなどを付加する場合にやらないと駄目って事です)

MIYUKI 2001/05/17(木) 14:14:12
[[解決]]
重さん!アドバイスありがとございます!
お陰でGetFileSizeで無事にファイルサイズを取得、SetRange()と
SetPos()関数でファイル変換の進捗状況に適応させたプログレスバー
を作成することが出来ました。
file_size = GetFileSize( hFile, NULL ) ;
     ・
     ・
dlg.Create();
dlg.SetRange(0,100);
         ・
Count = (double)(100 * ((double)(1+t) / (double)file_size));
dlg.SetPos((int)Count);
こんな具合です。(まだまだ初歩的なものですが、でも大満足です!)

プリエンプティブな機構にしなければ・・・・が勘違い? 私の方は
本当に無知識なので、大丈夫ですよっ。

(重さん)プリエンプティブな機構にしないとボタンの入力は受け付けてくれません。
(重さん)”中止”ボタンなどを付加する場合にやらないと駄目って事です)
はい! 分かりました! と言いたいところだけど、プリエンプティブな機構って一体・・・。
HPやMSDNで調べてみま〜す! 

 またその折には宜しくお願いします!(またというか・・近いうちですね・・きっと)

-------------------------------------------------------------------------------- 
 

MIYUKI [E-Mail] 2001/05/22(火) 12:01:38
「解決」に印したのですが・・・。またまた宜しいでしょうか?
先日、「プログレスバーの表示」が上手くいったと大満足だった
のですが、どうも「変換時間(保存)」がとっても長いんです。
プログレスバー付きダイアログを表示するのと、しないのとでは
倍くらい違うでしょうか。
 原因は読み込むバイト数とSetpos()の引数だと思うのですが、
それをどのように変えてあげたら良いのか分かりません

 こんな感じなのですが・・・。
 int t = 0;
 dlg.Create();
 dlg.SetRange(0,100);
 while(fread(&ch,1,1,stream)){ //多分この第二引数・・・
      if(dlg.CheckCancelButton()){
         ・
         ・
         ・
   //fprintfなどを使って書き込み処理
         ・
         ・
     Count = (double)(100 * ((double)(t) / (double)file_size));
                   //あとはこの
    dlg.SetPos((int)Count);
     t += 1;
     }

色々とフローを書いたり、「t += 1」を10に変えてみたりしたの
ですが、「プログラム違反」の表示が出てきて困っています。
何が原因なんでしょうか? fread関数ではダメなのですか?
他に何か良い方法はないのでしょうか? 
初心者なので迷惑三昧かと思いますが、どうか宜しくお願いします。

2001/05/22(火) 13:01:35
システムモニタでCPUの使用率が100%になっていませんか?

whileループの中に
Sleep(10);でも加えてみて下さい。

> if(dlg.CheckCancelButton()){
前にも書き込みを行いましたが、このままではボタンの処理は受付けてくれません。
以下のコードをループの中に組み込めばボタンも受付けます。

MSG msg;

if(::PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
    ::TranslateMessage(&msg);
    ::DispatchMessage(&msg);
}

MIYUKI [E-Mail] 2001/05/22(火) 13:53:33
重さん!いつもいつも下らないと思われる問いかけへのアドバイスありがとう
ございます。
えっと・・。重さんが仰られたとおりにループ内に「Sleep(10)」を加えて
みました! SLEEPは一時的に指定されたプロセスを非アクティブにするとMSNDに
書いてあったのですが、何事もやってみなけりゃ分かりませんものね〜。
で・・・あれ? さっきよか処理速度が遅くなってしまったっ!! 色々試して・・・
引数で渡した値が大きいほど、非アクティブな時間も長くなるってことなのねっ。
ではではと(1)を加えてみる。 やっぱり遅い・・・。

さては重さんがもう一つ云っていた「システムモニター」のCPU使用率が100%に
なっちゃってるのだな〜・・・とPCを調べしたのですが、検索でも出てこない・・、
ヘルプでもお手上げです。

システムモニターの詳細が分からない。処理速度をもう少しだけでも良いので、確実に
UPさせたいのです。 ふぅ・・・どうしたら良いのでしょうか???


度々の登場ですみませんが、どうぞ宜しくお願いします!! MIYUKI

2001/05/22(火) 17:18:51
ファイルを読み込んで書き込むだけのプログラムを組んでみましたが、
プログレスバーの使用、未使用に関わらず速度は殆ど変わりませんでした。
(ちなみにCreateFile使用)

fread、fwriteを1バイトずつ行っている為、高水準入出力のオーバーヘッドが
関係しているのではないでしょうか。

システムモニターは「アプリケーションの追加と削除」−「Windowsファイル」−「システムツール」で追加できます。

MIYUKI [E-Mail] 2001/05/30(水) 11:36:18
お久しぶりで〜す!MIYUKIです!
申し訳ありませんが、もう少々「プログレスバー」にお付き合い
下さいませっ。お願いします。
えっと・・・やっぱり重さんが仰った通り、fread、fwriteを1byte
づつ読み込んでいたのが原因ではだったみたいですぅ。
私もこの間中「fopenに甘えないで、Infile.Open!!」なんて
VC(C++?)の基本であるクラスを勉強しながら今までのソースに
変化を加えてました〜。
重さんと同じように、私もファイルをただ読み込んで書きこむ
(80バイトづつくらい)ソースを試しに作ってみて、プログレスバー
の動きを確認しました! わわ! こんなに早く・・・ぅ・・。
//CprogressDig dig;  ファイルサイズの取得(file_size)
//unsigned char ss[80]; UINT Gotbytes = 0; long Readbytes = 0;
       ・
dlg.Create();
dlg.SetRange(0,100);
whille((GOtbytes = InFile.Read(ss,sizeof(ss))) > 0){
   MSG msg;
   if(::   
           ・
      ・
OutFile.Write(ss,Gotbytes);
Readbytes += Gotbytes;
Count = (int)((double)100 / (double)file_size * Readbytes);
dlg.Setpos(Count);
}
上手くプログレスバーが機能したので嬉しくって嬉しくって!!
でも一つだけどうしても解決出来ない事・・・。
私。読みこんだバイナリファイルをテキストファイル
として変換したいんです。 例えば
 0000: 09 99 99 99 - 90 90 99 ff
  0010: 77 89 23 f4 - 00 00 00 00
みたいに行の最初にインデックスを設けて、16若しくは8桁
くらいの改行を変換時に加えて。
今まではそれもあって最初に書きこさせて頂いた時のソースみたっく
1バイトづつ読み込んでは
fprintf(stream2,"\n8: "10*indcnt);
fprintf(stream2,"\%02x" ch);
みたいな処理をしていたのですが(この間中に配列も試してみました)
今はファイルのオープンも
if(!InFile.Open(filepath, CFile::modeRead | CFile::typeBinary))
のような形にしてしまったので、stream(FILE*)も使ってないのです。

えっと・・長くなってしまいましたが、上のような処理(80bytesづつ
読み込むループ)の中で変換(書き込み)時にインデックスやそうした
処理を加える事(fprintfのように)って出来るのでしょうか?
またfprintfのような関数で、このループ内でも使えるようなモノってあるので
しょうか? MSDNでキーワード検索するのですが・・なかなかぁ。

訳分らない?説明になってしまいましたが、どうか宜しくお願いします。

古いスレッドには追加発言できません。