Question How to set TableLayoutPanel cell's size programitacally

kfirba

Well-known member
Joined
Dec 29, 2012
Messages
77
Programming Experience
1-3
I'm trying to make a TableLayoutPanel with PictureBox + Label in each cell. I have got it all right but I just can't set the cells sizes to be the same! I'm trying to have 4 columns with endless number of rows, and I would like the cell to be in the Label width, unless the Label width is smaller than thePicture width.
For now, my code pretty much works, it just doesn't set the cell size because I have no idea how to do it.

Output image at the bottom of the post

Here is my code:

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim movieN As Integer = MoviesDataSet.movies.Rows.Count
        Dim tablePanel As New TableLayoutPanel


        With tablePanel
            .Size = New Point(650, 450)
            .ColumnCount = 4
            .GrowStyle = TableLayoutPanelGrowStyle.AddRows
            .AutoScroll = True
            .Margin = New System.Windows.Forms.Padding(0)
            .Location = New System.Drawing.Point(5, 50)
            .CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset
        End With
       


        For Each MovieRow As DataRow In MoviesDataSet.Tables("movies").Rows
 
            Dim myLabel As New Label
            Dim myPicture As New PictureBox
            Dim container As New Panel
          
         
            myLabel.Text = MovieRow("movieName")
            myLabel.Location = New System.Drawing.Point(30, 110)
            With myPicture
                .Image = Image.FromFile(MovieRow("moviePhoto"))
                .Tag = MovieRow("ID")
                .Size = New System.Drawing.Size(100, 100)
                .SizeMode = PictureBoxSizeMode.StretchImage
                .Location = New System.Drawing.Point(2, 2)
                .Cursor = Cursors.Hand
            End With


          
            With container
                .Dock = DockStyle.Fill
                .Margin = New System.Windows.Forms.Padding(0)
                .Controls.Add(myPicture)
                .Controls.Add(myLabel)
            End With




            With tablePanel.Controls


                .Add(container)


            End With


            AddHandler myPicture.Click, AddressOf MyPictureClickEvent
        Next
        Me.Controls.Add(tablePanel)
    End Sub




The output I get:



As you can see, the cell's width and height is just not right >.<

Thanks in advance!
 
This is the code designer generates:
        Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
        Me.TableLayoutPanel1.ColumnStyles.Add(New System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50.0!))
You can try changing settings in designer and looking at the code it generates.

If you need to dynamically change one of the columns styles you can retrive it from the ColumnStyles collection and modify it, for example:
Me.TableLayoutPanel1.ColumnStyles(1).Width = 123
 
Thanks!, that solves the columns problem, but what do I have to do in order to set the height of all of the rows to he auto sized
 
Design your first row to be autosize style and the rest will follow same style.
 
Design your first row to be autosize style and the rest will follow same style.

Thanks a lot! I didn't know its gonna follow the same style ;)!

Edit:
I have tried what you told me to do, and the columns just work perfect, but the I just can't make it work with the rows as well :s
 
Last edited:
What is it you can't make work with rows?
 
What is it you can't make work with rows?

I can't set their height property to by autosized :s
My result for now is, 4 columns as I wanted, but the first 3 rows are very short and the last row is very large. I just can't set the row size to be sized according to the content the row has
 
The last row does seem to fill the remaining of the table if previous rows can't. A possible solution to prevent last row "stretching" could be to add a last dummy row with an empty Panel (with Height=0).
 
The last row does seem to fill the remaining of the table if previous rows can't. A possible solution to prevent last row "stretching" could be to add a last dummy row with an empty Panel (with Height=0).

I'm not really sure that it my problem because my first rows aren't having the full height that they need, the rows height is way too small and can't contain the picturebox and the label.

Here is a photo to demonstrate the problem:





