2013-04-10 76 views
1

如何在保持縱橫比(與實際圖像或其SizeMode相互依賴)的同時將PictureBox組件的比例縮放到最適合屏幕上的給定空間?將FlowLayout中的組件縮放到儘可能大的位置

我測試了設置FlowLayout的Dock和PictureBox的填充。我還使用面板作爲包裝進行了測試,並測試了AutoSize和AutoSizeMode的不同設置。

要給出有關背景的更多信息:我想在應用程序的視口中動態添加和刪除圖像,所以TableLayout首先是靜態的。我不得不承認,我也在考慮手動計算一個位置的大小 - 或者動態調整TableLayout的行數和列數 - 但是在我看來,容易出錯。我認爲有一個FlowLayout和自動調整大小的組件應該是正確的方式 - 但它似乎不以這種方式工作。 (作爲網頁開發人員,我只是想「浮動圖像左」,「寬度和高度設置爲'自動'」,不滾動。)

圖像應該可視化這一點:第一個數字應該指出佈局,如果只有一個PictureBox - 它佔用整個空間(或者給定高寬比時儘可能大)。第二個顯示如果有兩個(三個或四個)圖像,我希望佈局如何。第三個數字基本上顯示了具有三(至六)個圖像的調整大小的窗口。

我有遺漏嗎?

Desired behaviour of PictureBox components on dynamically adding more PictureBox components or resizing the application

+0

您應該使用TableLayoutPanel而不是FlowLayoutPanel,但是您的文章沒有描述您將使用的邏輯確定您希望使用多少列和多少行。這個邏輯很可能是你的自定義代碼。 – LarsTech 2013-04-10 17:05:28

+0

謝謝,實際上這是問題的一部分。我只是適應了一些描述。行的數量應該是(至少那會很好),隱含地確定圖像的當前數量和給定(固定)寬高比,例如對於所有圖像爲4:3。 – 2013-04-11 11:53:34

回答

0

該代碼段執行此操作:

它安排在相對於縱橫比的一個容器內的可見的控件(參見編碼R變量),並使用該容器邊距值來獲得項目之間的水平和垂直間隙。容器的填充也被處理。

public static void Arrange(Control container) 
{ 
    var H = container.DisplayRectangle.Height; 
    var W = container.DisplayRectangle.Width; 
    var N = container.Controls.OfType<Control>().Count(c => c.Visible); 
    var R = 4/3d; // item aspect ratio 

    var margin = container.Margin; 
    var padding = container.Padding; 

    var horizontalGap = margin.Left + margin.Right; 
    var verticalGap = margin.Top + margin.Bottom; 

    if (N == 0) 
     return; 

    var bestSizedItem = (

     // Try n rows 
     Enumerable.Range(1, N).Select(testRowCount => 
     { 
      var testItemHeight = (H - verticalGap * (testRowCount - 1))/testRowCount; 

      return new 
      { 
       testColCount = (int)Math.Ceiling((double)N/testRowCount), 
       testRowCount = testRowCount, 
       testItemHeight = (int)testItemHeight, 
       testItemWidth = (int)(testItemHeight * R) 
      }; 
     }) 

     // Try n columns 
     .Concat(
     Enumerable.Range(1, N).Select(testColCount => 
     { 
      var testItemWidth = (W - horizontalGap * (testColCount - 1))/testColCount; 

      return new 
      { 
       testColCount = testColCount, 
       testRowCount = (int)Math.Ceiling((double)N/testColCount), 
       testItemHeight = (int)(testItemWidth/R), 
       testItemWidth = (int)testItemWidth 
      }; 
     }))) 

     // Remove when it's too big 
     .Where(item => item.testItemWidth * item.testColCount + horizontalGap * (item.testColCount - 1) <= W && 
         item.testItemHeight * item.testRowCount + verticalGap * (item.testRowCount - 1) <= H) 

     // Get the biggest area 
     .OrderBy(item => item.testItemHeight * item.testItemWidth) 
     .LastOrDefault(); 

    Debug.Assert(bestSizedItem != null); 

    if (bestSizedItem == null) 
     return; 

    int x = container.DisplayRectangle.X; 
    int y = container.DisplayRectangle.Y; 

    foreach (var control in container.Controls.OfType<Control>().Where(c => c.Visible)) 
    { 
     control.SetBounds(x, y, 
      bestSizedItem.testItemWidth, 
      bestSizedItem.testItemHeight); 

     x += bestSizedItem.testItemWidth + horizontalGap; 
     if (x + bestSizedItem.testItemWidth - horizontalGap > W) 
     { 
      x = container.DisplayRectangle.X; 
      y += bestSizedItem.testItemHeight + verticalGap; 
     } 
    } 
} 

我把Gist這個片段中,所以如果你願意,你可以作出貢獻。