Tworzenie nowych TextBoxów dynamicznie

0

Witam mam mały problem a mianowicie chodzi o to żeby dać użytkownikowi możliwość wpisania cyfry do textbox'a i po czym zostanie utworzona odpowiednia ilość TextBox'ów w odnisieniu do podanej liczby...

Mam taki kod ale program mi się wywala gdzieś przy podaniu lokalizacji ale nie wiem też czy reszta jest dobrze, w każdym bądz razie nie wyskakuje mi żaden błąd...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TextBoxy
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private System.Windows.Forms.TextBox[] textboxy;

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            textboxy = new System.Windows.Forms.TextBox[2];
            int ntb = 0;
            foreach (System.Windows.Forms.TextBox textbox in textboxy)
            {
                textbox.Location = new System.Drawing.Point(12, 30);
                textbox.Name = "textbox" + ntb.ToString();
                textbox.Size = new System.Drawing.Size(100, 20);
                textbox.TabIndex = ntb;
                textbox.Visible = true;
                ntb ++;

            }
        }
    }
} 

Z góry dzięki za odpowiedz

0

Może posłuż się właściwościami Left i Top

i Width i Height.
I dodatkowo trzeba gdzieś TextBox dodać.
this.Controls.Add(...);

0

Aplikacja wywala się, bo ty tak naprawdę stworzyłeś tylko tablicę bez ustalonych jej elementów. Przez to każdy element tablicy jest null'em i nie możesz mu nic zmienić. Musisz stworzyć każdy TextBox oddzielnie, zamiast twojego foreach'a daj:

for (int i = 0; i < textboxy.Length; i++)
{
	textboxy[i] = new TextBox();

	textboxy[i].Location = new System.Drawing.Point(12, 30);
	textboxy[i].Name = "textbox" + ntb.ToString();
	textboxy[i].Size = new System.Drawing.Size(100, 20);
	textboxy[i].TabIndex = ntb;
	textboxy[i].Visible = true;

	this.Controls.Add(textboxy[i]);
}

Wypadało by jeszcze ustalać pozycję dla każdego TextBox'a, bo tak to będą się na siebie nakładały.

0

Albo użyć TableLayoutPanel, on sam rozmieści nowe TextBoxy.

0

Panowie dzięki bardzo, rewelacja wszystko działa tylko faktycznie TextBoxy się nakładają na siebie... I tu też moje pytanie jak użyć tego TableLayoutPanel bo nie jestem zbyt biegły w C#...

Bo może powiem o co chodzi dokładnie, chcę dać użytkownikowi możliwość wpisania w TextBox stopień wielomianu po czym powinna wyskoczyć odpowiednia ilość TextBox'ów w które bedzie mógł wprowadzić wartości każdego z wielomianów...

Zastanawiam się jeszcze czy będę mógł dokonać jakiś działań na tych nowo powstałych TextBox'ach jeśli tak to jak je zdefiniować, czy normalnie jako TextBox2, 3 i 4...?
Bo nie do końca będzie wiadoma ich ilość więc też bym musiał zrobić jakąś pętlę żeby je odpowiednio nazywał i pobierał z nich podane wartości...

0

Pokombinuj z tym TableLayoutPanel. W kodzie musisz zmieniać jego ilość kolumn/wierszy w zależności i ile będziesz miał TextBox'ów. Do odszukania danej wartości danego TextBox'a możesz użyć:

this.Controls.Find("TextBox" + licznik.ToString(), false)[0].Text;

Ta metoda zwraca tablicę odnalezionych kontrolek o danej nazwie. I bierzesz pierwszą taką kontrolkę (jedyna taka) i pobierasz jej wartość Text. licznik to licznik twojej pętli gdzie będziesz pobierał ze wszystkich TextBox'ów wartości, zależy ile będziesz ich tam miał.

0

Staram się bawić tym TableLayoutPanel, mianowicie podzieliłem go na jedną kolumnę i 25 wierszy i teraz zastanawiam się jak wprowadzić kod do niego żeby z automatu wszystkie TextBox'y miały tę sam rozmiar i dodawały się jeden pod drugim...
Aha i macie może pomysł jak ograniczyć użytkownikowi wprowadzenie większej liczby TextBox'ów niż 25 myślałem o jakimś wyskakującym MessageBox'ie...

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TextBoxy
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private System.Windows.Forms.TextBox[] textboxy;

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            textboxy = new System.Windows.Forms.TextBox[2];
            int ntb = 0;
            for (int i = 0; i < textboxy.Length; i++)
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "textbox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);
              
            }
        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {

        }
    }
}
1

