2014-12-30 42 views
2

在我的应用程序中,我遇到了以下情况:可滚动区域如何检索显示内容的大小?

我有一个带有多个选项卡的选项卡控件的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; 
     } 
    } 
} 
+0

标签页不知道面板包含。为什么不在面板上设置滚动条。 –

+0

在这种情况下,我会在面板上遇到同样的问题。面板通常由一个TableLayoutPanel和几个带有几个控件的子面板组成。 –

回答

1

samplePanel.Size回报率(200,100)。在您的CreateSamplePanel方法中,如果您设置了samplePanel.MinimumSize = sampleSize;,那么您的代码将起作用。

面板根据其子控件不计算其大小属性(例如,Size,MinimumSize,PreferredSize)。您将不得不继承Panel并提供该行为。即使TableLayoutPanelFlowLayoutPanel也不能正确计算PreferredSize属性,这是令人惊讶的。通常情况下,您通常会覆盖GetPreferredSize(Size proposedSize)方法,并可选地让MinimumSize属性返回PreferredSize属性。

值得注意的是,DockStyle.FillMinimumSize彼此不一致。 TabPage控件本质上是DockStyle.Fill模式,这就是为什么您必须设置AutoScrollMinSize属性。

编辑:是否存在任何现有的函数来检索控制列表的总体所需大小(递归地),例如,通过他们的X/Y和大小?

它取决于主机容器本身(例如,TableLayoutPanel)正确计算其PreferredSize,因为只有它知道其布局如何执行的确切细节。

您可以将AutoSize属性设置为true,然后希望GetPreferredSize(...)/PreferredSize计算出正确的大小。对于TableLayoutPanel,我记得有一种情况是计算不正确,我不得不对它进行子类化并覆盖GetPreferredSize(...)方法。除非AutoSize为真,否则将不会调用GetPreferredSize(...)

如果你谈论的是一个普通的PanelUserControl,默认情况下这些使用所见即所得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; 
     } 
    } 
+0

事情是在我的实际应用程序中,我没有'sampleSize'。没有任何现有的函数可以递归地检索控制列表的总需求大小,例如,通过他们的X/Y和大小? –

+0

在编辑的问题中查看答案。 – Loathing

相关问题