2

私はプログラムを書いて、大きなモニターのいくつかのリストボックスに数字のリストを表示します.私の質問は、ボックス内のすべてのデータを表示するためにリストボックスを自動スクロールする方法はありますか?

4

3 に答える 3

7

通常、私は次のようにします:

listBox.SelectedIndex = listBox.Items.Count - 1;
listBox.SelectedIndex = -1;

しかし、あなたも試すことができます

int nItems = (int)(listBox.Height / listBox.ItemHeight);
listBox.TopIndex = listBox.Items.Count - nItems;

お役に立てれば :)

于 2015-02-02T19:25:43.740 に答える
3

アイテムを選択せず​​にスクロールを直接制御するには、 の Win32SetScrollPosメソッドを使用する必要がありますUser32.dll。基本的なサポートを提供する拡張クラスを次に示します。

public class ScrollableListView : ListView
{
    private const int WM_VSCROLL = 0x115;

    private enum ScrollBar : int { Horizontal = 0x0, Vertical = 0x1 }

    public void SetScroll(int x, int y)
    {
        this.SetScroll(ScrollBar.Horizontal, x);
        this.SetScroll(ScrollBar.Vertical, y);
    }

    public void SetScrollX(int position)
    {
        this.SetScroll(ScrollBar.Horizontal, position);
    }

    public void SetScrollY(int position)
    {
        this.SetScroll(ScrollBar.Vertical, position);
    }

    [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
    private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

    [DllImport("user32.dll")]
    private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);

    private void SetScroll(ScrollBar bar, int position)
    {
        if (!this.IsDisposed)
        {
            ScrollableListView.SetScrollPos((IntPtr)this.Handle, (int)bar, position, true);
            ScrollableListView.PostMessage((IntPtr)this.Handle, ScrollableListView.WM_VSCROLL, 4 + 0x10000 * position, 0);
        }
    }
}

その後、X または Y スクロールをすばやく簡単に設定できます。これは、他のコントロールでも機能するはずです。


コントロールを自動的に上下にスクロールさせたい場合は、約 20 ミリ秒の間隔で繰り返しタイマーを設定する必要があります。スクロールの位置と方向を追跡し、それに応じてインクリメントまたはデクリメントし、これらのメソッドを使用して位置をコントロールに送信します。


アップデート:

上記の SetScrollPos メソッドには、主にスクロールバーの移動に関するいくつかの問題がありましたが、コンテンツには問題がありませんでした。これはおそらく小さな見落としにすぎませんが、それまでの間、「既成概念にとらわれない」MarqueeListView ソリューションを以下に示します。

まず、使用するスクロールバーを表す列挙型です。SB_HORIZこれらの (および)には、Win32 名の代わりに表示名を使用SB_VERTして、もう少しわかりやすくしました。

public enum ScrollBarDirection : int { Horizontal = 0x0, Vertical = 0x1 }

スクロール コマンド コード自体の別の列挙型 - Up ( SB_LINEUP)、Down ( SB_LINEDOWN)、および EndScroll ( SB_ENDSCROLL) 以外のすべてを削除しました。EndScroll は、スクロール メッセージの後に、コントロールに更新を通知するために必要です。

public enum ScrollCommand : int { Up = 0x0, Down = 0x1, EndScroll = 0x8 }

そして最後にクラスそのもの。基本的に、20 ミリ秒ごとに下にスクロールして開始します (デフォルトでは、これは MarqueeSpeed プロパティで変更できることに注意してください)。次に、スクロール位置を取得し、前回と比較します。スクロール バーの動きが止まると、方向が逆になります。これは、GetScrollInfoメソッドで発生していた問題を回避するためです。

public class MarqueeListView : ListView
{
    protected const int WM_VSCROLL = 0x115;

    private ScrollCommand scrollCommand;
    private int scrollPositionOld;
    private Timer timer;

    public MarqueeListView()
        : base()
    {
        this.MarqueeSpeed = 20;

        this.scrollPositionOld = int.MinValue;
        this.scrollCommand = ScrollCommand.Down;

        this.timer = new Timer() { Interval = this.MarqueeSpeed };
        this.timer.Tick += (sender, e) =>
        {
            int scrollPosition = MarqueeListView.GetScrollPos((IntPtr)this.Handle, (int)ScrollBarDirection.Vertical);
            if (scrollPosition == this.scrollPositionOld)
            {
                if (this.scrollCommand == ScrollCommand.Down)
                {
                    this.scrollCommand = ScrollCommand.Up;
                }
                else
                {
                    this.scrollCommand = ScrollCommand.Down;
                }
            }
            this.scrollPositionOld = scrollPosition;

            MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)this.scrollCommand, IntPtr.Zero);
            MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)ScrollCommand.EndScroll, IntPtr.Zero);
        };
        this.timer.Start();
    }

    public int MarqueeSpeed
    {
        get
        {
            return this.timer.Interval;
        }
        set
        {
            this.timer.Interval = value;
        }
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern int GetScrollPos(IntPtr hWnd, int nBar);

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    protected static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
}

最後に、これをテストするための簡単な Main メソッドを次に示します。

    private static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        Form form = new Form() { StartPosition = FormStartPosition.CenterScreen, Width = 1280, Height = 720 };
        MarqueeListView list = new MarqueeListView() { View = View.Tile, Dock = DockStyle.Fill };
        for (int i = 0; i < 1000; i++) { list.Items.Add(Guid.NewGuid().ToString()); }
        form.Controls.Add(list);

        Application.Run(form);
    }

これは必ずしも「適切な」または最善の方法であるとは限りませんが、別のアプローチがいくつかのアイデアを与えるかもしれないと考えました!

私はSetScrollPos、はるかに優れた、よりスムーズな効果をもたらすものを使用したいと考えていました. 次に、加速と減速を簡単に含めることができます-オプションで、マウスオーバーで停止して減速し、マウスアウトで加速するなど. 、それで、再び機能するようになったら、これを更新します。

それが役立つことを願っています!

于 2015-02-02T22:59:37.670 に答える