我在发帖之前进行了搜索,但无法找到与我的问题相近的内容。
我需要弄清楚的是如何给出图片盒的最佳宽度和高度(比例为4:3),给定要显示的盒子数量和可用空间。
现在,它并不像简单地将可用空间除以所需的盒子数一样简单,因为可用空间不是一致的形状,而是两个尺寸可能不同的矩形(见图) ,它是 a + b 空间。
如果事实上,我已经尝试从那里开始使用以下代码:
Private Sub LayoutSnapshots()
Dim lTotalSpace As Single, lSnapsize As Single, sXSize As Single, sYSize As Single
Dim I As Integer, J As Integer, X As Integer = 0, Y As Integer = 0, oPic As PictureBox
' bSnaps is the number of picture boxes to be displayed
If stSetting.bSnaps = 0 Then Exit Sub
' oSnaps is a List(Of PictureBoxe) to groupp the actual picture boxes
If oSnaps.Count > 0 Then
For Each oCtrl As PictureBox In oSnaps
Me.Controls.Remove(oCtrl)
Next
End If
oSnaps.Clear()
' Calculating the a+b space shown on the picture
lTotalSpace = ((Me.ClientSize.Height - MenuStrip1.Height) * Me.ClientSize.Width) - ((picPreview.Width + iMargin) * (picPreview.Height + iMargin))
If lTotalSpace < 1 Then
MsgBox("Window is too small. Please adjust one of these settings : Window size, Snapshots count, Live free view size.", MsgBoxStyle.ApplicationModal Or MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
Exit Sub
End If
'calculating a single picture's size by dividing total space by the number of snaps
lSnapsize = Math.Truncate(lTotalSpace / stSetting.bSnaps)
'Calculating Height and Width, with 4:3 ratio
sXSize = Math.Truncate(Math.Sqrt((4 * lSnapsize) / 3))
sYSize = Math.Truncate(Math.Sqrt((3 * lSnapsize) / 4))
For I = 1 To stSetting.bSnaps
If oPic IsNot Nothing Then oPic = Nothing
oPic = New PictureBox
oPic.BackColor = Color.White
oPic.BorderStyle = BorderStyle.FixedSingle
oPic.Size = New Size(sXSize - 1, sYSize - 1)
oPic.Location = New Point(X * sXSize, (Y * sYSize) + MenuStrip1.Height)
oSnaps.Add(oPic)
' Layed them successively on screen, need to optimize this
If ((X + 2) * sXSize) > (Me.ClientSize.Width) Then
X = 0
Y += 1
Else
X += 1
End If
Next
For Each oCtrl As PictureBox In oSnaps
Me.Controls.Add(oCtrl)
Next
End Sub
但很明显,随着窗口调整大小的所有可能性,我无法想出任何实用的方法来优化它。
我很确定这与&#34;运营研究&#34;有关,因为我记得当我还是学生的时候我们做过这样的优化问题,但我不确定如何实际对此进行建模,或者即使它可以通过线性编程来解决。
答案 0 :(得分:1)
我已经弄明白了。解决方案是一种强大的力量&#34;技术,它并不总是返回最佳但是误差只是几个像素。我使用下面的代码,它可以工作,但它可能需要在间距方面进一步优化。由于我现在有时间压力,我无法对所有内容发表评论,但仍想分享答案,所以只需花一些时间来分析它:
Private Sub LayoutSnapshots()
Dim sA As Single, sB As Single, sTotal As Single, sSnap As Single, sWidth As Single, sHeight As Single
Dim iCount As Integer = stSetting.bSnaps, iFit As Integer, iX As Integer, iY As Integer, iYg As Integer, I As Integer
Dim rA As Rectangle, rB As Rectangle, oPic As PictureBox, lpLoc As New List(Of Point), pLoc As New Point
Static bWarn As Boolean
Dim gPic As Graphics
' bSnaps is the number of picture boxes to be displayed
If stSetting.bSnaps = 0 Then Exit Sub
' If controls already on form, remove them and start form scratch
If oSnaps.Count > 0 Then
For Each oCtrl As PictureBox In oSnaps
Me.Controls.Remove(oCtrl)
Next
End If
' oSnaps is a List(Of PictureBox) grooping the picture boxes. Clear it for now
oSnaps.Clear()
'sA, sB are the sizes of spaces A and B respectively
sA = (Me.ClientSize.Width * (Me.ClientSize.Height - (MenuStrip1.Height + picPreview.Height + iMargin)))
sB = ((Me.ClientSize.Width - (picPreview.Width + iMargin)) * (picPreview.Height + iMargin))
' Total free space
sTotal = sA + sB
' This condition is important. It ensures there is at least one solution
' before entering the loops bellow. Otherwise we might get stuck in an infinite loop
If (sTotal < (stSetting.bSnaps * stSetting.bSnaps)) Then
' bWarn is a static boolean. Since this Sub is called from Form_Resize event, we
' want to warn the user only once when there is no space.
' Otherwise it becomes annoying.
If bWarn Then MsgBox("Window is too small. Please adjust one of these settings : Window size, Snapshots count, Live free view size.", MsgBoxStyle.ApplicationModal Or MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
bWarn = False
Exit Sub
End If
bWarn = True
Me.UseWaitCursor = True
Do
'rA, rB are the bounding rectangles of spaces A and B respectively
rA = New Rectangle(0, MenuStrip1.Height, Me.ClientSize.Width, Me.ClientSize.Height - (MenuStrip1.Height + picPreview.Height + iMargin))
rB = New Rectangle(0, picPreview.Top, Me.ClientSize.Width - (picPreview.Width + iMargin), picPreview.Height + iMargin)
' A single box's size
sSnap = Math.Truncate(sTotal / iCount)
' Width and Height with 4:3 aspect ratio.
sWidth = Math.Truncate(Math.Sqrt((4 * sSnap) / 3))
sHeight = Math.Truncate(Math.Sqrt((3 * sSnap) / 4))
' iFit keeps track of how many boxes we could fit in total
iFit = 0
iYg = 0
lpLoc.Clear()
' It would be a bit too long to explain the next block of code and I have a deadline to meet
' I'll comenting on that later
iX = 0
iY = 0
Do While (rA.Height >= ((sHeight * (iY + 1)) + 1))
If (((iX + 1) * sWidth) + 1) <= rA.Width Then
iFit += 1
lpLoc.Add(New Point(rA.X + ((iX * sWidth) + 1), rA.Y + ((iYg * sHeight) + 1)))
iX += 1
Else
iX = 0
iY += 1
iYg += 1
End If
Loop
'Add unused space from A to B.
rB.Height = rB.Height + (rA.Height - ((iYg * sHeight) + 1))
iX = 0
iY = 0
Do While (rB.Height >= ((sHeight * (iY + 1)) + 1))
If (((iX + 1) * sWidth) + 1) <= rB.Width Then
iFit += 1
lpLoc.Add(New Point(rB.X + ((iX * sWidth) + 1), rA.Y + ((iYg * sHeight) + 1)))
iX += 1
Else
iX = 0
iY += 1
iYg += 1
End If
Loop
Application.DoEvents()
iCount += 1
Loop While iFit < stSetting.bSnaps
' Add controls to form. Lay them one next to each other.
iX = 0
iY = 0
For I = 1 To stSetting.bSnaps
If oPic IsNot Nothing Then oPic = Nothing
oPic = New PictureBox
oPic.BackColor = Color.Cyan
oPic.BorderStyle = BorderStyle.FixedSingle
oPic.Size = New Size(sWidth - 1, sHeight - 1)
oPic.Location = lpLoc(I - 1)
' Just for debugging, displays index of each box inside it.
oPic.Image = New Bitmap(oPic.Width, oPic.Height)
gPic = Graphics.FromImage(oPic.Image)
gPic.DrawString(I, New Font("Arial", 10, FontStyle.Regular), Brushes.Red, New Point(0, 0))
oSnaps.Add(oPic)
Me.Controls.Add(oSnaps.Last)
Next
'Catch Ex As Exception
'Finally
Me.UseWaitCursor = False
'End Try
End Sub
P.S:如果您愿意,请随时为代码添加更多说明。