Files
wg_cpso/UserControls/TextBoxes/AutoScrollTextBox.cs
2026-03-25 18:20:24 +08:00

123 lines
4.6 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace UserControls
{
public partial class AutoScrollTextBox : TextBox
{
[DllImport("user32.dll")]
static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
[DllImport("user32.dll")]
static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
// Variables
private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 4;
private const int SB_BOTTOM = 7;
private const int SB_OFFSET = 13;
//
private double _textCharWidth;
// Properties
public double TextCharWidth
{
get
{
if (_textCharWidth < 0)
{
SizeF sizeA = TextRenderer.MeasureText("A", Font);
SizeF sizeAA = TextRenderer.MeasureText("AA", Font);
//
_textCharWidth = sizeAA.Width - sizeA.Width;
}
return _textCharWidth;
}
}
// Constructors
public AutoScrollTextBox()
{
InitializeComponent();
//
_textCharWidth = -1;
}
// Methods
public void AutoScrollAppendText(string text)
{
if (text == null) return;
//
bool bottomFlag = false;
int VSmin;
int VSmax;
int sbOffset;
int savedVpos;
// Win32 magic to keep the textbox scrolling to the newest append to the textbox unless
// the user has moved the scrollbox up
sbOffset = (int)((this.ClientSize.Height - SystemInformation.HorizontalScrollBarHeight) / (this.Font.Height));
savedVpos = GetScrollPos(this.Handle, SB_VERT);
GetScrollRange(this.Handle, SB_VERT, out VSmin, out VSmax);
if (savedVpos >= (VSmax - sbOffset - 1))
bottomFlag = true;
this.AppendText(text);
if (bottomFlag)
{
GetScrollRange(this.Handle, SB_VERT, out VSmin, out VSmax);
savedVpos = VSmax - sbOffset;
bottomFlag = false;
}
SetScrollPos(this.Handle, SB_VERT, savedVpos, true);
PostMessageA(this.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
public void AutoScrollSetText(string text)
{
bool bottomFlag = false;
int VSmin;
int VSmax;
int sbOffset;
int savedVpos;
// Win32 magic to keep the textbox scrolling to the newest append to the textbox unless
// the user has moved the scrollbox up
sbOffset = (int)((this.ClientSize.Height - SystemInformation.HorizontalScrollBarHeight) / (this.Font.Height));
savedVpos = GetScrollPos(this.Handle, SB_VERT);
GetScrollRange(this.Handle, SB_VERT, out VSmin, out VSmax);
if (savedVpos >= (VSmax - sbOffset - 1))
bottomFlag = true;
//
if (text != this.Text)
this.Text = text;
//
if (bottomFlag)
{
GetScrollRange(this.Handle, SB_VERT, out VSmin, out VSmax);
savedVpos = VSmax - sbOffset;
bottomFlag = false;
}
SetScrollPos(this.Handle, SB_VERT, savedVpos, true);
PostMessageA(this.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * savedVpos, 0);
}
}
}