Docking 2 rich text boxes - c#

I am trying to make a text editor and I have 2 rich text boxes. I am uses the 1st rich text box as a number like and setting its Enabled property to false. Then the second text box is going next to it
I have currently set the dock of the first text box to left and the second one to fill. But the 2nd one keeps taking up the whole tabpage? And going slightly more left towards the number line and its hidden under there a little bit. Here is my create new document void I have... T2 is the number line and T is the default text box they will type into.
TabPage t = new TabPage("new " + getNumber());
tabControl1.TabPages.Add(t);
tabControl1.SelectedTab = t;
RichTextBox T2 = new RichTextBox();
t.Controls.Add(T2);
T2.Dock = DockStyle.Left;
T2.Enabled = false;
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T.Dock = DockStyle.Fill;
T.Font = new Font("Microsoft San Serif", 11);
Random R = new Random();
int RandomNumberHere = R.Next(1000, 100000);
T.Text = "Welcome, type your text...";
T.Select();

The problem is that you define your fill-docked text box at the end of the control list... winforms likes the fill-docked elements first in the list.
Easily solved:
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T.Dock = DockStyle.Fill;
T.Font = new Font("Microsoft San Serif", 11);
// Add this line
T.BringToFront();
Or you could also do T2.SendToBack(); after T is added to the controls collection.
Or you could simply create (and add to t.Controls), the fill-docked textbox first, and the left-docked textbox second.
Either way works
By the way, try to name your variables correctly. t, T, T2 are just not good names

Here you go:
t.Controls.Add(T2);
t.Controls.Add(T);
t.Controls.SetChildIndex(T, 1);
t.Controls.SetChildIndex(T2, 0);
t.PerformLayout(); // needed after SetChildIndex!
T2.Dock = DockStyle.Left;
T.Dock = DockStyle.Left;
If you want your boxes to grow with the TabPage here is one way to do it:
private void t_Resize(object sender, EventArgs e)
{
// assuming you want the two RTBs to fill the TabPage
// if you want something else, best add an anchored container panel
// and use its resize event instead
T2.Width = t.Width / 4;
T.Width = t.Width / 4;
}
And yes, t, T and T2 are really bad names!

There's a few things going on:
Fill does just that; it Fills the entirety of the PARENT control. Whether anything else is there or not.
Your other text box will be hidden until it is set to Enabled.
What you Might? be looking for is a way to have the text box size itself based on the size of the tab page being created:
{
TabPage t = new TabPage("new " + 1);
tabControl1.TabPages.Add(t);
tabControl1.SelectedTab = t;
RichTextBox T2 = new RichTextBox();
t.Controls.Add(T2);
T2.Dock = DockStyle.Left;
T2.Enabled = true ;
RichTextBox T = new RichTextBox();
t.Controls.Add(T);
T2.Dock = DockStyle.Right;
var AdjustedSize = T2.Size;
AdjustedSize.Width = t.Size.Width * 2 / 3;
T2.Size = AdjustedSize;
T.Font = new Font("Microsoft San Serif", 11);
Random R = new Random();
int RandomNumberHere = R.Next(1000, 100000);
T.Text = "Welcome, type your text...";
T.Select();
}

Related

How to save state of Windows Form Application (or save data in text boxes with arrays)

