Clearest code challenge
This is a real problem I had recently.
Suppose you have a form with OK and Cancel buttons. You want the buttons to be placed in the bottom-right corner of the form. Normally you'd place them where they go, then set their Anchor properties to Bottom, Right.
However, today I'm going to place an arbitrary limitation. You can't set the positions of the button controls in the designer, you have to write it in code.
Button _buttonCancel;
Button _buttonOK;
void PlaceButtons()
{
this._buttonCancel.Location = ???;
this._buttonOK.Location = ???;
}
I think the Cancel button should be 12 pixels from the bottom right corner. The OK button should be 12 pixels to the left of the Cancel button.
But here’s the real challenge: write the clearest code possible.
I know my solution. It’s clearer than what I would have written a few years ago, but I wonder if I could have done better. I’ll post mine in a few days, I guess.
Comments
- Anonymous
March 20, 2004
The following info will be needed in the equation:
1) FormDimensions
2) ButtonDimensions - Anonymous
March 20, 2004
Assuming that this is the Form and button sizes have already been set...
private const int Size buttonMargin = new Size(12, 12);
this._buttonCancel.Location.X = this.ClientRectangle.Right - buttonMargin.Width - this._buttonCancel.Width;
this._buttonCancel.Location.Y =
this.ClientRectangle.Bottom - buttonMargin.Height - this._buttonCancel.Height;
this._buttonOK.Location.X = this._buttonCancel.Location.X - buttonMargin.Width - this._buttonOK.Width;
this._buttonOK.Location.Y = this.ClientRectangle.Bottom - buttonMargin.Height - this._buttonOK.Height; - Anonymous
March 20, 2004
protected override void OnSizeChanged(EventArgs e) {
base.OnSizeChanged (e);
//instead of ctor put your code with layout logic here
}
btw why the heck VS auto completes using base.OnSizeChanged (e);
with a space after the method ?
nobody writes this way, not even MS :) - Anonymous
March 20, 2004
Isn't the Location X and Y immutable? I thought you had to create a new Point() class every time. Apart from that, my code would take the same form as DarthPedro's code. - Anonymous
March 20, 2004
Rich is right that the Location property is immutable, so you can't modify X & Y directly & must create a new object to replace it.
I'm assuming that correctness isn't the hard part here. I assume that most developers can solve the problem of placing the controls correctly. The challenge is clarity. - Anonymous
March 20, 2004
The comment has been removed - Anonymous
March 20, 2004
int margin = 12;
ControlMover okMover = new ControlMover(_buttonOK, this.ClientSize, margin);
okMover.MoveLeft();
okMover.MoveUp();
ControlMover cancelMover = new ControlMover(_buttonCancel, _buttonOK.Location, margin);
cancelMover.MoveLeft();
class ControlMover
{
Control _control;
int _margin;
public ControlMover(Control c, Point location, int margin)
{
_margin = margin;
_control = c;
_control.Location = location;
}
public ControlMover(Control c, Size location, int margin)
: this (c, new Point(location), margin)
{
}
public void MoveLeft(int delta)
{
_control.Location = Offset(- delta - _margin, 0);
}
Point Offset(int deltaX, int deltaY)
{
Point location = _control.Location;
location.Offset(deltaX, deltaY);
return location;
}
public void MoveLeft()
{
MoveLeft(_control.Width);
}
public void MoveUp(int delta)
{
_control.Location = Offset(0, - delta - _margin);
}
public void MoveUp()
{
MoveUp(_control.Height);
}
} - Anonymous
March 21, 2004
private const int Margin = 12;
int x = ClientRectangle.Right - Margin;
int y = ClientRectangle.Bottom + Margin + _buttonCancel.Height;
this._buttonCancel = New Point(x,y)
x -= buttonCancel.Width - Margin;
this._buttonOK = new Point(x,y) - Anonymous
March 21, 2004
The comment has been removed - Anonymous
March 24, 2004
Private Sub JayBazExample_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
_buttonCancel.PositionBottomRight(12, 12)
_buttonOK.PositionLeftOf(_buttonCancel, 12)
End Sub
End Class
Public Class PositionalButton
Inherits Button
Public Sub PositionBottomRight(ByVal VerticalPadding As Int32, ByVal HorizontalPadding As Int32)
Top = Me.Parent.ClientSize.Height - Me.Height - VerticalPadding
Left = Me.Parent.ClientSize.Width - Me.Width - HorizontalPadding
End Sub
Public Sub PositionLeftOf(ByVal Target As Button, ByVal VerticalPadding As Int32)
Top = Target.Top
Left = Target.Left - Me.Width - VerticalPadding
End Sub
End Class - Anonymous
March 24, 2004
_buttonCancel.Top = ClientSize.Height - _buttonCancel.Height - 12;
_buttonCancel.Left = ClientSize.Width - _buttonCancel.Width - 12;
_buttonOK.Top = _buttonCancel.Top;
_buttonOK.Left = _buttonCancel.Left - _buttonOK.Width - 12; - Anonymous
March 24, 2004
_buttonCancel.Location = new Point(ClientSize.Width - _buttonCancel.Width - 12, ClientSize.Height - _buttonCancel.Height - 12);
_buttonOK.Location = new Point(_buttonCancel.Left - _buttonOK.Width - 12, _buttonCancel.Top); - Anonymous
March 25, 2004
For me the clearest solution is simple
private void PlaceButtons()
{
const int BUTTON_MARGIN = 12;
_buttonCancel.Location = new System.Drawing.Point(
this.ClientRectangle.Width - _buttonCancel.Width - BUTTON_MARGIN,
this.ClientRectangle.Height - _buttonCancel.Height - BUTTON_MARGIN);
_buttonOK.Location = new System.Drawing.Point(
this.ClientRectangle.Width - _buttonCancel.Width - _buttonOK.Width - 2*BUTTON_MARGIN,
this.ClientRectangle.Height - _buttonOK.Height - BUTTON_MARGIN);
_buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
_buttonOK.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
} - Anonymous
June 09, 2009
PingBack from http://greenteafatburner.info/story.php?id=3736