Tlačítko ve smyčce WHILE   zodpovězená otázka

VB.NET

Dobrý den, pro programátory je to ptákovina, ovšem jako laik na to nemohu přijít.Potřeboval bych v časově náročné smyčce WHILE...END WHILE kromě vlastní činnosti kódu ve smyčce kontrolovat i tlačítko, umístěné na stejném formuláři (nebo číst stisk klávesy na klávesnici). Poradíte prosím? Děkuji za pomoc. Moc mně nenadávejte, začínám...

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

Pokud máte nějaký náročný proces, spouštějte ho ve vlastním vlákně nebo vám přestane odpovídat uživatelské rozhraní a tím pádem vám bude kontrola tlačítka k ničemu. Kromě toho tlačítko není třeba kontrolovat, pouze na jeho událost napojit metodu která se automaticky zavolá při klepnutí na něj.

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

Ve formuláři si vytvořte boolean proměnou,

před spuštěním smyčky nastavit na false,

pak testujte ve smyčce zda je true, tak se

stane v události tlačítka click nebo keypress

formuláře u dané klávesy,kde ji dáte true.

Ale je to jen tip neprogramátora,nekamenovat.

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

Vždyť už jsem psal, že takhle to fungovat nebude, protože když zahltíte hlavní vlákno aplikace nějakým náročným cyklem tak se vám nebude vykreslovat uživatelské rozhraní a tím pádem nepůjde na nic kliknout! A ošetřit to pomocí Application.DoEvents() je totální lameřina která to vše akorát zpomalí...

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

Na začátečníky nemůžete hned vybafnout vlákna, to by se do toho úplně zamotali. Je pravda, že DoEvents zpomaluje a nemělo by se používat, ale úplným začátečníkům ho prozradit můžeme. Až budou umět programovat lépe, naučí se vlákna.

Dim zastavit As Boolean = False

Public Sub CasoveNarocnaProcedura()
   zastavit = False
   While podmínka

       Application.DoEvents()   'zpracuje události 
       If zastavit Then Exit While  'pokud je příkaz pro zastavení, vypadnout z cyklu 
   End While
End Sub

Public Sub Button1_Click(sender As Object, e As EventArgs)
   zastavit = True
End Sub

Jak psal kolega Linhart, toto řešení není vhodné používat v profesionálních aplikacích, nicméně začátečníkům bude stačit.

Události tlačítek ani jiných komponent se nemůžou zpracovat, pokud se zrovna zpracovává nějaká jiná událost, tak, jak události nastávají, řadí se do fronty a zpracovávají se postupně. Když máme nějakou událost, která se zpracovává dlouho, můžeme uvnitř zavolat Application.DoEvents, což způsobí, že se v daný okamžik zpracují všechny události, které čekají ve frontě za touto událostí, a pak se pokračuje dál. Díky tomu se nestane, že kliknutí na tlačítko aplikaci zasekne, ale událost se normálně zpracuje.

Vhodnější je použít vlákna, toto řešení není čisté, Application.DoEvents má poměrně velkou řežii a při extrémně častém volání zpomaluje.

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

Bohužel jsem z neznalosti asi špatně definoval situaci. Tlačítko chci používat v grafickém výstupu v Sub Form1_Paint(ByVal.... Pokud vše spustím bez procedury WHILE, je to OK, jakmile přidám smyčku, tlačítko je i špatně zobrazeno a nereaguje ani na výše uvedené zpracování událostí DoEvents.

Samozřejmě máte pravdu s použitím vláken, to je pro mně zatím velmi daleko.

Díky za trpělivost.

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

No, tady je problém, že v události Paint by se nemělo vůbec nic počítat, protože Paint vykresluje. Vykreslování obecně žere dost výkonu samo o sobě, takže ještě prodlužovat dobu spuštění této procedury není vhodné. A mimochodem kreslit na formulář z jiného vlákna také není to pravé.

Řešením je např. vykreslit scénu do obrázku a v události Paint ten obrázek překreslit na obrazovku. Nebudete si tím blokovat událost Paint, která by měla proběhnout co nejrychleji, aby vykreslování nebrzdila.

'vytvořit obrázek stejné velikosti jako je okno
Dim img As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height)
Dim g As Graphics = Graphics.FromImage(img)

'vykreslit časově náročnou scénu do obrázku a volat DoEvents
While něco
  g.DrawLine ...
  DoEvents()
End While

'říct formuláři, že jsme už hotovi, ať si zavolá událost Paint
Me.Invalidate()

'------------------------------------------------
Protected Sub Form1_Paint(sender As Object, e As PaintEventArgs)
    'až to bude, nakreslit to na formulář na pozici 0,0
    Me.CreateGraphics().DrawImage(img, 0, 0)
End Sub

Do události Paint tím pádem dáme jenom vykreslení jednoho velkého obrázku, který ale už máme nachystaný, takže Paint už zdržovat nebude.

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

Problém nastane v momentě, kdy bude požadavek na překreslení okna a výpočet obrázku ještě nebude hotov... Buď se bude muset počkat a nebo vykreslit předchozí obrázek (nový obrázek se kreslí do nové instance která se do proměnné kterou bude používat Paint přiřadí až v momentě dokončení vykreslování). Každopádně je to celé kostrbaté.

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