I have been working a program that is used as a guide/way to memorize items when studying terms for whatever (test, exam, etc.). It generates a set amount of textboxes inside of a group box (which has the subject name set as its text property) in which you can write the term name and definition. I was wondering how I would save what was written in the text boxes after being generated. Perhaps being able to save the state of the application after pressing save and being able to set the application to its previous state when wanted (Kind of like snapshots that you use in virtual machines). Another way I thought of is to perhaps make a group of each subject somehow and within that store an array of text in each term name box and the associated term definition. Here is the code inside of the button I press to generate the text boxes. There is also a photo of the form: Photo of form Here is one of the program running: Image of Program running Edit: I am not asking for the straight up entire code. I would like just a guideline/idea of how I would go about doing this.
GroupBox groupBox1 = new GroupBox();
TextBox textTest = new TextBox();
textTest.Location = new Point(15, 40);
groupBox1.Controls.Add(textTest);
Button buttonForBoxes = new Button();
NumericUpDown numberUpDown1 = new NumericUpDown();
groupBox1.Controls.Add(buttonForBoxes);
buttonForBoxes.Location = new Point(140, 40);
buttonForBoxes.Text = "moretext";
numberUpDown1.Location = new Point(15, 15);
groupBox1.Controls.Add(numberUpDown1);
groupBox1.AutoSize = true;
var numVal = numericUpDown1.Value;
var numDo2 = 40;
var numDo1 = 120;
var inSubjectBox = subjectBox.Text;
//Makes boxes however many times you specify
for (int i = 0; i < numVal; i++)
{
numDo2 += 110;
TextBox text1 = new TextBox();
text1.Location = new Point(15, numDo1);
groupBox1.Controls.Add(text1);
numDo1 += 110;
TextBox textThing = new TextBox();
textThing.Location = new Point(15, numDo2);
textThing.Multiline = true;
textThing.Size = new System.Drawing.Size(600, 60);
groupBox1.Controls.Add(textThing);
}
// Set the Text and Dock properties of the GroupBox.
groupBox1.Text = inSubjectBox;
groupBox1.Dock = DockStyle.Top;
// Enable the GroupBox (which disables all its child controls)
groupBox1.Enabled = true;
// Add the Groupbox to the form.
this.Controls.Add(groupBox1);
Maybe you can try to save the textbox info into Settings.
First, go to Project -> Properties -> Settings and add new items(type of StringCollection) in Settings.
Then, modify the code like this(save the location of the TextBox in the format of "x;y"):
private void Addtextbox_Click(object sender, EventArgs e)
{
Properties.Settings.Default.text1Collection.Clear();
Properties.Settings.Default.textThingCollection.Clear();
var numVal = 2;
// code omitted
// ...
for (int i = 0; i < numVal; i++)
{
numDo2 += 110;
TextBox text1 = new TextBox();
text1.Location = new Point(15, numDo1);
groupBox1.Controls.Add(text1);
// save info to Settings
Properties.Settings.Default.text1Collection.Add(String.Format("{0};{1}", text1.Location.X, text1.Location.Y));
numDo1 += 110;
TextBox textThing = new TextBox();
textThing.Location = new Point(15, numDo2);
textThing.Multiline = true;
textThing.Size = new System.Drawing.Size(600, 60);
groupBox1.Controls.Add(textThing);
// save info to Settings
Properties.Settings.Default.textThingCollection.Add(String.Format("{0};{1}", textThing.Location.X, textThing.Location.Y));
// call Save()
Properties.Settings.Default.Save();
}
// code omitted
// ...
}
private void LoadtextboxFromSettings_Click(object sender, EventArgs e)
{
foreach (string text1str in Properties.Settings.Default.text1Collection)
{
TextBox text1 = new TextBox
{
Location = new Point(Convert.ToInt32(text1str.Split(';')[0]), Convert.ToInt32(text1str.Split(';')[1]))
};
groupBox1.Controls.Add(text1);
}
foreach (string textThingstr in Properties.Settings.Default.textThingCollection)
{
TextBox textThing = new TextBox
{
Multiline = true,
Location = new Point(Convert.ToInt32(textThingstr.Split(';')[0]), Convert.ToInt32(textThingstr.Split(';')[1])),
Size = new Size(600, 60)
};
groupBox1.Controls.Add(textThing);
}
}
Besides, if you get the exception System.NullReferenceException: 'Object reference not set to an instance of an object.', try to add a default value for each "setting".
Update:
The way to set Settings default value.
I used to do something similar when storing the positions of forms and the size of some controls on them. Then it was necessary for the application to open on restart in the same form as it was last used.
All forms and controls data I saved to XML file, when closing application. When then application has been started I read this XML file and set positions of forms and controls.

Insert Row in Middle of Table Layout panel C# Windows

