28

Multiline=True の System.Windows.Forms.TextBox の場合、テキストが収まらない場合にのみスクロールバーを表示したいと思います。

これは、表示のみに使用される読み取り専用のテキスト ボックスです。ユーザーがテキストをコピーできるように、これは TextBox です。スクロールバーの自動表示をサポートする組み込み機能はありますか? そうでない場合は、別のコントロールを使用する必要がありますか? または、TextChanged をフックしてオーバーフローを手動でチェックする必要がありますか (そうであれば、テキストが収まるかどうかを確認する方法は?)


WordWrap と Scrollbars 設定のさまざまな組み合わせでうまくいきません。最初はスクロールバーがなく、テキストが指定された方向に収まらない場合にのみ、それぞれが動的に表示されるようにしたいと思います。


@nobugz、ありがとう、WordWrapが無効になっているときに機能します。wordwrap を無効にしたくないのですが、それは 2 つの悪のうち小さいほうです。


@André Neves、良い点です。ユーザーが編集できる場合は、そのようにします。一貫性が UI の直感性の基本的なルールであることに同意します。

4

6 に答える 6

33

同じ問題を解決したいときに、この質問に出くわしました。

これを行う最も簡単な方法は、System.Windows.Forms.RichTextBox に変更することです。この場合の ScrollBars プロパティは、RichTextBoxScrollBars.Both のデフォルト値のままにしておくことができます。これは、「必要に応じて水平スクロール バーと垂直スクロール バーの両方を表示する」ことを示します。この機能が TextBox で提供されるとよいでしょう。

于 2009-03-04T20:15:29.410 に答える
14

プロジェクトに新しいクラスを追加し、以下に示すコードを貼り付けます。コンパイル。ツールボックスの上部から新しいコントロールをフォームにドロップします。完璧ではありませんが、うまくいくはずです。

using System;
using System.Drawing;
using System.Windows.Forms;

public class MyTextBox : TextBox {
  private bool mScrollbars;
  public MyTextBox() {
    this.Multiline = true;
    this.ReadOnly = true;
  }
  private void checkForScrollbars() {
    bool scroll = false;
    int cnt = this.Lines.Length;
    if (cnt > 1) {
      int pos0 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(0)).Y;
      if (pos0 >= 32768) pos0 -= 65536;
      int pos1 = this.GetPositionFromCharIndex(this.GetFirstCharIndexFromLine(1)).Y;
      if (pos1 >= 32768) pos1 -= 65536;
      int h = pos1 - pos0;
      scroll = cnt * h > (this.ClientSize.Height - 6);  // 6 = padding
    }
    if (scroll != mScrollbars) {
      mScrollbars = scroll;
      this.ScrollBars = scroll ? ScrollBars.Vertical : ScrollBars.None;
    }
  }

  protected override void OnTextChanged(EventArgs e) {
    checkForScrollbars();
    base.OnTextChanged(e);
  }

  protected override void OnClientSizeChanged(EventArgs e) {
    checkForScrollbars();
    base.OnClientSizeChanged(e);
  }
}
于 2008-09-18T02:18:22.637 に答える
7

nobugzのソリューションには非常に微妙なバグがあり、ヒープが破損しますが、これはAppendText()を使用してTextBoxを更新している場合に限られます。

OnTextChangedからScrollBarsプロパティを設定すると、Win32ウィンドウ(ハンドル)が破棄されて再作成されます。ただし、OnTextChangedは、Win32編集コントロール(EditML_InsertText)の腸から呼び出され、その直後に、そのWin32編集コントロールの内部状態が変更されないことを期待します。残念ながら、ウィンドウが再作成されたため、その内部状態はOSによって解放され、アクセス違反が発生しました。

したがって、話の教訓は次のとおりです。nobugzのソリューションを使用する場合は、AppendText()を使用しないでください。

于 2009-03-20T15:47:12.557 に答える
7

また、いくつかの実験を行ったところ、有効にすると縦棒が常に表示され、有効にすると横棒が常に表示されることがわかりましたWordWrap == false

ここであなたが望むものを正確に手に入れることはできないと思います。ただし、ユーザーは強制しようとしている Windows の既定の動作よりも優れた動作を望んでいると思います。私があなたのアプリを使用していた場合、テキストが多すぎて予期しないスクロールバーに対応する必要があるという理由だけで、テキストボックスの領域が突然縮小した場合、おそらく気になるでしょう!

おそらく、アプリケーションを Windows のルック アンド フィールに従わせるだけでもよいでしょう。

于 2008-09-16T14:51:21.360 に答える
2

私は以下のコードである程度の成功を収めました。

  public partial class MyTextBox : TextBox
  {
    private bool mShowScrollBar = false;

    public MyTextBox()
    {
      InitializeComponent();

      checkForScrollbars();
    }

    private void checkForScrollbars()
    {
      bool showScrollBar = false;
      int padding = (this.BorderStyle == BorderStyle.Fixed3D) ? 14 : 10;

      using (Graphics g = this.CreateGraphics())
      {
        // Calcualte the size of the text area.
        SizeF textArea = g.MeasureString(this.Text,
                                         this.Font,
                                         this.Bounds.Width - padding);

        if (this.Text.EndsWith(Environment.NewLine))
        {
          // Include the height of a trailing new line in the height calculation        
          textArea.Height += g.MeasureString("A", this.Font).Height;
        }

        // Show the vertical ScrollBar if the text area
        // is taller than the control.
        showScrollBar = (Math.Ceiling(textArea.Height) >= (this.Bounds.Height - padding));

        if (showScrollBar != mShowScrollBar)
        {
          mShowScrollBar = showScrollBar;
          this.ScrollBars = showScrollBar ? ScrollBars.Vertical : ScrollBars.None;
        }
      }
    }

    protected override void OnTextChanged(EventArgs e)
    {
      checkForScrollbars();
      base.OnTextChanged(e);
    }

    protected override void OnResize(EventArgs e)
    {
      checkForScrollbars();
      base.OnResize(e);
    }
  }
于 2010-11-10T17:42:57.190 に答える