可滚动区域如何检索正在显示的内容的大小
本文关键字:显示 区域 滚动 何检索 检索 | 更新日期: 2023-09-27 18:35:46
在我的应用程序中,我遇到以下情况:
我有一个带有多个选项卡的选项卡控件的 Windows 窗体。每个选项卡都包含由其他类在启动时或运行时添加的任意内容。
我想设置选项卡的方式是,一旦表单太小,选项卡的面板无法显示所有内容,滚动条就会自动出现。
到目前为止,我尝试的是设置选项卡页面的AutoScroll = true
并将 AutoScrollMinSize
属性设置为面板的大小。
这并没有像预期的那样工作,因为小组的Size
似乎总是(200,100)独立于其内容。
我创建了一个小型示例应用程序(下面的代码)来演示该问题。如果调整窗体大小,则会看到仅当窗体小于面板(默认大小为 (200, 100))而不是面板中的文本框(大小为 300, 150)时,才会显示滚动条。如果手动设置AutoScrollMinSize
(取消注释第 34 行),它将按预期运行。
问题是:标签页如何检索其中显示内容的实际大小?
我可能会递归所有控件并尝试自己计算大小 - 但这感觉真的很糟糕。
PS:请不要建议将面板的大小设置为标签的大小,因为实际的面板比这复杂得多。
法典:
只需在Visual Studio中创建一个应用程序并使用以下代码覆盖Program.cs:
using System;
using System.Windows.Forms;
namespace ScrollbarTest
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var sampleForm = CreateSampleForm();
Application.Run(sampleForm);
}
private static Form CreateSampleForm()
{
var sampleForm = new Form() { };
var tabControl = new TabControl() { Dock = DockStyle.Fill };
var tabPage = new TabPage("Test") { AutoScroll = true };
sampleForm.Controls.Add(tabControl);
tabControl.TabPages.Add(tabPage);
var samplePanel = CreateSamplePanel();
tabPage.Controls.Add(samplePanel);
// this does not provide the right size
tabPage.AutoScrollMinSize = samplePanel.Size;
// uncomment this to make it work
//tabPage.AutoScrollMinSize = new System.Drawing.Size(300, 150);
return sampleForm;
}
private static Control CreateSamplePanel()
{
// As an example, create a panel with a text box with a fixed size.
var samplePanel = new Panel() { Dock = DockStyle.Fill };
var sampleSize = new System.Drawing.Size(300, 150);
var textBox = new TextBox()
{
Dock = DockStyle.Fill,
MinimumSize = sampleSize,
MaximumSize = sampleSize,
Size = sampleSize
};
samplePanel.Controls.Add(textBox);
return samplePanel;
}
}
}
samplePanel.Size
返回 (200,100)。在 CreateSamplePanel
方法中,如果设置samplePanel.MinimumSize = sampleSize;
则代码将起作用。
面板不计算其尺寸属性(例如 Size
、MinimumSize
、PreferredSize
)基于其子控件。您必须对面板进行子类化并提供该行为。即使是TableLayoutPanel
和FlowLayoutPanel
也没有正确计算PreferredSize
属性,这令人惊讶。至少,通常重写 GetPreferredSize(Size proposedSize)
方法,并选择性地让 MinimumSize
属性返回 PreferredSize
属性。
值得注意的是,DockStyle.Fill
和MinimumSize
是相互矛盾的。 TabPage
控件本质上是DockStyle.Fill
模式,这就是必须设置 AutoScrollMinSize
属性的原因。
编辑:是否有任何现有函数可以检索控件列表(递归)所需的总大小,例如通过它们的 X/Y 和大小?
这取决于主机容器本身(例如 TableLayoutPanel
)来正确计算其PreferredSize
,因为只有它知道其布局如何执行的确切细节。
您可以将 AutoSize
属性设置为 true,然后希望GetPreferredSize(...)/PreferredSize
计算正确的大小。对于TableLayoutPanel
,我记得有一种情况,它没有正确计算,我不得不对其进行子类化并覆盖GetPreferredSize(...)
方法。 除非AutoSize
属实,否则不会调用GetPreferredSize(...)
。
如果你在谈论一个普通的Panel
或UserControl
,默认情况下,这些使用所见即所得的LayoutEngine
,并且不计算PreferredSize
。您可以对高度进行子类化,然后计算最大control.X + control.Width
和相同的高度,并将其用作首选大小。
首先尝试将AutoSize
设置为 true,看看这是否适合您。否则,您可能必须重写GetPreferredSize(...)
方法。下面是一个粗略的例子:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var sampleForm = new Form() { AutoScroll = true };
var panel = new MyPanel() { AutoSize = true, AutoSizeMode = AutoSizeMode.GrowAndShrink, BackColor = Color.LightYellow };
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 3; j++) {
Button b = new Button { Text = "Button" + panel.Controls.Count, AutoSize = true };
b.Click += delegate {
MessageBox.Show("Preferred Size: " + panel.PreferredSize);
};
panel.Controls.Add(b, j, i);
}
}
sampleForm.Controls.Add(panel);
Application.Run(sampleForm);
}
private class MyPanel : TableLayoutPanel {
public override Size MinimumSize {
get {
return PreferredSize;
}
set {
}
}
public override Size GetPreferredSize(Size proposedSize) {
Size s = new Size();
int[] harr = new int[100];//this.RowCount];
int[] warr = new int[100];//this.ColumnCount];
foreach (Control c in this.Controls) {
var cell = this.GetPositionFromControl(c);
var ps = c.PreferredSize;
Padding m = c.Margin;
int w = ps.Width + m.Horizontal;
int h = ps.Height + m.Vertical;
if (w > warr[cell.Column])
warr[cell.Column] = w;
if (h > harr[cell.Row])
harr[cell.Row] = h;
}
foreach (int w in warr)
s.Width += w;
foreach (int h in harr)
s.Height += h;
return s;
}
}