OnDrawにTextOutやDrawTextで書いた文字列をスクロールさせたい – 固定ページ 3 – プログラミング – Home

通知
すべてクリア

[解決済] OnDrawにTextOutやDrawTextで書いた文字列をスクロールさせたい

固定ページ 3 / 3

dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

ちょっと補足します。

> 画面サイズの変更によって、表示する内容が変化しないのであれば、
> SetScrollSizes を呼び出す必要はありません。

は、ウィンドウのサイズを変更したとき(3)の話です。


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

私が前に書いた自前で計算しないといけないと言う所が誤解を招いてるかも。
自前で計算しなくてはならないのはCScrolViewのような便利なクラスを使用しない場合です。
CScrollViewを使っているなら面倒な部分はCScrollViewが面倒を見てくれるので
毎回、一枚の紙に一行ずつ描画するイメージでいいはずです。
ウインドウ上の位置の調整はCSrollViewがしてくれます。

ドキュメント-ビュー・アーキテクチャを使う場合、
通常はドキュメントクラスに表示したい文字列を持たせます。
例えば、ドキュメントクラスのメンバー変数にCStringArrayの変数を作成して
ドキュメントクラスのOnNewDocumentで文字列配列を必要なデータで初期化すれば、
起動時に既にデータが設定された状態に出来ると思います。
通常、ドキュメントクラスはそのドキュメントクラスが扱うデータを取り出したり
設定したり、追加したりするメンバー関数を追加定義するのが普通です。
この場合なら、データの行数を取得する関数、インデックスを指定して特定の行のデータ
を取り出す関数、
データに指定したデータを追加する関数等がドキュメントクラスには必要になると思います。
ビュークラスのOnInitialUpdateでドキュメントクラスから文字列の行数をもらえば、
表示に必要なY方向の幅は計算できると思いますから、これをSetScrollSizeで設定します。
ビュークラスのOnDrawは、ドキュメントクラスから一行ずつデータをもらいながら
データの行数分だけTextOutします。
みそになるのは、ビュークラス自身は内部にデータが何行あるとか、どの行にどんなデー
タがあるとか知っている必要はないということです。
ビュークラスは、ドキュメントクラスに何行あるかをたずね、
一行ずつデータを取り出して、行数回TextOutを繰り返すと言う処理をするだけにします。

表示するデータを増やしたいのであれば、メニュー等を用意しておいて
それを操作したらデータが一行分増えると言う風にします。
例えば、メニューに「データ」という項目を設けて、これをクリックしたらデータを増や
すでもよいです。
クリックされたら、データをドキュメントクラスに追加して、あとはOnInitialUpdateで
やった事と同じ処理でSetScrollSizeを行います。

ドキュメント-ビュー・アーキテクチャを使用するということは、
表示系とデータ管理系を切り離して自由に組み合わせが出来るような構造にすると言うの
が目的になります。
この辺の考え方は今後、ドキュメント-ビュー・アーキテクチャを使うのであれば、基本
になる考え方なのできちんと抑えておいた方がいいです。


返信引用
わか
 わか
(@わか)
ゲスト
結合: 24年前
投稿: 3
 

ご回答ありがとうございます。
昨日の午後から体調を崩し今日は自宅でお休みです。(インフルエンザっぽい)

>REEさん
記述する場所はおおむねあってますよね。
では、なぜ残像が残ったり、スクロールバーのつまみを一番下に
移動しても一番下まで表示されないのか?また、ウィンドウの位置
を動かすと、表示が一番上に戻ってしまうのか?(つまみはそのまま)

>ちなみに、OnDrawで使っているNowTopって何のための変数ですか?
この変数は、次の行はどの位置(y方向)から書き始めたらよいか
保存する変数です。実はTextOutの前にDrawTextも使って、領域を
使った表みたいなものを表示しているためです。説明を省略してし
まってすいません。

>dairygoodsさん
>というより、どこで躓いているか見えないので
結果が上記のように意図していない結果になることに躓いています。

>自分の描きたい絵が 何×何 ピクセルかを指定するだけです。
自分の描きたい絵(文字)が何行分あるかを計算して指定している
つもりなんですが・・・・。計算値が間違っているかもしれないの
で、ためしに明らかに大きい値を指定しても最後の行が表示されて
いないのです。

>画面サイズの変更によって、表示する内容が変化しないのであれば、
>SetScrollSizes を呼び出す必要はありません。
そうなんですか。これは私の勘違いでした。

>OnDrawでは、たとえば、SetScrollSizes で 1000x1000 を指定したなら、
>(0, 0) - (1000, 1000) の領域に好きなように描くだけです。
なんか私の発想は順番が逆なんですかね。私のイメージでは、SetScrollSizes
で1000x1000を指定する前に、まず文字を描いてしまって、このサイズ
では表示しきれないから、あとで必要なサイズを計算して、改めて
SetScrollSizesでサイズを指定するイメージでした。
(印刷の話はちょっとおいておきます。)


返信引用
REE
 REE
(@REE)
ゲスト
結合: 24年前
投稿: 240
 

とりあえず、症状に影響しない部分を削除した上で、
関連すると思われる関数(特にOnDraw)のソースをそのまま載せてみては如何ですか?
その際には、削除したソースでも症状が再現することを確認しておいてください。


返信引用
わか
 わか
(@わか)
ゲスト
結合: 20年前
投稿: 17
Topic starter  

REEさんありがとうございます。サンプルソースを作る過程で
削っているうちに、悪さ(残像およびスクロールが変になる)
しているコードがわかりました。でも、なぜなのかはわかりま
せん。このコードはネットから探し出してきたものです。
(とりあえず後回しにした、プレビューで文字が小さくなる
件で調べたときに見つけました。)
コメント「// プリンタかどうかチェック」のところから
「// フォント設定」の手前のところまでです。
ここを外すと、表示、スクロールとも、とりあえずうまくい
くような感じです。(しかしプレビューを表示してみると、
やはり文字が小さくなって、おかしな表示になります。)
プレビューについては、しばらく自力でまた調べます。
どうしてもわからないときは別件としてまた質問したいと思
います。そのときはよろしくお願いいたします。

ということで、いちおう解決・・・かな?
みなさん、長い間ありがとうございました。大変ご迷惑を
おかけいたしました。

void CSampleView::OnInitialUpdate()
{
(省略)
// コード修正ここから
// sizeTotal.cx = sizeTotal.cy = 100;
sizeTotal.cx = sizeTotal.cy = 1000; // とりあえず
// ここまで
(省略)
}

void CSampleView::OnDraw(CDC* pDC)
{
(省略)
// TODO: この場所にネイティブ データ用の描画コードを追加します。

// コード追加ここから

long NowTop; // 現在の上位置
long NowLeft; // 現在の左位置

// プリンタかどうかチェック。
// 印刷なら色や設定を印刷用に切り替える。
pDC->SetMapMode(MM_ISOTROPIC); // 1ピクセルが正方形になる
pDC->SetWindowOrg(0, 0);
pDC->SetViewportOrg(0, 0);
pDC->SetWindowExt(500, 400);
pDC->SetViewportExt(500, 400);

if(pDC->IsPrinting()){
int i,j;
i = pDC->GetDeviceCaps(HORZRES); // これで紙の幅と高さが解る
j = pDC->GetDeviceCaps(VERTRES);
pDC->SetWindowOrg(0, 0);
pDC->SetViewportOrg(0, 0);
pDC->SetWindowExt(500, 400);
pDC->SetViewportExt(i, j);
}
else{
pDC->SetMapMode(MM_TEXT);
}

// フォント設定
pDC->SetTextColor(RGB(0,0,0)); // テキストの色
pDC->SetBkMode(TRANSPARENT); // バックグラウンドモード設定
CRect myAREA(10,10,100,100); // 矩形領域確保(サイズ適当)

// 罫線用ブラシの設定
CBrush myBRUSH(RGB(0,0,0)); // 黒ブラシ
pDC->SelectObject(&myBRUSH); // 黒ブラシを選択

// **リテラル部**
CString ss = XXXX:; // 文字列をセット
pDC->DrawText(ss,myAREA,DT_CALCRECT | DT_LEFT); // 最適な高さと幅を計算
pDC->DrawText(ss,myAREA,DT_LEFT); // 矩形領域文字列出力
NowTop = myAREA.bottom;
(中略)

// **表のヘッダ部**
ss = 各検査項目; // 文字列を再セット
// 構造体の値を変更する
myAREA.left = 10;
myAREA.top = NowTop + 5; // 位置調整
pDC->DrawText(ss,myAREA,DT_CALCRECT | DT_CENTER); // 最適な高さを計算
myAREA.right = 200; // 幅を調整
pDC->DrawText(ss,myAREA,DT_CENTER); // 矩形領域文字列出力
pDC->FrameRect(myAREA,&myBRUSH); // 矩形領域外周出力
NowTop = myAREA.bottom;
NowLeft = 200;
(中略)

// **表のディテール部**
ss = 項目①\n項目②\n項目③; // 文字列を再セット
myAREA.left = 10;
myAREA.top = NowTop-1; // 位置調整
pDC->DrawText(ss,myAREA,DT_CALCRECT | DT_CENTER); // 最適な高さを計算
myAREA.right = 200; // 幅を調整
pDC->DrawText(ss,myAREA,DT_CENTER); // 矩形領域文字列出力
pDC->FrameRect(myAREA,&myBRUSH); // 矩形領域外周出力
NowTop = myAREA.bottom;
NowLeft = myAREA.right;
(中略)

// ここは文字をたくさん書いて高さを稼ぐための仮処置
for(int i=0;i<=20;i++){
pDC->TextOut(10,NowTop+i*15,あいうえお);
}
pDC->TextOut(10,NowTop+i*15,かきくけこ);

// ここまで

}


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

多分、DCの解像度を見てサイズ調整するコードがあったのではないかと思うのですが、
その所為で実際に更新しているサイズとCScrollViewが認識しているサイズにずれが出た
のかもしれませんね。

通常印刷を行うときは改ページ処理が必要になるのでOnDrawに印刷用のコードまで書くよ
りも印刷用のコードと画面用の描画コードは分けた方が無難です。
仮にやるとしても共通になりそうな部分だけ別関数にしてOnDrawとOnPrintの両方から呼
ぶようにするとかした方がいいと思いますよ。


返信引用
dairygoods
 dairygoods
(@dairygoods)
ゲスト
結合: 23年前
投稿: 1421
 

CScrollViewは、プログラマがスクロール量を気にしなくても
描画できるように、SetViewportOrg() で原点を調整しています。

なので、OnDrawでSetViewportOrg(0,0)としてしまうと、
描画位置がずれます。


返信引用
固定ページ 3 / 3

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました