Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows.Forms.Panel 32767 size limit

Tags:

c#

.net

winforms

I have an application that uses Windows.Forms.Panel to display a list of pictures. When the height of the panel exceeds 32767 pixels the rest of the content is simply cut off.

example:

Windows.Forms.Panel myPanel;

ArrayList pictureList;

foreach(pic in pictureList) {
    myPanel.Controls.Add(pic) // adds all the objects without complaints
}

In the example all elements are add to the panel without an error to be thrown, but after the panel has reached a size of 32767 no image is displayed anymore.

My question: Is it possible to break this limit and display more content in a panel?

I know that the approach is inconvinient in any way, but there is no time now to redesign the whole Application.

like image 426
Dyonisos Avatar asked Nov 09 '11 11:11

Dyonisos


3 Answers

This is an architectural limitation in Windows. Various messages that indicate positions in a window, like WM_MOUSEMOVE, report the position in a 32-bit integer with 16-bits for the X and 16-bits for the Y-position. You therefore cannot create a window that's larger than short.MaxValue. This isn't exactly a real problem, nobody has a monitor that's wider than 32,767 pixels and won't for a long time to come.

You'll have to do this differently. Like using Graphics.TranslateTransform() in a Paint method.

like image 78
Hans Passant Avatar answered Nov 03 '22 19:11

Hans Passant


LPARAM - A Data type of Windows used to pass message parameters to Windows Procedure. It is a 32 bit pointer which passes message as two parts i.e in High order(First 16 bits of 32 bits) and Low order(Second 16 bits of 32 bits).

  Where 
       High order is used to pass the height of the control and
       Low order is used to pass the width of the control

So if the height or width of the control exceeds 32762size, it shows error because

32767 is the highest number that can be represented in a signed 16bit integer.

like image 38
Tijo Tom Avatar answered Nov 03 '22 18:11

Tijo Tom


Solution without a paint method

I had this exact problem. I didn't want to have to re-write functionality that was already coded into my child controls. This routine manages the child controls via a scrollbar, and keeps the out-of-play ones hidden and just offscreen.

Public Class ManuallyScrollingPanel
  Inherits Panel

  Public WithEvents sbar As New System.Windows.Forms.VScrollBar

  Sub New()
    MyBase.New()
    Controls.Add(sbar)
    sbar.Visible = True
    Me.AutoScroll = False
  End Sub

  Sub SetScrollParams()
    If PanelPositions.Any Then
      Dim NewMax = CInt((From item In PanelPositions.Values Select item.Bottom).Max + 500) - Height
      If sbar.Maximum <> NewMax Then
        sbar.Maximum = NewMax
      End If
    End If
  End Sub

  Public Sub RegisterChildSize(pnl As Panel, DesiredBounds As Drawing.Rectangle)
    PanelPositions(pnl) = DesiredBounds
    SetScrollParams()
  End Sub

  Dim PanelPositions As New Dictionary(Of Panel, Drawing.Rectangle)

  Private Sub ManuallyScrollingPanel_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
    sbar.Top = 0
    sbar.Left = Width - sbar.Width
    sbar.Height = Me.Height
    SetScrollParams()
    sbar.LargeChange = CInt(Height * 0.9)
    sbar.SmallChange = CInt(Height * 0.2)
  End Sub

  Private Sub sb_Scroll(sender As Object, e As ScrollEventArgs) Handles sbar.Scroll
    ScrollTo(e.NewValue)
  End Sub

  Private Sub sb_ValueChanged(sender As Object, e As EventArgs) Handles sbar.ValueChanged
    ScrollTo(sbar.Value)
  End Sub

  Sub ScrollTo(pos As Integer)
    Me.AutoScroll = False
    For Each kvp In PanelPositions
      Dim VirtBounds = New Drawing.Rectangle(CInt(kvp.Value.Left), CInt(kvp.Value.Top - pos), CInt(kvp.Value.Width), CInt(kvp.Value.Height))
      If VirtBounds.Bottom < 0 Or VirtBounds.Top > Height Then
        ' it's not visible - hide it and position offscreen
        kvp.Key.Visible = False
        kvp.Key.Top = VirtBounds.Top
      Else
        ' Visible, position it
        kvp.Key.Top = VirtBounds.Top
        kvp.Key.Visible = True
      End If
    Next
  End Sub

End Class

Then, for each child control (mine were dynamically added, sounds like the OP was doing the same thing) make this call:

CType(Parent, ManuallyScrollingPanel).RegisterChildSize(Me, PanelObject.Bounds)

Note I pass in the child's bounds separately as I build the controls from DTOs to allow the same app+views to render as a web app and a windows app. Same with limiting it to panels. Refactor out as needed.

like image 42
FastAl Avatar answered Nov 03 '22 18:11

FastAl