質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.48%

  • C#

    9215questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Windows Forms

    178questions

    Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。

C# テキストボックスのスクロールバーの位置を取得したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 97

moko2

score 3

プログラム初心者です。
Visual Studio 2019 で C# を使用して Windowsフォームアプリでオリジナルのテキストエディタを作成中です。

テキストボックスのスクロールバーの位置を記憶しておいて、再起動後などに復元したいと思ったので下記の記事を参考に試してみましたが、リッチテキストボックスでは正常に動作して、テキストボックスでは動作しませんでした。
http://pineplanter.moo.jp/non-it-salaryman/2017/11/23/csharp-scroll-control/

しかし同じようなことを試している別の記事ではテキストボックスで実装されています。
http://seshikanai.blog.fc2.com/blog-entry-4.html

ということは何か私の方に問題があるのでしょうか‥
とは言えコードは参考記事そのままになります。

// スクロールバーの位置を取得&復元するための関数
[DllImport("USER32.dll")]
public static extern IntPtr SendMessage(
    IntPtr hWnd, Int32 Msg, Int32 wParam, ref Point lParam);

private Point pos = new Point(0, 0);

// GET
private void Button1_Click(object sender, EventArgs e)
{
    // スクロール位置を取得
    SendMessage(this.textBox1.Handle, 0x04DD, 0, ref pos);
    //NativeMethods.SendMessage(this.richTextBox1.Handle, 0x04DD, 0, ref pos);
    label1.Text = pos.X.ToString();
    label2.Text = pos.Y.ToString();
}

// SET
private void Button2_Click(object sender, EventArgs e)
{
    // スクロール位置を復元
    SendMessage(this.textBox1.Handle, 0x04DE, 0, ref pos);
    //NativeMethods.SendMessage(this.richTextBox1.Handle, 0x04DE, 0, ref pos);
    label1.Text = pos.X.ToString();
    label2.Text = pos.Y.ToString();
}

イメージ説明

こちらについて何かお分かりの方いらっしゃいましたら、ご教授いただけましたらありがたく思います。

よろしくお願いします。m(_ _)m

追記:
代替案として「キャレットの位置を保存して、復元時にキャレットの位置までスクロールする」という実装も試してみました。
ただしこちらの場合、キャレットがある行がテキストボックスに表示されている範囲での最下行までしかスクロールダウンしてくれず、とても不格好な上に結局少し手でスクロールダウンさせる必要があり不便です。。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • papinianus

    2019/06/13 07:18

    代替案はキャレットの位置+15までスクロールする、ではだめなのですか?

    キャンセル

  • moko2

    2019/06/13 11:26 編集

    papinianusさんコメントありがとうございます!

    キャレットの位置までスクロールするメソッドは「textBox1.ScrollToCaret();」なのですが、こちらにはどうも引数が無いようでそれ以上の指定ができません。。
    https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.textboxbase.scrolltocaret?view=netframework-4.8

    こちらのメソッド、見えている範囲の上までスクロールするというような指定ができれば便利ですよね。

    キャンセル

  • papinianus

    2019/06/13 19:00

    回答でたんでいいですが、キャレット位置を保存してるのですよね?それを15行下にしてスクロールして位置を戻せるかと思いました。もちろん縦が固定のときなので、実用的ではないでしょうが。

    キャンセル

  • moko2

    2019/06/13 20:16

    はい、キャレット位置の保存は途中で軽く試しました。
    ただ、こちらに質問した段階ではそもそもスクロール位置を制御することができなかったので、キャレットの位置からさらにスクロール位置を変えてやるにも方法が分からない‥という感じです。。

    キャンセル

回答 1

checkベストアンサー

+2

0x04DD(EM_GETSCROLLPOS)や0x04DE(EM_SETSCROLLPOS)はリッチエディット用のメッセージのようなので、他の方法でやる必要がありそうです。

ちょっと作ってみたので試してみてください。
GetTextBoxScrollPosで取得、SetTextBoxScrollPosでセットができます。

        const int SB_HORZ = 0x00;
        const int SB_VERT = 0x01;
        const int WM_HSCROLL = 0x0114;
        const int WM_VSCROLL = 0x0115;
        const int SB_THUMBPOSITION = 4;

        [DllImport("USER32.DLL", CharSet = CharSet.Auto)]
        static extern int GetScrollPos(IntPtr hWnd, Int32 nBar);
        [DllImport("user32.dll")]
        static extern int SetScrollPos(IntPtr hWnd, Int32 nBar, int nPos, bool bRedraw);
        [DllImport("user32.dll")]
        static extern int SendMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);

        public static Point GetTextBoxScrollPos(TextBox textBox)
        {
            return new Point(GetScrollPos(textBox.Handle, SB_HORZ), GetScrollPos(textBox.Handle, SB_VERT));
        }

        public static void SetTextBoxScrollPos(TextBox textBox, Point newPos)
        {
            SendMessage(textBox.Handle, WM_HSCROLL, (newPos.X << 16) + SB_THUMBPOSITION, 0);
            SendMessage(textBox.Handle, WM_VSCROLL, (newPos.Y << 16) + SB_THUMBPOSITION, 0);
        }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/06/13 10:51

    あ、SetでXの位置が正しく設定されてなかった...

    キャンセル

  • 2019/06/13 11:02

    今度こそ大丈夫のはず・・・

    キャンセル

  • 2019/06/13 11:32

    takabosoftさんご回答ありがとうございます!

    早速試したところバッチリ動作しました!
    件のコードはリッチエディット用だったのですね。

    実装をあきらめるところだったので大変感謝しています。。
    ありがとうございました!

    キャンセル

  • 2019/06/13 11:35

    どういたしまして!私も勉強になりました。

    キャンセル

同じタグがついた質問を見る

  • C#

    9215questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Windows Forms

    178questions

    Windows Forms(WinForms)はMicrosoft .NET フレームワークに含まれる視覚的なアプリケーションのプログラミングインターフェイス(API)です。WinFormsは管理されているコードの既存のWindowsのAPIをラップすることで元のMicrosoft Windowsのインターフェイスのエレメントにアクセスすることができます。