Platnost proměnné   otázka

VB.NET

Zdravím všechny.

Kdo mi poradí, ak nadeklaruji proměnou "But" aby platila i mimo cyklus ?. Ona proměnná sice po spuštění funguje, ale pořád mne to v režimu ladění upozorňuje na nedeklerovanou proměnou.

Jen pro vysvětlenou, potřebuji do TableLayoutPanelu přidávat controls a dopředu neznám jejich počet. V našem případě jsem počet buněk přiřadil, ale v konečné aplikaci bude záležet na počtu uživatelů a počtu vybraných dnů z kalendáře. Pro zjednodušení jsem do buňky "vrazil" jen button, ale v originálu bude v každé buňce jednoduchý panel s dalšími potřebnými Controls .

Viz kód.


Private Sub CreatePanelPlanning()
        Dim CellWidthPlanning As Integer = 60
        Dim CellHightPlanning As Integer = 30
        Dim RowsCountPlanning As Integer = 5
        Dim ColumnsCountPlanning As Integer = 15
        Dim PositionPlanning As TableLayoutPanelCellPosition
        Dim PanelPlanning As New Windows.Forms.TableLayoutPanel
        Dim PointPlanning As Point
        
PointPlanning.X = 10
        PointPlanning.Y = 50

        With PanelPlanning
            .Location = PointPlanning
            .CellBorderStyle = TableLayoutPanelCellBorderStyle.InsetDouble
            .RowCount = RowsCountPlanning
            .ColumnCount = ColumnsCountPlanning
            .Width = (CellWidthPlanning + 4) * ColumnsCountPlanning
            .Height = (CellHightPlanning + 4) * RowsCountPlanning

            For r = 0 To RowsCountPlanning - 1
                .RowStyles.Add(New RowStyle(SizeType.Absolute))
                .RowStyles(r).Height = CellHightPlanning

                For s = 0 To ColumnsCountPlanning - 1
                    If r = 0 Then
                        .ColumnStyles.Add(New ColumnStyle(SizeType.Absolute))
                        .ColumnStyles(s).Width = CellWidthPlanning
                    End If
                    Dim But As New Windows.Forms.Button
                    But.Name = "S_" & r & "_" & s
                    But.Text = "S: " & r & "/" & s
                    PositionPlanning.Row = r
                    PositionPlanning.Column = s
                    .SetCellPosition(But, PositionPlanning)
                    .Controls.Add(But)
                    'AddHandler But.Click, AddressOf PanelPlanningButtonClick "Zde funguje bez problému, ale volá se v každém cyklu"
                Next

            Next
            AddHandler But.Click, AddressOf PanelPlanningButtonClick 'Sice funguje ale v debug režimu mne upozorňuje na "Error	Name 'But' is not declared."

            Me.Controls.Add(PanelPlanning)
        End With
    End Sub

    Private Sub PanelPlanningButtonClick(ByVal sender As Object, ByVal e As System.EventArgs)
        MsgBox(sender.name)
    End Sub

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

"But" deklarujete uvnitř cyklu a tak platí jenom v něm, za cyklem již "But" neexistuje.

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

Přidejte deklaraci "But" k těm nahoře...

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

Děkuji za snahu, ale pokud deklaruji proměnnou nahoře tak to zase "nevidí" do cyklu. Samozřejmě jsem to zkoušel.

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

Tázal jste se na platnost proměnné. Když ji nadefinujete před cyklem, bude platit i v něm. Tam místo definice změníte její obsah (But = New Windows.Forms.Button). Proč a nač, jsem nestudoval

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

Nechápu, čeho chcete dosáhnout. Vy si cyklem vytvoříte několik tlačítek, a až na poslední z nich namapujete nějakou událost? Tak, jak to máte teď, by to tak fungovalo. Nevím, k čemu by to bylo dobré.

Proč máte AddHandler v tom cyklu zakomentovaný? Přeci chcete událost nastavit každému tlačítku, ne? Takže se musí zavolat pro každé tlačítko, aby se to tlačítko napojilo na danou událost.

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