I am trying to add a row in middle of table layout panel. However I am struggling to find a way to do this. I tried following from one of the article on internet but this doesn't seems to be working. Can you help.
i have 3 columns and 5 rows in table layout panel. each row containing lable, textbox and blank lable.
i am trying to add a row after 2nd row in already created table layout panel.
var AddOnControl = ConfirmationTable.Controls.Find("Discount", true).First();
int childIndex = 1+ ConfirmationTable.Controls.GetChildIndex(AddOnControl);
Label lbl = new Label();
lbl.Name = key;
lbl.Text = key;
lbl.Font = new Font("Calibri", 10F, System.Drawing.FontStyle.Regular);
lbl.Size = new Size(lbl.Size.Width + 70, lbl.Size.Height);
ConfirmationTable.Controls.Add(lbl);
TextBox txt = new TextBox();
txt.Multiline = true;
txt.TextChanged += txt_TextChanged;
txt.Name = "txtPrice" + key;
txt.Text = value;
txt.BorderStyle = BorderStyle.None;
ConfirmationTable.Controls.Add(txt);
lbl = new Label();
lbl.Name = "blank";
ConfirmationTable.Controls.Add(lbl);
ConfirmationTable.Controls.SetChildIndex(lbl, childIndex);
ConfirmationTable.Controls.SetChildIndex(txt, childIndex + 1);
ConfirmationTable.Controls.SetChildIndex(txt, childIndex + 2);
but above code always adds a row at the bottom of the table. Any suggestion?
There is an overload of the Controls.Add method that accepts two integers as indexes for column/row position.
Like this:
tableLayoutPanel1.Controls.Add(lb3, 0, 1);
I believe this is enough to solve your problem in a simple way.

Creating Windows Forms labels within a tab control C#

I'm working on a project at the moment and I'm trying to have it where every contact within the ArrayList has their own tab page. Within the tab page I want all their info to be displayed, to do this I'm trying to create labels that will have their information. I'm right now just at the point trying to get at least one label to appear, but it does not appear to be displaying at all. My code is below. Any help?
int count = 0;
foreach (clsContactHandler contact in clsGlobal.mContacts)
{
string tabName = contact.FirstName + " " + contact.LastName;
Font font = new Font("Microsoft Sans Serif", 16.0f, FontStyle.Bold);
TabPage contactPage = new TabPage(tabName);
tabs.TabPages.Add(tabName);
Label label = new Label();
contactPage.Controls.Add(label);
label.Font = font;
label.AutoSize = true;
label.Location = new System.Drawing.Point(16, 7);
label.Name = "label" + count;
label.Size = new System.Drawing.Size(43, 13);
label.Text = "Name:";
count++;
}
Since you're creating the new page as TabPage contactPage object,
tabs.TabPages.Add(tabName);
should be
tabs.TabPages.Add(contactPage);
like suggested use
tabs.TabPages[tabName].Controls.Add(label);
but before that set name property:
contactPage.Name="someUniqueName"
and use
tabs.TabPages[count].Controls.Add(label);
where count is I suppose, the index tracker in case TabPages["someUniqueName"] throws NullReferenceException.
Also, add contactpage to tabs and not tabName

Programmatic Insertion of Controls into a Form

I have a for loop which I'm attempting to use to generate and lay out the contents of a Form.
This is what I've gotten to so far:
public void RefreshSkillDialog()
{
Point nPt = new Point(25, 25);
for (int x = 0; x < Enum.GetNames(typeof(Character.Skill)).Length; x++ )
{
GenerateFields(x,nPt);
Console.Write(this.Controls.Count + "\n");
Console.WriteLine(this.Controls[x].ToString() + "\n");
}
}
public void GenerateFields(int it, Point pt)
{
Label tLbl = new Label();
tLbl.Location = new Point(pt.X + (it * _vSpace), pt.Y);
tLbl.Name = Enum.GetName(typeof(Character.Skill), it);
tLbl.Text = this.Controls.Count.ToString();
this.Controls.Add(tLbl);
}
_vSpace is an integer initialized to 10 in the constructor.
The result of this code is:
I thought the issue was in reusing the tLbl variable, but as far as I can tell, it should work fine since I'm re-initializing it at the beginning of every iteration.
When you create a new Label, it is 100px wide by default.
You're changing the location (x-coordinate) of each new Label, but not by enough. Each new Label is overlapping the previous one, such that's it's covering up the text.
You can fix this by setting AutoSize = true on each Label:
Label tLbl = new Label();
tLbl.AutoSize = true;
...
Or by resizing it so that it's not as wide:
Label tLbl = new Label();
tLbl.Size = new Size(10, 23);
...
You might also consider just using a FlowLayoutPanel, since it will handle the layout for you. Add each new control to it, and don't bother with setting a Location.
Label tLbl = new Label();
tLbl.Name = Enum.GetName(typeof(Character.Skill), it);
tLbl.Text = flowLayoutPanel1.Controls.Count.ToString();
flowLayoutPanel1.Controls.Add(tLbl);
If you do that, you'll have to change your Console.WriteLine statement in the other method too:
Console.WriteLine(flowLayoutPanel1.Controls[x].ToString() + "\n");

C# Add Controls To Panel In a Loop

I wish to add a button for every line in a file to a panel.
My code so far is:
StreamReader menu = new StreamReader("menu.prefs");
int repetition = 0;
while(!menu.EndOfStream)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = menu.ReadLine();
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
MessageBox.Show(dynamicbutton.Location.ToString());
}
menu.Close();
The problem is that only the first control gets created.
The code looks fine but there could be a following situations.
1.You might have only one entry in the file, so you are experiencing only One Button added to the panel.
2.Your panel width is smaller than the sum of all the dynamic buttons width.
I suspect no 2 is the main reason that is causing problem.
So, I recommend that you use FlowLayoutPanel. To add a dynamic content as it automatically layout all the child controls.
Each time it is generating the same name for dynamic controls. That's the reason why it is showing only the last one. It simply overwrites the previous control each time.
int x = 4;
int y = 4;
foreach(PhysicianData pd in listPhysicians)
{
x = 4;
y = panPhysicians.Controls.Count * 30;
RadioButton rb = new RadioButton();
rb.CheckedChanged += new System.EventHandler(rbPhysician_CheckedChanged);
rb.Text = pd.name;
rb.Visible = true;
rb.Location = new Point(x, y);
rb.Height = 40;
rb.Width = 200;
rb.BackColor = SystemColors.Control;
rb.ForeColor = Color.Black;
rb.Font = new Font("Microsoft Sans Serif", 10);
rb.Show();
rb.Name = "rb" + panPhysicians.Controls.Count;
panPhysicians.Controls.Add(rb);
}
Try this code
StreamReader menu = new StreamReader("menu.prefs");
var str = menu.ReadToEnd();
var items = str.Split(new string[] {"\r\n" } , StringSplitOptions.RemoveEmptyEntries);
foreach (var item in items)
{
Button dynamicbutton = new Button();
dynamicbutton.Click += new System.EventHandler(menuItem_Click);
dynamicbutton.Text = item;
dynamicbutton.Visible = true;
dynamicbutton.Location = new Point(4+repetition*307, 4);
dynamicbutton.Height = 44;
dynamicbutton.Width = 203;
dynamicbutton.BackColor = Color.FromArgb(40,40,40);
dynamicbutton.ForeColor = Color.White;
dynamicbutton.Font = new Font("Lucida Console", 16);
dynamicbutton.Show();
menuPanel.Controls.Add(dynamicbutton);
repetition++;
}
The problem with Panel and similar controls other than the FlowLayoutPanel is when you create a control and a second one, the second is created at the same position if you are not changing it's location dynamically or setting it according to the other already added controls. Your control is there, it's in the back of the first control.
A flowLayoutPanel is better as it will add the controls next to each other as you add them while compromising more finer control at their positioning.
I also have similar problems with panels. For what you are doing it could be useful to just add strings to a listbox rather than using labels and a panel. That should be simpler.

Categories