Co do limitu 25 TextBox'ów: po zatwierdzeniu ilości nowych kontrolek wywołujesz funkcję, która zajmuje się ich tworzeniem. Na jej początku sprawdzasz ile kontrolek wpisał użytkownik (możesz przekazać przez parametr), jeżeli > 25 to wyświetlasz mbox'a i zwracasz wynik np. -1 (wychodzisz z funkcji). A co do TableLayoutPanel'a zaraz coś u siebie popróbuję i jak coś podam ci koncepcję.

Tak jak myślałem nie trzeba nic kombinować. Dajesz TableLayoutPanel ustawiasz, odpowiednią ilość kolumn i wierszy, a w funkcji dodającej TextBox'y wklepujesz:

tableLayoutPanel1.Controls.Add(textBox1);

Automatem ci się będzie dodawał przekazany TextBox do tabeli. I tak robisz z każdym kolejnym, inicjalizując jego właściwości wg swoich potrzeb.

0

Dzięki Wielkie za pomoc... naprawdę mega mi pomagacie... Jeszcze raz dzięki bardzo...

Natomiast co do kodu to wywala mi błąd w tym miejscu "tableLayoutPanel1.Controls.Add(textboxy);" chociaż nie wiem czemu O_o ??

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            textboxy = new System.Windows.Forms.TextBox[2];
            int ntb = 0;
            for (int i = 0; i < textboxy.Length; i++)
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "textbox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);
              
            }

            tableLayoutPanel1.Controls.Add(textboxy);
        }

A co do przekazywania parametru to rozumiem że ma być typu wartościowego, ale mam mały problem z napisaniem tego kodu bo wywala mi się od razu...
Jeżeli mam już textBox1 bo jest to ten w którym użytkownik może wpisać ilość nowo tworzonych textBox'ów to następne numeruje np. textBox2... itd. ?

0
mcshow napisał(a)

wywala mi błąd w tym miejscu "tableLayoutPanel1.Controls.Add(textboxy);"

Dlatego że próbujesz dodać tablicę kontrolek, zamiast jednej kontrolki. Powinno być tak:

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            textboxy = new System.Windows.Forms.TextBox[2];
            int ntb = 0;
            for (int i = 0; i < textboxy.Length; i++)
            {
                textboxy[i] = new TextBox();
                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "textbox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;

                tableLayoutPanel1.Controls.Add(textboxy[i]);              
            }
        }
0

Po zmianie pokazuje mi że "i" nie istnieje ??

Dobra już wiem nie w tym miejscu wywołałem tą funkcję :P

Wszystko działa tylko teraz jak przechwycić wartość z nowo powstałych textBox'ów ? Bo rozumiem że każdy stworzony ma kolejne nazwy czyli textBox2 itd...?

0

Kilka postów wyżej Xeo napisał Ci już jak dostać się do takiego textboxa.

0

Pytanie w którym miejscu programu wstawić podany przez Xeo kod żeby dobrze zadziałał...?

this.Controls.Find("TextBox" + licznik.ToString(), false)[0].Text;

Ta metoda zwraca tablicę odnalezionych kontrolek o danej nazwie. I bierzesz pierwszą taką kontrolkę (jedyna taka) i pobierasz jej wartość Text. licznik to licznik** twojej pętli gdzie będziesz pobierał ze wszystkich TextBox'ów wartości**, zależy ile będziesz ich tam miał.

I właśnie co do tej pętli to ma być wartość pobierana przez parametr ? Tylko jak taką pętlę zainicjować ?

0

Jak chcesz jeden TextBox konkretny odnaleźć to wywołujesz tą metodę Find(...) podając jej nazwę chcianej kontrolki + jej numer np. "TextBox1". I za metodą pobierasz pierwszy element wygenerowanej tablicy znalezionych kontrolek, czyli na ten twój znaleziony TextBox.

Jeżeli chcesz od razu pobrać ze wszystkich utworzonych TextBox'ów pobrać jakieś właściwości to robisz pętlę i po kolei podobnie jak przy jednym:

for (int i = 0; i < zmienna_przechowujaca_ilosc_textbox; i++)
    this.Controls.Find("TextBox" + licznik.ToString(), false)[i].Text; // ta wartość możesz zapisać gdzieś sobie do innej zmiennej

Można na drugi sposób. Wrzucasz każdy dodany TextBox na listę i wtedy, tylko pętlę foreach:

foreach (TextBox aktualny in lista_textbox)
    aktualny.Text;
0

Dzięki wielkie...

Znalazłem mały błąd we wcześniejszym kodzie:

         private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
            textboxy = new System.Windows.Forms.TextBox[3];
            for (int i = 0; i < textboxy.Length; i++)
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "TextBox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);

                tableLayoutPanel1.Controls.Add(textboxy[i]);
            }

        } 

Chodzi dokładnie o ten moment

  textboxy = new System.Windows.Forms.TextBox[3]; 

