Vytvoření komponent za běhu   zodpovězená otázka

C#

Zdravím,

nic jsem nevybingoval, ani nevygooglil a tak se ptám zde. Nenapsal by mi někdo kód, nebo odkaz pro vytvoření komponenty za běhu? Konkrétně potřebuji, aby se po klikání na tlačítko vytvořily pod sebe TextBoxy (1 klik = 1 TextBox) A když otevřu například textový soubor z OpenFileDialogu, tak se každý řádek vloží tolik TextBoxů, kolik je řádků a do každého se postupně vypíší řádky z dokumentu.

Díky!

nahlásit spamnahlásit spam 0 odpovědětodpovědět
Public Class Form1

    Private _fileName As String = "C:/test.lsv"
    Private _lineEditors As New List(Of TextBox)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim add As Integer = 0
        Using fs As New IO.FileStream(_fileName, IO.FileMode.OpenOrCreate)
            Using sr As New IO.StreamReader(fs, System.Text.Encoding.UTF8)
                While Not sr.EndOfStream
                    Dim tb As New TextBox
                    tb.Text = sr.ReadLine()
                    AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
                    tb.Location = New Point(12, 45 + add)
                    add += 33
                    Me.Controls.Add(tb)
                    _lineEditors.Add(tb)
                End While
            End Using
        End Using
    End Sub

    Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        DirectCast(sender, TextBox).BackColor = SystemColors.Info
    End Sub

End Class

Iterovat kolekcí TextBoxů můžete v Listu _lineEditors

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Ještě mě napadla otázka, jak to udělat obráceně? (aby se po kliknutí na Button2 obsah všech textboxů uložil dohromady na řádky do jednoho souboru?)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Napadlo mne, že tohle budete chtít udělat a proto jsem tak ten kód navrhl. Viz ta poznámka o _lineEditors kolekci.

Public Class Form1

    Private _fileName As String = "C:/test.lsv"
    Private _lineEditors As New List(Of TextBox)

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim add As Integer = 0
        Using fs As New IO.FileStream(_fileName, IO.FileMode.OpenOrCreate)
            Using sr As New IO.StreamReader(fs, System.Text.Encoding.UTF8)
                While Not sr.EndOfStream
                    Dim tb As New TextBox
                    tb.Text = sr.ReadLine()
                    AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
                    tb.Location = New Point(12, 45 + add)
                    add += 33
                    Me.Controls.Add(tb)
                    _lineEditors.Add(tb)
                End While
            End Using
        End Using
    End Sub

    Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        DirectCast(sender, TextBox).BackColor = SystemColors.Info
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Using fs As New IO.FileStream(_fileName, IO.FileMode.Create)
            Using sw As New IO.StreamWriter(fs)
                For Each tb As TextBox In _lineEditors
                    sw.WriteLine(tb.Text)
                Next
            End Using
        End Using
        MsgBox("All values has been saved.", MsgBoxStyle.OkOnly, "Save")
    End Sub

    ' append a new line editor
    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim tb As New TextBox
        tb.Text = String.Empty
        AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
        tb.Location = New Point(12, _lineEditors.Last.Location.Y + 33)
        Me.Controls.Add(tb)
        _lineEditors.Add(tb)
    End Sub

End Class

Button dva nyní obsluhuje ukládání, prohlédněte si ten kód, uvidíte, že to není žádná věda =)

Taky jsem přidal Button3, který připojí další TextBox na konec, což Vám umožní vytvořit další řádek, hodnotu.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Btw ještě malý detail. Když teď řádky uložíte a znova načtete, nové TextBoxy se Vám naplácají přes ty staré, ale když to pak uložíte zase, uložíte jak ty staré, tak ty nové (reference na ty staré zůstanou v kolekci _lineEditors). Předejít tomu můžete tak, že ještě před otevřením, na začátku metody Button1_Click nejdřív projedete _lineEditors a každý TextBox z formuláře odeberete a poté vyclearujete ten List, aby aplikace po každém novém načtení souboru začínala s čistým štítem...

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Kuju x)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Poslední dotaz - jak jste řekl, snažil jsem se smazat předchozí Textboxy a upravil kód pro otevření takto


    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim add As Integer = 0
        Using fs As New IO.FileStream(_fileName, IO.FileMode.OpenOrCreate)
            Using sr As New IO.StreamReader(fs, System.Text.Encoding.Default)
                For Each tb As TextBox In _lineEditors
                    _lineEditors.Remove(tb)
                Next

                While Not sr.EndOfStream
                    Dim tb As New TextBox
                    tb.Text = sr.ReadLine()
                    AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
                    tb.Location = New Point(12, 45 + add)
                    add += 33
                    Me.Controls.Add(tb)
                    _lineEditors.Add(tb)
                End While
            End Using
        End Using
    End Sub