Kód nemusí být dodělaný a možná jsou odstraněné některé jeho části. Možna jde jen o nějaký pokus :)

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

Mě šlo spíš o to, vysvětlit jak se nadeklaruje proměnná např. v cyklu, tak aby ji viděla celá procedura. Nebo obráceně, nadeklaruji si proměnnou hned na začátku, ale ta nevidí do cyklu a samozřejmě v design mode mi to hlásí chybu. Přestože při ignoraci tohoto hlášení po spuštění vše funguje, takže proměnná je viditelná v celé proceduře. Chápu, že se mě basic snaží informovat o tom, že v podminkách a cyklech se nemusí proměnná "naplnit" a proto se ptám, jak mám takovou proměnnou nadeklarovat ?

Zkrátka,inicializuji proměnnou třeba v cyklu, protože jí tam potřebuji, ale zároveń s ním budu pracovat i mimo cyklus.

Dá se to nějak elegantně řešit ?

Co se týče Vašeho dotazu, k čemu mi to bude dobré ?

Podobnou funkční aplikaci už jsem vytvořil ve VB6, ale tam jsem to řešil pomocí flexgridu. Aplikace slouží k plánování služeb, pohotovostí apod. pro předem neurčený počet pracovníků a dní. Aplikace při kliknutí na vytvořené tlačítko postupně mění ikony a přitom nabízí jen logicky dostupné varianty.Např. zaměstnanec nemůže jít na denní ihned po noční, nebo nemůže zároveň být v práci i na pohovotosti atd. Dále je možné nastavit dovolené, blokované volna, nemoci atd. . Při těchto změnách se zároveň přepisují již surové data do databáze. Stejně pak i načitá tyto data a na jejich základě přiřazuje odpovídající ikony k jednotlivým buttonům, tedy zaměstancům resp. dnům a činostem. Na základě tohoto rychlého nadefinování služeb, aplikace spočítá odpracované hodiny, zbylou dovolenou, dále kontroluje naplnění služeb a pohotovostí i např. dle dne v týdnu a následně vytváří tisknutelné sestavy pro potřeby personálního oddělení i pracovníků. Protože bych rád umožnil editaci uživatelsky definovaného časového rozpětí a dopředu neznám počet aktivních pracovníků, proto musím celou strukturu programu tvořit až za běhu. Tady však narážím na problém, který ve VB6 nebyl. Jestli si dobře pamatuji, tam se dal definovat název nějakých ovl. prvků, pomocí indexu, na který se pak dalo jednoduše odkazovat. Stačilo ve formuláři vytvořit jeden primární ovládací prvek a pak přičítat pouze onen index, při vytváření dalších. Nebyl tedy problém se odkazovat i v design režimu na ještě neexistující ovládcí prvky. U vb.net jsem se bohužel dočetl, že už nelze využívat této techniky. Proto se ještě ptám, existuje nějaký způsob jak se odkazovat na určité ovl. prvky, které se tvoří až za běhu ? Vím, že můžu vytvářenemů prvku zadat název, ale lze se na něj později odkazovat ? Jde o to, že tyto prvky jsou v zájemné logice a proto potřebuji vědět co obsahuje prvek vedle či pod ním.

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

Pokud proměnnou nadeklarujete v cyklu, platí pouze v tom cyklu. Pokud ji nadeklarujete v proceduře, platí v celé proceduře (i v cyklech, které jsou uvnitř). Deklarace je příkaz Dim něco AS něco. Pokud Vám jde o to, aby Visual Basic neházel warningy, protože cyklus se nemusí provést ani jednou a za ním byste pracoval s neinicializovanou proměnnou, stačí přímo v deklaraci do této proměnné něco přiřadit, ideálně Nothing. Pak si samozřejmě musíte dát pozor, abyste do proměnné něco smysluplného přiřadil, než s tím budete pracovat.

