tags:

views:

96

answers:

2

WinForms (.NET 2) question:

Is there a way to keep elements at a proportional distance when the parent form(or panel) is resized?

Could I use Graphics.TransformPoints or Graphics.TransformVectors for this scope? How. alt text

EDIT:
TableLayoutPanel will not work because superposed elements should be accepted.

EDIT2:
This is my code:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using Microsoft.VisualBasic.PowerPacks;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        List<Point> points;
        List<Point> shapePoints;
        Matrix m;
        float dx, dy;

        public Form1()
        {
            InitializeComponent();

            points = new List<Point>();
            shapePoints = new List<Point>();
            foreach (Control c in this.Controls)
            {
                points.Add(c.Location);
            }

            foreach (Shape s in this.shapeContainer1.Shapes)
            {
                if (s is SimpleShape)
                {
                    shapePoints.Add((s as SimpleShape).Location);
                }
                else if (s is LineShape)
                {
                    shapePoints.Add((s as LineShape).StartPoint);
                }
            }

            m = new Matrix();
            dx = this.Width;
            dy = this.Height;

            // this code will allow(?) do not move this control
            this.shapeContainer1.Dock = DockStyle.Fill;
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            dx = this.Width / dx;
            dy = this.Height / dy;
            ApplyScale(dx, dy);

            dx = this.Width;
            dy = this.Height;

            base.OnSizeChanged(e);
        }

        private void ApplyScale(float dx, float dy)
        {
            //m.Reset();
            m.Scale(dx, dy);

            Point[] locations = points.ToArray();
            m.TransformVectors(locations);

            for (int i = 0; i < this.Controls.Count; i++)
            {
                this.Controls[i].Location = locations[i];
            }

            Point[] shapeLocations = shapePoints.ToArray();
            m.TransformVectors(shapeLocations);

            for (int i = 0; i < this.shapeContainer1.Shapes.Count; i++)
            {
                SimpleShape ss = this.shapeContainer1.Shapes.get_Item(i) 
                                                             as SimpleShape;
                if (ss != null)
                {
                    ss.Location = locations[i];
                    continue;
                }

                LineShape ls = this.shapeContainer1.Shapes.get_Item(i) 
                                                             as LineShape;
                if (ls != null)
                {
                    ls.StartPoint = locations[i];
                    ls.Scale(new SizeF(dx, dy));
                }
            }
        }
    }
}

This is what I get:

alt text

A: 

Put a docked (or anchored) Table Layout Panel on your form, and set all its columns/rows to be percentage sized.

You can then dock your controls in the cells and the cells will maintain proportion as the table layout is resized.

Edit:

For superposed elements, could you not increase the number of columns/rows in your TLP to accommodate?

If reduce the number of columns/rows and then add sub TLPs to the cells that require more positioning?

Pondidum
I have here element per cell restrictions. What if I have (half) superposed elements? See updated image.
serhio
if you don't have other ideas, please remove your answer, the question will be unanswered, so more frequented :) thanks
serhio
With TLP you just can't have superposed elements. You just can't reproduce the first image.
serhio
+1  A: 

This seems to work: In form load, I store the %-left and %-top for each control I want to resize. I store it in the Tag-property for easy access. Then in the form-resize event, I just calculate the new %-left and %-top for each control and position them out.

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    For Each c As Control In Me.Controls
        c.Anchor = AnchorStyles.None
        c.Tag = CInt((100 / Me.Width) * c.Left).ToString & "|" & CInt((100 / Me.Height) * c.Top).ToString
    Next
End Sub

Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
    For Each c As Control In Me.Controls
        c.Location = New Point((Me.Width / 100) * CInt(Split(c.Tag, "|")(0)), (Me.Height / 100) * CInt(Split(c.Tag, "|")(1)))
    Next
End Sub

Start:

alt text

After form resize: alt text

Stefan
(The size of the elements has not changed, its only looks that way because of how I copyed them and saved them as pictures...)
Stefan
I suppose this should be a performance leak when the form contains multiple controls say > 50.
serhio
If you are talking about hundreds of controls, then I would draw them as graphics in the paint-event instead and not moving around controls. Its pretty easy to implement eather way.
Stefan
Please a) accept the answer as correct. b) give reason why not, so I can correct or withdraw my answer. If you have questions about performance, then put them in the question, and Ill modify my answer from the new criteria.
Stefan
drawing a control? hm. First of all, I have, between others, TextBoxes, and secondly, even my rectangles(circles) should reply to events like Click, have tooltips, etc. As about make this as answer... maybe, but I'll wait (a moment) for a alternative, if it does not appear, I'll do it.
serhio
remark that you could use a structure like Point or Size instead split strings.
serhio
serhio, Sure, but my code was just a quick proof of concept, not production code.
Stefan