Ovšem to u Next hází Error

Collection was modified; enumeration operation may not execute.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ano, to je proto, že dojde k modifikaci kolekce během její iterace. Vyřeší se to While cyklem.

        Dim add As Integer = 0
        While _lineEditors.Count > 0
            Me.Controls.Remove(_lineEditors.First)
            _lineEditors.RemoveAt(0)
        End While
        Using fs As New IO.FileStream(_fileName, IO.FileMode.OpenOrCreate)
        ...

Btw přesunul jsem tu smazání před streamy, jak vidíte, to je proto, že mazání kompientn jako takové nepotřebuje přístup k tomu soubru a program by ho držel zbytečně déle, než by bylo třeba. Obecně platí, že pokud otevíráte Stream a pdoobné záležitosti, které pak Flushujete,Disposnete atp. tak v Using ... End Using konstrukci kde s nimi pracujete má být právě jen kód který se jich bezprostředně týká.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Aha :)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Můžu si dovolit jeden dotaz? Zajímalo by mne, jaký scénář aplikace vyžaduje řešení, které používáte? Napadá mne totiž, že na to možná jdete špatně. To, co tu spolu dáváme dohromady by se též dalo vyřešit ListBoxem, u kterého by se nastavilo, že aktivní Item se překryje jedním Textovým polem, který se bude řádek editovat, pokud by Text TextBoxu po editaci zůstal například prázdný, chápalo by se to jako impuls k odstranění řádku a vytvoření nového řádku by se dalo iniciovat například vložením prázdného řádku (Itemu) na konec ListBoxu... Je to alternativa, o které byste měl také vědět, možná Vám přijde užitečnější :)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Tato varianta mne nenapadla :), stejně si ale myslím, že tento způsob bude lepší - program bude navíc plně skinovatelný. Dělám menší organizátor úkolů i se zatrhávátky a myslím, že se takhle se také více naučím, neboť se mi jistě budou určité části kódu hodit někdy jinde =)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

K té skinovatelnosti - toho samého by se dalo dosáhnout i s tím ListBoxem, jež podporuje OwnerDraw a mohl byste si tedy texty sám vykreslovat, pomocí MeasureItem by se dalo udělat i to, že by jednotlivé řádky byli různě vysoké v závislosti na obsahu, šlo by zapojit obrázky... Nicméně volba je na Vás a já vám držím palce ať vývoj dopadne,jak chcete :)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

:)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Skuste toto :

  Dim TextBox1 As New TextBox()
  TextBox1.Text = "Test"
  TextBox1.Location = New Point(100, 50)
  TextBox1.Size = New Size(75, 23)
  Me.Controls.Add(TextBox1)

Píšem z hlavy ,tak neviem či to funguje ,ale myslím že hej :)

Kristián Moser

nahlásit spamnahlásit spam 5 / 5 odpovědětodpovědět

Děkuji vám. :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

jak zařídit aby se při druhém kliku na stejné tlačítko vytvořil pod textboxem další textbox? Díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

tak ako si doteraz vytvaral setky len si zisti lokaciu posledneho vytvoreneho textboxu aby si vedel kam ho umiestnit...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tento user to asi nečetl... Tady máte Sub, snad to stačí... Příště čtěte celé vlákno

    Sub NovyRadek()
        Dim tb As New TextBox
        tb.Text = String.Empty
        tb.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
        tb.Width = Panel1.Width
        Try
            tb.Location = New Point(0, _lineEditors.Last.Location.Y + tb.Height)
        Catch ex As Exception
            tb.Location = New Point(0, 0)
        End Try
        Panel1.Controls.Add(tb)
        _lineEditors.Add(tb)
    End Sub

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Přijde mi jednodušší na začátku zjistit (nebo zadat ručně) pozici prvního textboxu do veřejné proměnné (x,y)a při každém vytváření nového textboxu do proměnné jen přičíst hodnoty

Sub NovyRadek()
Dim tb as new textbox
y += 23
tb.location = new point(x,y)
Panel1.Controls.Add(tb)
End Sub

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback