Neplynulé překreslení   zodpovězená otázka

VB.NET, WinForms

Zdravím, potřeboval bych poradit s jedním kosmetickým problémem. Po zapnutí mé aplikace se nastaví pozadí formuláře a tabControlu. Později potřebuju například dočasně nastavit Me.TabControl.enabled=false (generují se nějáká data pro uživatele a já potřebuji zajistit aby v průběhu generování do aplikace nezasahoval).

A zde je trošku problém, při změně vlastnosti enabled se formulář nepřekreslí plynule ale problikne. Je možné tento jev něják eliminovat? Na formuláři mám povolený doubleBuffered. Pokud nepoužiju žádné pozadí, tak k probliknutí nedojde.

Zde je kód kterým nastavuju pozadí:

frmAplikace.BackgroundImage = My.Resources.pozadi_modre

Pozadí je obrázek ve formátu JPG (a zkoušel jsem i PNG). Vím že problikávání se zde řešilo, ale byl to myslím případ kdy uživatel něco ručně překresloval.

A ještě jedna otázka související s překreslováním. Pokud mi běží nějáký delší cykl (například načítam texťák po řádcích apod.), průběžně informuju uživatele jak je procedura daleko. Občas se ale stane, že aplikace vypadá jako kdyby spadla (z horní lišty zmizí ikona aplikace, formulář se nepřekresluje atd.) ale procedura normálně běží. Po doběhnutí se aplikace normálně překreslí a je vše ok.

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

K bodu 2.

Ve vb6 fungovalo DoEvents (něco podobného bude v net), tímto příkazem předáte řízení událostí systému.

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

Ne, tímto příkazem se pouze zpracuje fronta čekajících Windows zpráv. Toto amatérské řešení v žádném případě nepoužívat.

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

K otázce číslo 2: To je jasné, protože cyklus provádíte v hlavním vlákně aplikace, které má za úkol mimo jiné překreslování uživatelského rozhraní. Tím že ho zahltíte nějakou náročnou činností tak aplikace dočasně zamrzne. Řešení: Náročné operace provádět ve vlastním vlákně (hlavně neřešit pomocí Application.DoEvents() !!!)

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

No já to řeším tak, že volám form1.statusStrip.refresh

Funguje to v pořádku, pokud uživatel neklikne mimo aplikaci (tzn.aplikace není v pozadí a uživatel nepracuje s jinou aplikací).

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

Dobrý den, pane Linharte,

můžete naznačit, proč není dobré použití DoEvents? V literatuře a myslím i někde tady na webu se s tím člověk docela často setkává, proto mne Vaše informace docela překvapila a zajímaly by mne důvody tohoto Vašeho doporučení. Děkuji.

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

Hlavní důvod je ten, že aplikační vlákno by se nemělo zbytečně zatěžovat a mělo by dělat jenom věci, které nezabírají moc času. Jakoukoliv časově náročnou operaci by mělo vykonávat vlákno jiné. Tady na vbnetu občas v článku DoEvents použiju, ale je to především kvůli tomu, že nechci zbytečně ukázkové příklady komplikovat vlákny, protože to odvádí pozornost od konkrétního problému. Ale DoEvents není čisté řešení.

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

Děkuji za informaci. Přiznám se, že původně jsem to chápal jako zcela adekvátní nástroj (samozřejmě u operací, které je nutno provádět synchronně, tedy čekat na jejich dokončení, než mohu pokračovat dál), protože jsem si to vyložil, že vlastně tím jenom supluju práci OS, který procesoru stejně přiděluje různé procesy postupně, tedy i při přehození do jiného vlákna mi musí všechna vlákna obsloužit multiprocessing OS. (je pravdou, že jsem v této úvaze abstrahoval od vícejádrových procesorů).