Gdy wpiszę w TextBox1 ilość nowych TextBox'ów i nie ważne czy to będzie 8 czy 24 i tak zawsze wyskakują 3... Domyślam się co jest źle bo chyba to wynika z tablicy którą tworzę o wartości [3] i zawsze będę miał 3 nowe TextBox'y...
Jak to zmienić żeby wartość nowych TextBox'ów równała się temu co wpiszę użytkownik ???

0

Zadeklaruj List<TextBox> textboxy będzie typu, a nie TextBox[] textboxy;

0
         __private List<TextBox> textboxy;__

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
           __ **textboxy = new List<TextBox> textboxy;**__
            **__for (int i = 0; i < textboxy.Length; i++)__**
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "TextBox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);

                tableLayoutPanel1.Controls.Add(textboxy[i]);
            }

        }

Wyskakuje mi teraz coś takiego:

1: Only assignment, call, increment, decrement, and new object expressions can be used as a statement C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

2: A new expression requires (), [], or {} after type C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

3: 'System.Collections.Generic.List<System.Windows.Forms.TextBox>' does not contain a definition for 'Length' and no extension method 'Length' accepting a first argument of type 'System.Collections.Generic.List<System.Windows.Forms.TextBox>' could be found (are you missing a using directive or an assembly reference?) C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

0
         __private List<TextBox> textboxy;__

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
           __ **textboxy = new List<TextBox> textboxy;**__
            **__for (int i = 0; i < textboxy.Length; i++)__**
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "TextBox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);

                tableLayoutPanel1.Controls.Add(textboxy[i]);
            }

        }

Wyskakuje mi teraz coś takiego:

1: Only assignment, call, increment, decrement, and new object expressions can be used as a statement C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

2: A new expression requires (), [], or {} after type C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

3: 'System.Collections.Generic.List<System.Windows.Forms.TextBox>' does not contain a definition for 'Length' and no extension method 'Length' accepting a first argument of type 'System.Collections.Generic.List<System.Windows.Forms.TextBox>' could be found (are you missing a using directive or an assembly reference?) C:\Users\Sebastian\Documents\Visual Studio 2010\Projects\TextBoxy\TextBoxy\Form1.cs

0
textboxy = new List<TextBox>();

To zwykłe utworzenie obiektu, przydatna umiejętność w programowaniu.

0

Zmieniłem i nadal są błędy czyli 1 i 3 błąd został i pojawił się nowy że gdzieś brakuje ";"

 ^         private List<TextBox> textboxy;

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
            textboxy = new List<TextBox>() textboxy;
            for (int i = 0; i < textboxy.Length; i++)
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "TextBox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);

                tableLayoutPanel1.Controls.Add(textboxy[i]);
            }

        } ^ 

Pokazuje że błędy są gdzieś w tym miejscu kodu

             int ntb = 0;
            textboxy = new List<TextBox>() textboxy;
            for (int i = 0; i < textboxy.Length; i++) 
0

Litosci...

Po pierwsze:

 List<TextBox> textboxy = new List<TextBox>();

Po drugie:
RTFM!
List nie ma wlasciwosci Length tylko Count
http://msdn.microsoft.com/en-us/library/27b47ht3.aspx

0

Witam

Poprawiłem cały kod i teraz nie pokazuje mi żadnego błędu ale z drugiej strony program też nie działa poprawnie czyli po wpisaniu wartości w TextBox nie wyskakuje odpowiednia ilość nowych TextBox'ów...

Wiecie może gdzie jest błąd...?

 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TextBoxy
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private List<TextBox> textboxy;

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
            textboxy = new List<TextBox>();
            for (int i = 0; i < textboxy.Count; i++)
            {
                textboxy[i] = new TextBox();


                textboxy[i].Location = new System.Drawing.Point(200, 12);
                textboxy[i].Name = "TextBox" + ntb.ToString();
                textboxy[i].Size = new System.Drawing.Size(100, 20);
                textboxy[i].TabIndex = ntb;
                textboxy[i].Visible = true;

                this.Controls.Add(textboxy[i]);

                tableLayoutPanel1.Controls.Add(textboxy[i]);
            }

        }

        private void tableLayoutPanel1_Paint(object sender, PaintEventArgs e)
        {
    
        }
    }
}

 
1

Ban na debugger? Zobacz jaką wartość ma textboxy.Count

1

Ta pętla jest zła: for (int i = 0; i < textboxy.Count; i++). Tutaj textboxy.Count będzie mieć 0, więc żadnych textboxów nie będzie. Najpierw musisz zdefiniować ile tych textboxów chcesz i tyle wykonać razy obrót pętlą, dopiero po utworzeniu takiego textboxa wrzucasz go do listy, aby mieć do nich dostęp później.

Tak w ogóle, źle to robisz, lista sama w sobie nie ma obiektów, więc nie możesz zrobić tak textboxy[i] zanim nie dodasz elementów do niej.