The code I'm using:

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim movieN As Integer = MoviesDataSet.movies.Rows.Count
        Dim tablePanel As New TableLayoutPanel


        With tablePanel
            .Size = New Point(Me.ClientRectangle.Width - 10, Me.ClientRectangle.Bottom - 55)
            .ColumnCount = 4
            .GrowStyle = TableLayoutPanelGrowStyle.AddRows
            .AutoScroll = True
            .Margin = New System.Windows.Forms.Padding(0)
            .Location = New System.Drawing.Point(5, 50)
            .CellBorderStyle = TableLayoutPanelCellBorderStyle.Inset
            .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 25.0!))
            .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 25.0!))
            .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 25.0!))
            .ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 25.0!))
            .Anchor = AnchorStyles.Bottom Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Top
        End With
        


        For Each MovieRow As DataRow In MoviesDataSet.Tables("movies").Rows
         
            Dim myLabel As New Label
            Dim myPicture As New PictureBox
            Dim container As New Panel
          
           
            myLabel.Text = MovieRow("movieName")
            myLabel.AutoSize = True
            myLabel.Location = New System.Drawing.Point(30, 110)
            With myPicture
                .Image = Image.FromFile(MovieRow("moviePhoto"))
                .Tag = MovieRow("ID")
                .Size = New System.Drawing.Size(100, 100)
                .SizeMode = PictureBoxSizeMode.StretchImage
                .Location = New System.Drawing.Point(2, 2)
                .Cursor = Cursors.Hand
            End With


            With container
                .Dock = DockStyle.Fill
                .Margin = New System.Windows.Forms.Padding(0)
                .Controls.Add(myPicture)
                .Controls.Add(myLabel)
            End With




            With tablePanel.Controls


                .Add(container)


            End With


             AddHandler myPicture.Click, AddressOf MyPictureClickEvent
        Next


        Me.Controls.Add(tablePanel)
    End Sub

 
I got an answer. In order to set the height of the row, all you have to do is is to add this:

tablePanel.RowStyles.Add(New RowStyle(SizeType.Absolute, 150))you should add this line after adding the Panel into the TableLayoutPanel
 
That is fantastic, but I wonder, why do you write all that code for creating TableLayoutPanel and configuring it (With tablePanel code block), can't this be done in designer?
 
Another thought, what you have posted here looks less of a table and more of a flow, consider using FlowLayoutPanel control instead.

I'm going to address another issue also, to me your 'container' Panel with a PictureBox and Label appears as a typical UserControl, something you can easier and with more flexibility set up in designer. Let's say you do this and call this control MovieTile, add a PictureBox called MoviePhoto and a Label called MovieName, then add this constructor to it:
    Public Sub New(name As String, photo As String, id As String)
        InitializeComponent()
        Me.MovieName.Text = name
        Me.MoviePhoto.ImageLocation = photo
        Me.Tag = id
    End Sub

Now in this example the loop adds instances of MovieTile to a FlowLayoutPanel (variable 'flow'), using your strongly typed MoviesDataSet dataset, with just one line of code:
        For Each m In MoviesDataSet.movies
            flow.Controls.Add(New MovieTile(m.movieName, m.MoviePhoto, m.ID))
        Next

How about that for Visual Basic?
 
Another thought, what you have posted here looks less of a table and more of a flow, consider using FlowLayoutPanel control instead.

I'm going to address another issue also, to me your 'container' Panel with a PictureBox and Label appears as a typical UserControl, something you can easier and with more flexibility set up in designer. Let's say you do this and call this control MovieTile, add a PictureBox called MoviePhoto and a Label called MovieName, then add this constructor to it:
    Public Sub New(name As String, photo As String, id As String)
        InitializeComponent()
        Me.MovieName.Text = name
        Me.MoviePhoto.ImageLocation = photo
        Me.Tag = id
    End Sub

Now in this example the loop adds instances of MovieTile to a FlowLayoutPanel (variable 'flow'), using your strongly typed MoviesDataSet dataset, with just one line of code:
        For Each m In MoviesDataSet.movies
            flow.Controls.Add(New MovieTile(m.movieName, m.MoviePhoto, m.ID))
        Next

How about that for Visual Basic?

I guess that is a code way to do it. Just to make it clearer, you created the flow panel and the picture box and the label at design?
And if so, you are creating an instance of those everytime and adding that into a flow panel?
I can't try it at the moment since I'm not home yet, but I'm gonna give it a shot once I come back home, your idea seems interesting. Just please explain me where you declare the Flow panel, Pictureboxe and the Label.

Thanks!
 
Back
Top