ScrollLabel for Smartphone 2003
为偶的NotesManager小程序写了一个带滚动条的Label控件,效果看起来象下面这样:

这个控件的实现思路说起来很简单,就是使用的一般Windows桌面程序中的窗口(Window)和视口(View)的概念。
考虑到Label本身不需要支持编辑的功能,出于效率的考虑,我在ScrollLabel控件中用一个Bitmap对象来保存Window的所有内容。在OnPaint中,如果发现Bitmap对象是空值(通常是第一次Paint),则根据当前Text的内容判断是否需要显示ScrollBar,并创建Bitmap对象,然后根据View的位置来显示应当显示在界面上的内容。以后每次Paint的时候,都只是根据滚动条的位置来计算View的位置,然后显示相应的Bitmap上的内容即可。当Text或者Font改变时,将原有的Bitmap销毁重新计算即可。整个OnPaint方法看起来象下面这样:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint (e);
if(bmpWindow == null)
{
Rectangle drawRect;
// Calculate the height of the window
SizeF size = e.Graphics.MeasureString(this.Text, this.Font);
rowHeight = size.Height;
float height = (size.Width / ClientSize.Width + 1) * rowHeight;
// Indicate if the scrollbar need to be shown.
if(height > ClientRectangle.Height)
{
// Recalculate the height of window.
height = (size.Width / (ClientSize.Width - scrollWidth)) * rowHeight + ClientSize.Height / 2;
// Show scrollbar
vs.Bounds = new Rectangle(this.ClientSize.Width - scrollWidth, 0,
scrollWidth, ClientSize.Height);
vs.LargeChange = (int)(ClientSize.Height / rowHeight);
vs.Maximum = (int)(height / rowHeight);
vs.Visible = true;
// Create window bitmap.
bmpWindow = new Bitmap(ClientSize.Width - scrollWidth, (int)height + 1);
drawRect = new Rectangle(0, 0, ClientSize.Width - scrollWidth, (int)height + 1);
}
else
{
bmpWindow = new Bitmap(ClientSize.Width, ClientSize.Height);
drawRect = this.ClientRectangle;
}
// Paint on the window bitmap.
Graphics g = Graphics.FromImage(bmpWindow);
g.FillRectangle(new SolidBrush(this.BackColor), drawRect);
g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), drawRect);
g.Dispose();
}
// Draw view.
e.Graphics.DrawImage(bmpWindow, 0, 0 - (int)rowHeight * vs.Value);
}
这个ScrollLabel的代码可以从这里下载。
不过这里使用的方法也有一些小缺陷,主要是源于目前版本的.NET CF不支持的一些功能。比如,为了得到作为Window的Bitmap的宽度和高度,我使用了MeasureString这个方法。但是目前版本的.NET CF中,MeasureString并不支持按给定宽度度量所需要的高度的功能,只能量出将所有的字画在一行上的宽度和高度。我的解决办法是,用MeasureString得到的高度作为行高,用MeasureString得到的宽度和整个ClientSize的宽度比值作为所有的行数,从而得到Window所需的高度。但是这样一来,就无法顾及由于英文的分词所带来的误差。比如MeasureString这个词,如果恰好在行尾,在Paint的时候它不会被截断,而时候整个的被放到下一行来显示。这样不断的叠加,最终在行数上是会产生一定的误差的。我暂时使用的解决方法是,对我用MeasureString得到的Window高度进行了1/2个ClientSize高度的误差补偿,这样你会发现,ScrollBar在滚动时并不是精确地滚动到最后一行,而是还会向下滚动一段空白区域。在大多数情况下,这段误差补偿是可以解决问题的,但是对于包含很多非常长的单词的情况,可能仍然会有问题。
更新后的NotesManager可以在这里下载。
posted on 2004-11-08 13:49:00 by sam1111 评论(14) 阅读(4992)
?
?