Reputation: 3
trying to learn programming and been experimenting somewhat. Ran into a little problem that I haven't been able to find a solution for. I have a programmatically created button and a click event that programmatically creates a new form. The form has some created labels, as well as a custom border. The same custom border is used on the main form and works even with auto size on and dynamically created content that changes the size of it. But on this programmatically created form the border only shows on the left and top sides, and I haven't been able to find an answer or solve it by experimentation.
Not sure how much code that is enough, but I made a simplified program showing the problem. It was simplified from the code of my program which uses hundreds of programmatically created buttons and several arrays of information which fills the labels used on the myForm form, so some things might seem strange since I removed the arrays and button creation process.
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace StackoverflowSample
{
public partial class Form1 : Form
{
private Button myButton;
/// <summary>
/// Borrowed code snippet for custom border: http://stackoverflow.com/q/5092216. Would have preferred no to do dllimport yet, but will let it pass this time.
/// </summary>
/// <param name="nLeftRect"></param>
/// <param name="nTopRect"></param>
/// <param name="nRightRect"></param>
/// <param name="nBottomRect"></param>
/// <param name="nWidthEllipse"></param>
/// <param name="nHeightEllipse"></param>
/// <returns></returns>
[DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
private static extern IntPtr CreateRoundRectRgn
(
int nLeftRect, // x-coordinate of upper-left corner
int nTopRect, // y-coordinate of upper-left corner
int nRightRect, // x-coordinate of lower-right corner
int nBottomRect, // y-coordinate of lower-right corner
int nWidthEllipse, // height of ellipse
int nHeightEllipse // width of ellipse
);
public Form1()
{
InitializeComponent();
this.BackColor = Color.White;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, 0, 0, 0, 0)); // Since our form is dynamically created and/or filled and auto sized, set starting values here to 0.
Region.MakeInfinite(); // This one was my own, to solve size problems with my dynamically created forms auto size, further reading required for other ways to do it.
}
private void Form1_Load(object sender, EventArgs e)
{
Font font = new System.Drawing.Font("Meiryo UI", 16.0f);
myButton = new Button();
myButton.Name = "tstButton";
myButton.Size = new Size(50, 50);
myButton.Location = new Point(10, 10);
myButton.Font = font;
myButton.Text = "Test Button";
myButton.Click += (sender2, e2) => { ButtonClick(sender, e); };
this.Controls.Add(myButton);
}
private void ButtonClick(object sender, EventArgs e)
{
Font font = new System.Drawing.Font("Meiryo UI", 16.0f);
Button myButton = (sender as Button);
Form myForm = new Form();
Label row1Label = new Label();
Label row2Label = new Label();
Label row3Label = new Label();
Label row4Label = new Label();
Label row5Label = new Label();
row2Label.AutoSize = true;
row2Label.Text = "Row 1: ";
row2Label.Font = font;
row2Label.Location = new Point(5, 5);
row1Label.AutoSize = true;
row1Label.Text = "Row 2: ";
row1Label.Font = font;
row1Label.Location = new Point(5, 35);
row3Label.AutoSize = true;
row3Label.Text = "Row 3: ";
row3Label.Font = font;
row3Label.Location = new Point(5, 65);
row4Label.AutoSize = true;
row4Label.Text = "Row 4: ";
row4Label.Font = font;
row4Label.Location = new Point(5, 95);
row5Label.AutoSize = true;
row5Label.Text = "Row 5: ";
row5Label.Font = font;
row5Label.Location = new Point(5, 125);
myForm.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
myForm.AutoSize = true;
myForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
myForm.Controls.Add(row1Label);
myForm.Controls.Add(row2Label);
myForm.Controls.Add(row3Label);
myForm.Controls.Add(row4Label);
myForm.Controls.Add(row5Label);
myForm.Font = font;
myForm.BackColor = Color.White;
myForm.Padding = new System.Windows.Forms.Padding(10, 10, 10, 10);
myForm.Show();
myForm.Paint += (sender4, e4) => { Form1_Paint(sender4, e4); }; // Hijacking the borrowed code for custom borders again for the info boxes.
myForm.Location = new Point(Cursor.Position.X + 25, Cursor.Position.Y - 100); // Create info box a little to the right and up from the cursors position.
myForm.LostFocus += (sender3, e3) => { CloseForm(sender3, e3, myForm); }; // If the info box loses focus, for example by clicking another button, close that box (form)
myForm.MouseEnter += (sender3, e3) => { CloseForm(sender3, e3, myForm); }; // Also, if the mouse enters the box, also close, so we can show the buttons under it.
}
/// <summary>
/// Event for closing my "custom" info boxes. Runs at LostFocus or MouseEnter events. So, clicking another button or entering the info box will close it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <param name="myForm">Gets the relevant form that the event will run on. Solved my problem of targeting dynamically created forms from outside its scope.</param>
private void CloseForm(object sender, EventArgs e, Form myForm)
{
myForm.Close();
}
/// <summary>
/// Paint event. Holds some borrowed code for getting custom border. Works so far, but further reading required.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Borrowed code snippet for custom border: http://stackoverflow.com/q/5092216
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid);
}
}
}
I am a beginner at programming so be somewhat forgiving and show the right way instead of condemning any bad coding.
Kind Regards,
Mattias
Upvotes: 0
Views: 9883
Reputation: 177
The davidovic's solution will have a side effect, when there is control dock left/right/top/down, you can't paint in this area, for you are using "ClientRectangle" which is override by the control.
There are two normal solutions of repainting border:
put another form under the form, but will have form dispose issue, may lead to out of memory
catch the nonclient area windows message, repaint the border. But it is very tricky, and may lead to many problems, for example, when form is minimized, when form is resize, some form area is hidden, and you should handle this event.
If you want to use the method 2, I suggest you to take the Lizard.dll for reference, it still has bugs but much stable than other kinds of library.
Upvotes: 0
Reputation: 8656
The problem is that you are using the same event handler for both forms. If you want to continue that way you should change the size of the ClientRectangle
according to the form for which the Pain event handler has been called (now you are always using the ClientSize
of the main form). Change the code of Form1_Paint
event handler to this:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Form frm = (Form)sender;
ControlPaint.DrawBorder(e.Graphics, frm.ClientRectangle,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid,
Color.LightBlue, 5, ButtonBorderStyle.Solid);
}
In your previous code, you were passing the ClientRectangle
of the main form in cases of the child form redrawing. After you change the code, the DrawBorder
method will get the proper ClientRectangle
for the form for which it has been called.
Upvotes: 3