设置ListBox的DrawMode为OwnerDrawFixed时水平滚动条不显示问题咨询
嘿,我帮你揪出了水平滚动条不显示的问题!
你现在的核心问题出在MeasureItem事件的逻辑上,还有个容易忽略的小细节,咱们拆解来看:
问题到底出在哪?
HorizontalExtent被反复覆盖成单一项的宽度:你每次在MeasureItem里把滚动范围设为当前项的宽度,如果后面遇到更短的项,这个值就会被缩小——滚动条只有当内容总宽度超过控件自身宽度时才会显示,所以最长项的宽度没被保留的话,滚动条自然不会出来。- (可选但重要)你用
Graphics.DrawString绘制文本,和TextRenderer.MeasureText的测量逻辑不一致,可能导致实际绘制的宽度和你测量的有偏差,就算滚动条出来了,文本显示也可能不对。
怎么修复?
第一步:修正MeasureItem,记录最大宽度
咱们加个全局变量存所有项里最宽的那个值,只在遇到更宽的项时才更新HorizontalExtent,同时别忘了开启水平滚动条属性:
private int _maxItemWidth = 0; // 用来存所有项里最宽的宽度 // 初始化时务必开启水平滚动条! articlesLB.DrawMode = DrawMode.OwnerDrawFixed; articlesLB.HorizontalScrollbar = true; articlesLB.MeasureItem += articlesLB_MeasureItem; articlesLB.DrawItem += articlesLB_SetColor; private void articlesLB_MeasureItem(object sender, MeasureItemEventArgs e) { string itemText = articlesLB.Items[e.Index].ToString(); int currentWidth = TextRenderer.MeasureText(itemText, articlesLB.Font).Width; // 只有当前项比之前的最大值宽,才更新滚动范围 if (currentWidth > _maxItemWidth) { _maxItemWidth = currentWidth; articlesLB.HorizontalExtent = _maxItemWidth; } }
第二步:优化绘制逻辑,保证测量和绘制一致
把Graphics.DrawString换成TextRenderer.DrawText,因为它和你用来测量宽度的TextRenderer.MeasureText是一套逻辑,不会出现宽度不匹配的问题:
private void articlesLB_SetColor(object sender, DrawItemEventArgs e) { if (e.Index < 0) return; ListBox listBox = (ListBox)sender; string itemText = listBox.Items[e.Index].ToString(); // 处理选中状态的背景色 Color bgColor = (e.State & DrawItemState.Selected) == DrawItemState.Selected ? Color.Yellow : listBox.BackColor; // 先绘制背景 using (SolidBrush bgBrush = new SolidBrush(bgColor)) { e.Graphics.FillRectangle(bgBrush, e.Bounds); } // 选择文本颜色 Brush textBrush = Brushes.Black; if (EditAOSideRB.Checked || EditAPinSideRB.Checked) { textBrush = itemText.Contains("* ") ? Brushes.DarkGreen : Brushes.Red; } // 用TextRenderer绘制,保证和测量的宽度完全匹配 TextRenderer.DrawText(e.Graphics, itemText, listBox.Font, e.Bounds, textBrush.Color, bgColor, TextFormatFlags.Left); // 绘制焦点矩形 if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) { e.DrawFocusRectangle(); } }
第三步:数据源更新时重置最大值
如果之后你要添加或删除ListBox的项,记得把_maxItemWidth重置为0,然后刷新控件,不然新的长项可能不会触发滚动条更新:
// 示例:更新ListBox数据源的方法 private void RefreshListBoxItems(List<string> newItems) { _maxItemWidth = 0; articlesLB.Items.Clear(); articlesLB.Items.AddRange(newItems.ToArray()); articlesLB.Refresh(); // 触发重新测量所有项的宽度 }
这样改完,水平滚动条就会根据最长项的宽度自动显示,文本超出边界时也能正常滚动啦~
内容的提问来源于stack exchange,提问作者GRF
相关产品推荐
相关产品推荐