Takže jdu prohlubovat své praktické zkušenosti s threadingem (a hlavně s tím související synchronizaci), abych vyrušil ty své DoEventy :-(

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

Dobrý den, pane Langer,

pojďme se podívat pod kapotu. Srdce každé Windows aplikace s uživatelským rozhraním je tzv. smyčka zpráv (Message Loop). Toto je zjednodušeně řečeno nekonečný cyklus Do...Loop, který nedělá nic jiného, než že přijímá Windows zprávy (Windows Message, WM_*) a odesílá je ke zpracování příslušným metodám (WndProc), ve kterých se již vyvolávají patřičné události (Button.Click). Jak už jsem na tomto webu kdesi zmiňoval, tak Windows zpráv jsou řádově stovky a slouží ke všem možným účelům, pro naše potřeby zejména k aktualizaci ovládacích prvků (vykreslování) a upozorňování na vstupy z klávesnice a myši. Při spuštění aplikace se smyčka zpráv rozjede právě v hlavním vlákně aplikace (po spuštění aplikace vlastně jediném). Následující kód velmi zjednodušeně představuje schéma smyčky zpráv:

Public Module MainModule()
  Public Sub Main()
    'GetMessage je funkce Windows API pro vyzvednutí Windows
    'zprávy z fronty zpráv.
    While GetMessage(...)
      'Odeslat zprávu ke zpracování (do WndProc)
    End While
  End Sub
End Module

Vzhledem k tomu, že tento nekonečný cyklus neustále běží po dobu spuštění aplikace a tím pádem se nonstop zpracovávají Windows zprávy, máme pocit, že aplikace běží plynule (překreslování uživatelského rozhraní, reagování na vstupy z klávesnice a myši). Řečnická otázka: Co se stane, když tomuto cyklu postavíme do cesty nějakou náročnou operaci, například načítání dat ze souboru?

Public Module MainModule()
  Public Sub Main()
    'GetMessage je funkce Windows API pro vyzvednutí Windows
    'zprávy z fronty zpráv.
    While GetMessage(...)
      'Odeslat zprávu ke zpracování (do WndProc)
      
      'Načítání ze souboru je časově náročná operace, která
      'zdržuje smyčku zpráv a způsobuje zamrznutí aplikace.
      Dim lines = IO.File.ReadAllLines(...)
    End While
  End Sub
End Module

Odpověď: Smyčka zpráv se pozastaví na dobu, než bude tato náročná operace dokončena a toto je právě důvod proč aplikace zamrzne, pokud náročnou operaci nespustíte ve vlastním vlákně, nezávisle na hlavním vlákně ve kterém běží smyčka zpráv.

Co způsobí DoEvents()?

Metoda Application.DoEvents() neudělá nic jiného, než že v okamžiku jejího zavolání zpracuje všechny Windows zprávy čekající ve frontě. Z hlediska uživatele aplikace to vypadá jako velmi vláčné, táhlé a pomalu reagující uživatelské rozhraní, které občas neodpovídá.

Pokud tedy chceme psát aplikace profesionálně, necháme hlavní vlákno na pokoji ať se věnuje zpracování Windows zpráv a veškerou časově náročnou činnost přesuneme do vlastních vláken.

Doufám že jsem do tohoto problému vnesl alespoň trochu světla.

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

Vážený pane Linharte,

mnohokrát Vám děkuji za Váš obsáhlý výklad. U Vašich odpovědí si mimo jejich věcnou erudovanost cením převážně té skutečnosti, že umíte jít tak trochu "za oponu", kterou pro nás .NET prostředí vytváří a pro mne je to zajímavé hned ze dvou důvodů.

Jednak jako profesí technik ("bohužel" ale v oboru strojařském) pátrám ne toliko po vnějších znacích toho kterého procesu, ale i po jeho podstatě, protože bez ní není možno ty vnější znaky důkladně poznat.

Jako další - a na tuto skutečnost jsem narazil již při několika "hlubších" diskusích s Vámi, je to pozadí pro mne zajímavé ještě z důvodu, že je mi kupodivu bližší, než ty vnější vyšperkované pochody. Třeba pokud se Vašeho dnešního tématu týká, mé programátorské počátky spadají do dob, kdy objektové programování a hlavně event-handled programování ještě nebylo zdaleka na pořadu dne, takže veškeré programy, které měly reagovat na jakékoliv "události" v reálném čase musely být právě takovými smyčkami, jako popisujete, řízeny (ale vše si musel vytvářet programátor sám).

Snad právě proto jsem při svých "povrchnějších" úvahách neviděl nic zlého, pokud uživatel do takové smyčky občas sám vstoupí, ale po vašem výkladu (který mi sice paradoxně nepřinesl žádnou informaci, kterou bych již dříve nevěděl nebo alespoň netušil - ale snad bylo důležité to vidět takto napsáno "černé na modrém" a doplněno Vaším fundovaným rozborem) mi stále víc a více připadá logické tvrzení, že využívání metody DoEvents není zrovna moc čisté a patří tak trochu k archaismům z dob minulých.

Ještě jednou Vám děkuji.

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

A to ešte pán Linhart pripravuje sériu článkov o programovaní viacvláknových aplikácii, len škoda že zatiaľ zostalo len u prvej časti... Určite by veľa ľudí privítalo ďaľšie časti (vrátane mňa) aj v menších časových intervaloch. Ale tak ako sa píše hore patrí p.L. poďakovanie za jeho snahu o pomoc.

nahlásit spamnahlásit spam 2 / 2 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