我编写程序将在大显示器上的多个列表框中显示数字列表,我的问题是有没有办法自动滚动列表框以显示框中的所有数据?
3 回答
通常,我会这样做:
listBox.SelectedIndex = listBox.Items.Count - 1;
listBox.SelectedIndex = -1;
但你也可以试试
int nItems = (int)(listBox.Height / listBox.ItemHeight);
listBox.TopIndex = listBox.Items.Count - nItems;
希望这可以帮助 :)
要直接控制滚动而不选择项目,您需要SetScrollPos
使用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
它会产生更好,更平滑的效果。然后,您可以轻松地包括加速和减速 - 可以选择在鼠标悬停时减速到停止,然后在鼠标移出时加速等。不过目前它只是不打球 - 我在某处的旧项目中有一个有效的滚动更新方法,所以如果我让它再次工作,我会更新它。
希望有帮助!
或者只需使用以下方法将您的项目插入顶部:
lbLog.Items.Insert(0,"LogItem");