Co se týče druhého dotazu, já jsem se spíš ptal, proč si v cyklu vytváříte několik tlačítek a AddHandler máte až za cyklem, čímž namapujete událost jen pro poslední tlačítko, pro to, které je zrovna v proměnné btn nebo jak se to jmenuje. Pokud chcete, aby to fungovalo, musíte mít AddHandler uvnitř cyklu, aby se s událostí provázalo každé tlačítko a ne jen to poslední.

Jinak pokud potřebujete něco jako kolekci komponent na formuláři, která byla ve VB6, asi nejelegantnější řešení je dát si do deklarací ve formuláři (mimo proceduru) něco jako:

Dim TextBoxy As New List(Of TextBox)

Tím se vytvoří seznam pro položky typu TextBox, který se může libovolně nafukovat. Když komponenty v cyklu generujete, po přidání na formulář je ještě přidejte do tohoto seznamu, nějak takto:

Dim txb As TextBox = Nothing   'tahle deklarace by šla šoupnout i dovnitř cyklu, ale chci Vám zároveň ukázat, jak se to dá dělat s jednou proměnnou
For i As Integer = 1 To 10   'vytvoříme 10 TextBoxů
   txb = New TextBox()
   txb.Left = i * 50: txb.Top = 30
   Me.Controls.Add(txb)    'přidat TextBox na formulář
   TextBoxy.Add(txb)       'přidat TextBox do seznamu TextBoxy
Next
'poznámka - za cyklem je v proměnné txb odkaz na poslední TextBox

Tím vygenerujete 10 TextBoxů a přidáte je do seznamu TextBoxy. Na jednotlivé TextBoxy se pak z celého formuláře můžete odkazovat přes TextBoxy(i), kde i je pořadí vytvoření (čísluje se od nuly).

Jinak je nutné si uvědomit, že TextBox je třída - referenční typ. Proto když napíšete New TextBox, vytvoří se nový objekt, ale ten není fyzicky uložen v té proměnné, do které tohle přiřadíte. Objekt samotný leží kdesi v paměti (na haldě) a do proměnné se uloží jenom adresa, kde ten objekt leží. Když tedy do proměnné txb přiřadíte jeden TextBox a za chvíli do ní uložíte druhý, ten první se nesmaže. Například u čísel (Integer, Single, Double atd.), což jsou hodnotové typy, by se tohle stalo - hodnota je uložena přímo v proměnné. U objektů ale ne, prostě jenom zmizí odkaz na ten objekt a nahraje se tam jiný. Objektu se to nijak nedotkne. stejně tak formulář má v kolekci Controls seznam odkazů na objekty, které má na sebe vykreslit (přidali jsme mu je tam přes Me.Controls.Add), a stejně tak náš seznam TextBoxy si vlastně také drží jenom odkazy na skutečné objekty. Jakmile na objekt v paměti nevedou žádné odkazy, tento objekt bude odstraněn Garbage Collectorem.

Kdyžtak si přečtěte tento článek, je to tam vysvětlené podrobněji: http://www.vbnet.cz/clanek--107-objektov... . Připadá mi, že v tom trochu tápete.

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

I když jsem ten Addhandler pro tlačítko uvedl mimo vnitřní cyklus, tak se asi díky nějaké dědičnosti, protože byl provázán na vnitřní panel prováděl u všech tlačítek. V reálu se jedná o jeden tablepanel, v kterém jsou obsaženy další tablepanely a na nich jsou tlačítka. Možná by stačilo přidat jen jeden addhandler pro tlačítka a u vniřních názvů uvádět jen název a fungovalo by to stejně. Doma to ještě testnu a dám vědět.

Jinak, děkuji za vyčerpávající odpověď. Vyzkouším a moc děkuji za uvedený příklad.

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

Tak jste měl pravdu. Mimo cyklus ten addhandler nefunguje i po ignoraci chyby. Ono totiž při chybě nedojde k překompilaci a spustí se původní kompilace, kde byl addhandler uvnitř cyklu. To mi předtím nedošlo :-)

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