MFCのViewクラスでエディタを作成しています。
水平方向のスクロールがわかりません。
秀丸等のエディタでは、文字入力時にウインドウの右端まで入力した時に
自動で右にスクロールしますが、このやりかたが良くわかりません。
ウインドウの右端の位置を判定し、左端の位置をずらして描画
するやりかたで良いのでしょうか?
このやり方だと、左端が全角で半分しか表示できない時に文字が化けてしまう気がします。
秀丸等では水平スクロールバーのように表示のみずらすやり方を行っている気がするのですが、
やり方が良くわからないです。
どなたかご存知ないでしょうか?
CScrollViewを使用すれば、その辺りのことは、MFCがやってくれます。
OnDraw()内ではスクロール量を意識せずに描画コードを書けます。
自分でやる場合は、SetWindowOrg()などで原点をずらして、
普通に左端から描画すると良いと思います。
亀レスでごめんなさい。
VCは初めてなので分からないことだらけです。
考え方のヒントでも結構ですので教えて頂けませんか?
他の人からの引継なのでVeiwクラスで垂直スクロールバーまで作成されています。
ここから基本クラスをCScrollViewクラスに変更できるでしょうか?
基本クラスの変更の仕方がよく分かりません。
class CXXXView: public CVeiw
{
・・・
}
↓こんなふうにしちゃダメですよね
class CXXXView: public CScrollView
{
・・・
}
また、Veiwクラスで行番号表示とルーラーを作成していますので
SetWindowOrgで原点をずらすと一緒に行番号が動いてしまう気がします。
行番号とルーラーは動かないようにして、テキスト領域のみスクロールする
ようにするにはどのようにすれば良いでしょうか?
開発環境:Win98 VC++6.0(SP5) MFC
部分的にスクロールしたいのであれば、CScrollViewは使えないですね。
描画部分で、次にようにしてみてください。
1) スクロールしない部分を描画する。
2) スクロール部分をクリップする(IntersectClipRect)。
3) SetWindowOrgで原点をずらしてスクロールする部分を描画する。
>1) スクロールしない部分を描画する。
この部分が良くわかりません。
クライアント領域を超えて描画するということでしょうか?
2つの場合が必要かなと思っているのですが、
私の考えはどうでしょうか?
①の場合、先頭アドレスをずらして描画する処理は必要ないでしょうか?
①入力時の場合(入力しながら右にスクロール)
テキスト部分の描画は、1行毎に文字列を管理していますので、
スクロールした分の文字列の先頭アドレスをずらして描画(TextOut)
②スクロールバーの場合(マウスやPgUp等で動かす)
SetScrollInfo、SetWindowOrg等を使用し描画する座標を動かして
表示する。その時、文字列の先頭アドレスはずらさない。
nanaさん,はじめまして.
>他の人からの引継なのでVeiwクラスで垂直スクロールバーまで作成されています。
>ここから基本クラスをCScrollViewクラスに変更できるでしょうか?
>基本クラスの変更の仕方がよく分かりません。
>class CXXXView: public CVeiw
>{・・・}
> ↓こんなふうにしちゃダメですよね
>class CXXXView: public CScrollView
>{・・・}
CViewからCScrollViewへの変換ですが,
1.CXXXView.h,CXXXView.cpp内を検索し,CViewをCScrollViewへ置換する.
ただし,関数パラメータ内のCView*は置換しない.
2.OnInitialUpdate()がオーバーライドされていなければ,
オーバーライドし,その中でCScrollSizesを呼び出す.
手動ですが,これでできると思います.
Windowsにおける描画処理というのは、常に全画面を書き直す方式だと考えてください。
つまり、入力によって1文字増えただけの場合も、先頭から全て書き直します。
(1)や(2)の場合で分岐する必要はありません。
>>1) スクロールしない部分を描画する。
>この部分が良くわかりません。
行番号やルーラーなど、スクロールしていても固定位置に表示される
部分のことです。
とりあえずZIYIさんのやり方で基本クラスの変更をしてみました。
>CViewからCScrollViewへの変換ですが,
>1.CXXXView.h,CXXXView.cpp内を検索し,CViewをCScrollViewへ置換する.
> ただし,関数パラメータ内のCView*は置換しない.
>2.OnInitialUpdate()がオーバーライドされていなければ,
>オーバーライドし,その中でCScrollSizesを呼び出す.
教えて頂いて恐縮ですが、
× CScrollSizes
○ SetScrollSizes
で、基本クラスの変更は出来ました。
だけど、スクロールしない部分があるので基本クラスの変更はしないようにしました。
でも基本クラスの変換の仕方が理解できました。
どうもありがとうございます。
>行番号やルーラーなど、スクロールしていても固定位置に表示される
>部分のことです。
テキスト領域のことと思ってました。
考えが分かったのでdairygoodsさんに教えて頂いたやり方で作成してみます。
まだ不安なので解決にチェックはしないでおきますね。
>オーバーライドし,その中でCScrollSizesを呼び出す.
あ!この部分ですね.
確かにCScrollSizes→SetScrollSizesでした.
間違えてました,申し訳ないです.
お久しぶりです。
dairygoodsさんの通りに行いました。
テキスト部をクリップし、原点をずらしてスクロールまでできるようになりました。
(どうしようもない事でかなりはまりましたが・・)
しかし、右方向にスクロールする時、行番号のところに先頭のテキスト部が上書きされてしまい
ます。
領域を固定して表示する関数かAPIがありますでしょうか?
宜しくお願いします。
行 テキスト部
---------------
100 あいうえお
101 かきくけこ
102 さしすせそ
↓こんな感じになってしまう
10あいうえお
10かきくけこ
10さしすせそ
> 領域を固定して表示する関数かAPIがありますでしょうか?
これをするのが、IntersectClipRectなどのクリップ関数です。
pDC->IntersectClipRect(テキスト部);
で、テキスト部に描画が限定されます。
座標の指定は合ってますでしょうか。
dairygoodsさん。
どうもご迷惑かけます。
サンプル作って、水平スクロールのみやってみました。
・行番号領域 (0,0)-(90,0)
・テキスト領域 (90,0)-(10000,10000)
クリップ領域はテキスト領域としているのですが、
原点位置のずらしかたがおかしいのでしょうか?
それとも表示の仕方でしょうか?
ちょっと使い方が理解できてません。
一応ソースも上げておきます。
//スクロール量(グローバル)
static int nSCPos=0;
//テキスト領域(グローバル)
int nCol=10000;
int nRow=10000;
void CHelloView::OnDraw(CDC* pDC)
{
CHelloDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//行番号領域
int nGyo=90;
//原点位置
int nOrg = nGyo-nSCPos; //nSCPosはスクロール移動量を外部変数で持ってきてる
//文字サイズ
int nChrH=18;
int nChrW=9;
char deb1[50] = {xxxxxxxxxxxx}; //行番号領域
int j;
for(j=0;j<20;j++ ){
pDC->TextOut(0,j*nChrH , deb1);
}
//スクロール部分をクリップする
IntersectClipRect(pDC->m_hDC ,nOrg ,0,nCol,nRow);
//原点位置の変更
pDC->SetWindowOrg(nOrg, 0);
int i;
for(i=0;i<20;i++ ){
pDC->TextOut(nOrg*2,i*nChrH ,
1Hello World! 2Hello World! 3Hello World! 4Hello World!);
}
}
> IntersectClipRect(pDC->m_hDC ,nOrg ,0,nCol,nRow);
クリップ領域の左側は、nOrgじゃなくてnGyoですね。
ほとんどやってもらったみたいになっちゃいましたね。
dairygoodsさんどうもありがとうございました。
やっと解決にチェックができました。