private List<TextBox> textboxy;
 
        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
            textboxy = new List<TextBox>();
            for (int i = 0; i < int.Parse(textbox1.Text); i++)
            {
                TextBox textbox = new TextBox();
 
                textbox.Location = new System.Drawing.Point(200, 12);
                textbox.Name = "TextBox" + ntb.ToString();
                textbox.Size = new System.Drawing.Size(100, 20);
                textbox.TabIndex = ntb;
                textbox.Visible = true;
 
                //this.Controls.Add(textbox); // to jest zbędne, jak dodajesz to tableLayoutPanel, to już nie musisz na formę
                textboxy.Add(textbox);

                tableLayoutPanel1.Controls.Add(textbox);
            }
 
        }

Mniej więcej o to mi chodzi.

0

Rewelacja ! Dzięki bardzo, tylko teraz jest problem bo wartość do textBox'a można wprowadzić raz bo po usunięciu i podaniu ponownie program się wywala...

Idzie jakoś temu zaradzić ?

A przy okazji jak ograniczyć wprowadzenie więcej niż powiedzmy 25 nowych textBox'ów ?

Coś na zasadzie if (i > 25) {messageBox.Show ("zbyt duża wartość")...? }

0

Ja bym ci radził nie robić tego w evencie onTextChange tylko np. po naciśnięciu klawisz albo przycisku, bo tak po wprowadzeniu liczby np. 11, zrobią się najpierw jeden, a potem 11. A dokładnie w którym miejscu się wywala, prześledź działanie programu debugger'em.

0

Wywala się gdzieś w tym miejscu

  for (   int i = 0; i < int.Parse(textBox1.Text); i++) 

ale chyba masz rację zrobię przycisk umożliwiający potwierdzenie danej wartości i kasujący nowo powstałe textBox'y...

0
mcshow napisał(a)

Wywala się gdzieś w tym miejscu

  for (   int i = 0; i < int.Parse(textBox1.Text); i++) 

ale chyba masz rację zrobię przycisk umożliwiający potwierdzenie danej wartości i kasujący nowo powstałe textBox'y...

Wywala sie w tym miejscu bo textBox1.Text jest rowne string.Empty a tego sie nie da sparsowac na int.

0

A mi się z tym kodem nic nie wywala.

Ino

int.Parse(textbox1.Text)

trzeba zamienić na:

int.Parse(textBox1.Text)

:)

btw

textbox.Name = "TextBox" + ntb.ToString();

Tworzycie textboxy o tej samej nazwie? :P

    public partial class Form1 : Form
    {
        private const int iHEIGHT = 20, iWIDTH = 100;
        private const int iCOLS = 5, iROWS = 2;
        private List<TextBox> tbList = new List<TextBox>();

        public Form1()
        {
            InitializeComponent();

            tableLayoutPanel1.ColumnCount = iCOLS;

            for (int i = 0; i < tableLayoutPanel1.ColumnStyles.Count; i++)
            {
                tableLayoutPanel1.ColumnStyles[i].SizeType = SizeType.Absolute;
                tableLayoutPanel1.ColumnStyles[i].Width = iWIDTH + 4;
            }

            tableLayoutPanel1.RowCount = iROWS;

            for (int i = 0; i < tableLayoutPanel1.RowStyles.Count; i++)
            {
                tableLayoutPanel1.RowStyles[i].SizeType = SizeType.Absolute;
                tableLayoutPanel1.RowStyles[i].Height = iHEIGHT + 4;
            }

            tableLayoutPanel1.Height = iROWS * (iHEIGHT + 4);
            tableLayoutPanel1.Width = iCOLS * (iWIDTH + 4);
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            int ntb = 0;
            Int32.TryParse(textBox1.Text, out ntb);

            if (ntb > tbList.Count)
            {
                tableLayoutPanel1.RowCount = (ntb < iROWS) ? iROWS : ntb;
                tableLayoutPanel1.Height = (iHEIGHT + 4) * tableLayoutPanel1.RowCount;

                for (int i = tbList.Count; i < ntb; i++)
                {
                    tbList.Add(new TextBox());

                    tbList[i].Location = new System.Drawing.Point(0, 0);
                    tbList[i].Name = String.Format("{0}{1}", "tbTest", i);
                    tbList[i].Size = new System.Drawing.Size(iWIDTH, iHEIGHT);
                    tbList[i].TabIndex = i;
                    tbList[i].Visible = true;

                    tableLayoutPanel1.Controls.Add(tbList[i]);
                }
            }
        }
    }

Zmień sobie nazwy: Form1, textBox1 i tableLayoutPanel1 na bardziej konkretniejsze ;d

1 użytkowników online, w tym zalogowanych: 0, gości: 1