没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
转帖|其它|编辑:郝浩|2011-01-14 11:47:26.000|阅读 7387 次
概述:滚动条换肤是C#WinForm中的难点,因为很多控件的滚动条是由系统来进行绘制的,所以滚动条的绘制就不得不使用大量的API函数来进行绘制。如果对API函数不熟悉的话,就很难达到自己想要的效果,而这部分本身就不是C#的强项,所以网上使用C++重绘滚动条的例子很多,但用C#写的确很少。
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
滚动条换肤是C#WinForm中的难点,因为很多控件的滚动条是由系统来进行绘制的,所以滚动条的绘制就不得不使用大量的API函数来进行绘制。如果对API函数不熟悉的话,就很难达到自己想要的效果,而这部分本身就不是C#的强项,所以网上使用C++重绘滚动条的例子很多,但用C#写的确很少。
先看一下效果图:
上图实现的是一个仿FoxMail的换肤控件的截图,其中实现了TreeView、Panel、DataGridView和ListBox的滚动条的换肤,下面介绍一下滚动条换肤的原来。
在网上搜了一下,滚动条换肤一般有两种方法实现。第一种方式比较变态,直接拦截系统绘制滚动条的消息,将绘制过程接管过来,这种方式显然不是C#的强项,不过网上已经有了C++的实现版本,如果对C++比较熟悉的话,可以研究一下,如果哪位用空改成C#的版本,希望可以给我发一份。
C++版本的滚动条换肤示例代码下载:/Files/liutao409/SkinSB.rar(这个例子实现的效果相当的不错,并且没有什么Bug,很值得研究一下)
第二种方法相对来说比较简单,就是将自己绘制的滚动条覆盖在控件的滚动条上面,然后让自己绘制的滚动条和控件自身的滚动条进行联动就可以了。关于如何自绘滚动条,网上应该可以找得到,我这里就不详细说了,只提供一个滚动条绘制的源代码给大家下载。
C#版自绘垂直滚动条示例代码下载:/Files/liutao409/customscrollbar_src.rar。
上面介绍了滚动条绘制需要处理的一些问题,下面的就是本文的重点,如何让自定义滚动条和控件的滚动条进行联动。下面我用DataGridview的滚动条的例子来说明。
其它地方我就不多说了,代码里面写得很明白,关键的水平和垂直滚动条的相关参数的说明给大家讲解一下,这个参数的算法绝对是原创,并且可以跟系统自带的滚动条高度的同步:
this._hScrollBarEx.Maximum = 需要滚动的区域的宽度;(包括显示区域和未显示的滚动区域的宽度,注意不包括行标题列)
this._hScrollBarEx.LargeChange = _hScrollBarEx.Maximum / _hScrollBarEx.Width + 显示区域的宽度(可显示的区域的宽度,注意不包括行标题列);
this._vScrollBarEx.Maximum = 显示区域包含的数据的行数 + _vScrollBarEx.Minimum + _vScrollBarEx.LargeChange(默认值为100) - 1;
public class DataGridViewEx : DataGridView
{
private int _displayRowCount = 0;
private int _displayWidth = 0;
private ScrollBarEx.HScrollBarEx _hScrollBarEx;
private ScrollBarEx.VScrollBarEx _vScrollBarEx;
public DataGridViewEx():base()
{
_hScrollBarEx = new HScrollBarEx();
_vScrollBarEx = new VScrollBarEx();
this.Controls.Add(_hScrollBarEx);
this.Controls.Add(_vScrollBarEx);
base.SetStyle(ControlStyles.UserPaint |ControlStyles.AllPaintingInWmPaint |ControlStyles.OptimizedDoubleBuffer, true);
this.HorizontalScrollBar.VisibleChanged += new EventHandler(ScrollBar_VisibleChanged);
this.VerticalScrollBar.VisibleChanged += new EventHandler(ScrollBar_VisibleChanged);
this.SizeChanged += new EventHandler(ScrollBar_VisibleChanged);
this._vScrollBarEx.ValueChanged += new EventHandler(VScrollBarEx_ValueChanged);
this._hScrollBarEx.ValueChanged += new EventHandler(HScrollBarEx_ValueChanged);
this.Scroll += new ScrollEventHandler(DataGridViewEx_Scroll);
this.ColumnHeadersHeightChanged += new EventHandler(ScrollBar_VisibleChanged);
this.ColumnWidthChanged += new DataGridViewColumnEventHandler(ScrollBar_VisibleChanged);
this.RowHeadersWidthChanged += new EventHandler(ScrollBar_VisibleChanged);
this.RowHeightChanged += new DataGridViewRowEventHandler(ScrollBar_VisibleChanged);
this.RowsAdded += new DataGridViewRowsAddedEventHandler(ScrollBar_VisibleChanged);
this.RowsRemoved += new DataGridViewRowsRemovedEventHandler(ScrollBar_VisibleChanged);
this.ColumnAdded += new DataGridViewColumnEventHandler(ScrollBar_VisibleChanged);
this.ColumnRemoved += new DataGridViewColumnEventHandler(ScrollBar_VisibleChanged);
this.DataSourceChanged += new EventHandler(ScrollBar_VisibleChanged);
SetScrollBarEx();
}
private void VScrollBarEx_ValueChanged(object sender, EventArgs e)
{
if (!this.dgvScroll)
{
this.FirstDisplayedScrollingRowIndex = _vScrollBarEx.Value;
Application.DoEvents();
}
}
private void HScrollBarEx_ValueChanged(object sender, EventArgs e)
{
if (!this.dgvScroll)
{
this.HorizontalScrollingOffset = _hScrollBarEx.Value;
GetDisplayWidth();
Application.DoEvents();
}
}
private void DataGridViewEx_Scroll(object sender, ScrollEventArgs e)
{
this.dgvScroll = true;
if (e.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
_vScrollBarEx.Value = this.FirstDisplayedScrollingRowIndex;
}
else
{
_hScrollBarEx.Value = this.HorizontalScrollingOffset;
}
this.dgvScroll = false;
}
private void ScrollBar_VisibleChanged(object sender, EventArgs e)
{
SetScrollBarEx();
}
private void SetScrollBarEx()
{
if (this.VerticalScrollBar.Visible)
{
_vScrollBarEx.Visible = true;
_vScrollBarEx.Location = new Point(this.DisplayRectangle.Width, 0);
this.VerticalScrollBar.SendToBack();
_vScrollBarEx.Height = this.DisplayRectangle.Height;
GetDisplayRowCount();
}
else
{
_vScrollBarEx.Visible = false;
}
if (this.HorizontalScrollBar.Visible)
{
_hScrollBarEx.Visible = true;
_hScrollBarEx.Location = new Point(0, this.DisplayRectangle.Height);
this.HorizontalScrollBar.SendToBack();
_hScrollBarEx.Width = this.DisplayRectangle.Width ;
GetDisplayWidth();
_hScrollBarEx.Value = this.HorizontalScrollingOffset;
}
else
{
_hScrollBarEx.Visible = false;
}
}
public int GetDisplayWidth()
{
int width = 0;
for (int i = 0; i < this.Columns.Count; i++)
{
width += this.Columns[i].Width;
}
_displayWidth = width;
this._hScrollBarEx.Maximum = width;
this._hScrollBarEx.LargeChange = _hScrollBarEx.Maximum / _hScrollBarEx.Width + this.DisplayRectangle.Width - this.RowHeadersWidth;
return width;
}
public int GetDisplayRowCount()
{
int j = 0;
int height = 0;
int i = this.FirstDisplayedScrollingRowIndex;
if (i < 0)
{
i = 0;
}
for (; i < this.Rows.Count; i++)
{
height += this.Rows[i].Height;
if (height < this.DisplayRectangle.Height - this.ColumnHeadersHeight)
{
j++;
}
else
{
break;
}
}
j = this.Rows.Count - j;
if (j < 0)
{
j = 0;
}
if (_displayRowCount != j)
{
_displayRowCount = j;
_vScrollBarEx.Maximum = j + _vScrollBarEx.Minimum + _vScrollBarEx.LargeChange - 1;
if (this.FirstDisplayedScrollingRowIndex < 0)
{
_vScrollBarEx.Value = 0;
}
else if (this.FirstDisplayedScrollingRowIndex > _vScrollBarEx.Maximum)
{
_vScrollBarEx.Value = _vScrollBarEx.Maximum;
}
else
{
_vScrollBarEx.Value = this.FirstDisplayedScrollingRowIndex;
}
}
return j;
}
}
DataGridview的滚动条不是由系统进行绘制的,所以滚动条的很多参数都是可以取到的,但是像Listbox或者Textbox这样的控件,滚动条的信息很多都不好获取,这个时候,就要使用API函数来进行处理了,但整个滚动条的覆盖方案还是可以参照上面的来进行,只是把一些参数的获取和设置改由API函数来完成就行了,当然在一些细节的地方会有所不同。
特别要注意的是下面两句:
我原来以为只要用SetScrollInfo设置控件的滚动条参数后控件就会自动滚动到指定的位置,但实际结果却不是这样的,必须还要调用PostMessage发送一个让控件滚动的消息控件才会滚动。
Win32API.SetScrollInfo(tvImageList.Handle,
(int)ScrollBarDirection.SB_VERT, ref info, true);
Win32API.PostMessage(tvImageList.Handle, Win32API.WM_VSCROLL, Win32API.MakeLong((short)Win32API.SB_THUMBTRACK, (short)(info.nPos)), 0);
好了,就写到这吧。希望对需要的朋友有所帮助!
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
文章转载自:网络转载面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号