V dnešní době je web zdrojem nepřeberného množství informací. Avašak někdy může být díky neochotě webového prohlížeče problém se k nim dostat. Pokud tedy někdy zápasíte se svým prohlížečem, předkládám tu jednoduchý návod, jak postavit kostru vlastního...
Nejprve je třeba se zamyslet nad návrhem projektu. Náš webový prohlížeč se bude skládat z hlavního okna, ve kterém se budou zobrazovat jednotlivé záložky, přičemž uživatel bude moci mezi těmito záložkami volně přepínat a aktivní záložku ovládat danými nástroji. K dosažení cíle nám poslouží technologie MDI (Multiple Document Interface). MDI známe například z MS Wordu, kde je jedno hlavní okno, které může obsahovat větší množství rovnocenných podružných oken, ve kterých se zobrazují jednotlivé dokumenty.
Vytvoření nového projektu
Spusťte Visual Studio .NET, nebo Visual Basic .NET a založte nový projekt (vpřípadě Studia založte projekt pro VB). V prohlížeči budeme potřebovat dva druhy oknen, vložíme si proto do projektu ještě jeden prázdný formulář. Dále, abychom mohli provázat dceřinná okna se záložkovými tlačítky v hlavním okně, budeme potřebovat třídu. Vložíme tedy ještě prázdný soubor pro třídu. Nemusím jistě zmiňovat, že je vhodné si projekt průběžně ukládat.
Návrh formulářů
V Solution Exploreru (standardně okno v pravém horním rohu) poklikejte na první formulář, který se pro nás stane hlavním oknem. Otevře se vám návrhové okno pro úpravu formuláře a vkládání prvků. Pokud označíte jakýkoli ovládací prvek, v okně vlastností (standardně v pravém dolním rohu) se zobrazí vlastnosti, které můžete nastavit. Změníme vlastnost Name na "Master". Tím jsme definovali jméno, pomocí kterého se budeme odkazovat na formulář. Dále ještě u formuláře nastavíme IsMdiContainer na TRUE, protože chceme, aby se tento formulář choval jako hlavní rodičovské okno. Nyní z Toolboxu přidáme jednotlivé ovládací prvky hlavního okna, ktaré budeme potřebovat.
Jako první přidáme MenuStrip, který slouží pro vytvoření menu. Označíme kliknutím nový MenuStrip a jednotlivé položky menu intuitivně přidáváme tak, že do volné pozice, kde je napsáno "Type here", napíšeme text, který uživatel uvidí jako popisek položky menu. Pokud na již vytvořenou položku klikneme, můžeme do ní stejným způsobem vložit podmenu. Vytvořte tedy menu "Soubor", ve kterém budou potřebné příkazy "Nová záložka", "Zavřít záložku", "Zavřít všechny záložky" a "Konec", tak jak napovídá obrázek vpravo.
Dále budeme v hlavním okně potřebovat dva ToolStripy, vložte je tedy z Toolboxu do formuláře. Jeden bude sloužit jako lišta s tlačítky pro přepínání záložek a druhý jako panel nástrojů pro práci s aktivní záložkou. Jeden tedy označíme a z roletky na něm obzažené vložíme tlačítko. Po jeho označení je možné nastavovat vlastnosti, nastavte tedy popisek "Nová záložka". Stejným způsobem na druhém ToolStripu vytvořte ovládací prvky a nastavte popisky podle následující ilustrace (v pořadí zleva: Button, Button, Label, TextBox, Button). Stejně jako s ToolStripem se pracuje se StatusStripem, který také jeden vložte (využijeme jej pro informaci o stavu načítání stránky) a naplňte jej prvky podle obrázku, nastavte vlastnosti (v pořadí zleva: StatusLabel, ProgressBar, StatusLabel). Vkládaným prvkům doproučuji nastavit rozumné názvy, aby byla následná orientace v kódu jednodušší.
Nyní přejdeme k návrhu záložkového formuláře. Po otevření v návrhovém prostředí ho pojmenujte "Slave" a vložte na něj WebBrowser.
Trocha nutné teorie ... :(
Kód záložkového formuláře bude nejjednodušší, proto s ním začneme. K editoru kódu se dostaneme tlačítkem v Solution Exploreru, nebo přez View>Code. Nyní budeme pracovat na návrhu třídy formuláře, dalo by se říci "šablony", podle které potom budeme vytvářet jednotlivé instance tohoto formuláře. Můžeme se tedy představit, že každý konkrétní formulář, který vytvoříme podle Slave, potom bude obsahovat stejné prvky, metody (Method), události (Event) i vlastnosti (Property).
Psaní kódu ... konečně :)
Záložkový formulář nebude zrovna vzkvétat vlastní inteligencí, tu za něho přebere jeho rodičovský objekt. V tomto formuláři vytvoříme pouze 4 veřejné (Public) sub-rutiny (Sub), které budeme volat, pokud budeme chtít, aby záložka provedla určitou činnost. V těch nebude nic jiného, než že budou předávat příkazy WebBrowseru. V případě rutiny "tabGoto" předáváme ještě adresu webu, který chceme zobrazit. Poslední částí kódu tohoto formuláře je událost jeho načtení "Slave_Load", která proběhne před prvním zobrazením formuláře. Její hlavičku nemusíme vypisovat, stačí z levé záložky nad oknem kódu vybrat "(Slave Events)" a v pravé událost "Load". Při této události záložku maximalizujeme a WebBrowseru poručíme jít na domovskou stránku. Tím je kód záložkového okna hotov:
'kod formulare Slave, ktery bude pouzit jako zalozky
Public Class Slave
'aktivovani formulare
Public Sub tabActivate(ByVal sender As Object, ByVal e As System.EventArgs)
Me.Activate()
End Sub
'otevreni stranky
Public Sub tabGoto(ByVal address As String)
wb.Navigate(address)
End Sub
'historie zpet
Public Sub tabBack()
wb.GoBack()
End Sub
'historie vpred
Public Sub tabForw()
wb.GoForward()
End Sub
'pri otevreni nove zalozky ji maximalizujeme a prejdeme na domovskou stranku
Private Sub Slave_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.WindowState = FormWindowState.Maximized
wb.GoHome()
End Sub
End Class
Nyní je třeba oživit hlavní okno. Nejdůležitější jsou pro nás dvě rutiny "tabAdd" a "tabRemove", které budou sloužit pro vytvoření respektive zavření záložky. Tyto následně budeme volat u událostí Click příslušných položek menu a tlačítek. Protože budeme za záložku považovat třídu, která za nás udělá všechnu práci, stačí v rutině pro novou záložku vytvořit novou instanci této třídy, která se o vše již postará. Protože naše třída bude chytrá, odchytí si, pokud uživatel zavře okno a kompletně se zruší. Proto tedy můžeme záložky zavírat například zavřením formuláře, jak je vidět z rutiny "tabRemove". Podobně funguje i událost, která nastane při kliknutí na položku menu "Zavřít všechny záložky", která projde kolekci MdiChildren hlavního formuláře a zavře všechny jeho podružné formuláře.
'pridani nove zalozky
Private Sub tabAdd()
'vytvorime objekt nove zalozky podle tridy TWindow
Dim newWindow As TWindow
newWindow = New TWindow(Me)
End Sub
'odebrani zalozky
Private Sub tabRemove()
'pokud existuje aktivni zalozka, zavreme ji
Try
Me.ActiveMdiChild.Close()
Catch
MsgBox("Musíte mít otevřenou záložku")
End Try
End Sub
'zavreni vsech zalozek
Private Sub mnuCloseAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles mnuCloseAll.Click
For Each tab As Form In Me.MdiChildren
tab.Close()
Next
End Sub
Dále je třeba implementovat ovládání záložek. Díky tomu, že hlavní formulář má vlastnost ActiveMdiChild, která nás informuje o aktivním podružném okně, není problém na tomto okně zavolat rutiny, které jsme implementovali dříve. Tedy rutiny pro procházení historie a otevření webu na dané adrese. Abychom zvýšili uživatelský komfort, odchytíme událost KeyDown textového pole s adresou, a pokud uživatel stiskl enter, je to jako kdyby klikl na "GO".
'v historii krok zpet
Private Sub ToolBack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolBack.Click
'aktivni zalozce predame povel
Try
Dim actChild As Slave = Me.ActiveMdiChild
actChild.tabBack()
Catch
MsgBox("Musíte mít otevřenou záložku")
End Try
End Sub
'v historii krok dopredu
Private Sub ToolForw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolForw.Click
'aktivni zalozce predame povel
Try
Dim actChild As Slave = Me.ActiveMdiChild
actChild.tabForw()
Catch
MsgBox("Musíte mít otevřenou záložku")
End Try
End Sub
'presmerovani
Private Sub ToolAdresaBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolAdresaBtn.Click
Try
'pokud zalozka existuje, predame ji adresu
Dim actChild As Slave = Me.ActiveMdiChild
actChild.tabGoto(Me.ToolAdresaTxt.Text)
Catch
'pokud zalozka neexistuje, vytvorime ji
tabAdd()
Dim actChild As Slave = Me.ActiveMdiChild
actChild.tabGoto(Me.ToolAdresaTxt.Text)
End Try
End Sub
'pohlidame, pokud v adresim radku uzivatel zadal enter,
'je to totez, jako kdyby kliknul na "GO"
Private Sub ToolAdresaTxt_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles ToolAdresaTxt.KeyDown
If e.KeyCode = Keys.Enter Then
ToolAdresaBtn_Click(Me, System.EventArgs.Empty)
End If
End Sub
Poslední, co musí hlavní formulář umět je reakce na změny na záložkách. Konkrétně se jedná o změnu titulku okna a změnu stavu načítání dokumentu. Tyto události za nás pohlídá záložková třída, ovšem musí exisovat rutiny, které se v tu chvíli provedou. Rutina "updateTitle" tedy nastaví titulek hlavního okna stejný, jaký má aktivní záložka a "updateProgress" se postará o to, aby se ve status-baru objevilo "Hotovo" v případě, že je dokument kompletní, případně progress-bar, který ukáže aktuální stav.
'nastaveni titulku okna
Public Sub updateTitle()
Me.Text = Me.ActiveMdiChild.Text
End Sub
'zmena progresu
Public Sub updateProgress(ByVal progress As Single)
If progress = 1 Then 'nacteno
statusLoadProc.Visible = False
statusLoadBar.Visible = False
statusLoadTxt.Text = "Hotovo"
Else 'stale se nacita, zobrazime procenta
statusLoadTxt.Text = "Načítám:"
statusLoadProc.Visible = True
statusLoadBar.Visible = True
statusLoadBar.Value = CInt(100 * progress)
End If
End Sub
Třída TWindow
Nyní je čas naprogramovat již několikrát zmiňovanou třídu, která bude jádrem programu. Je tedy třeba otevřít soubor s kódem třídy a přejmenovat ho. Pokud jste dodržovali stejné názvy jako já v rutině pro tvorbu nové záložky, pojmenujte třídu "TWindow". Aby naše třída mohla udržet informace o tom, že k záložce kterou reprezentuje patří konkrétní tlačítko v liště a konkrétní formulář, je potřeba, aby si na ně udržovala reference. Třída tedy bude mít následující soukromé (Private) vlastnosti, které budou schraňovat tyto informace:
'vnitrni reference na objekty
Private myButton As ToolStripButton 'tlacitko v hlavnim formulari
Private myMark As Slave 'formular zalozky
Private myBrowser As WebBrowser 'webBrowser na formulari zalozky
Private myMaster As Master 'rodicovske okno
Každá třída může obsahovat takzvaný konstruktor. Je to událost, která nastane, pokud z dané třídy vytvoříme instanci. Pokud tedy v našem prohlížeči necháme zobrazit novou záložku, vytvoří se nám instance této třídy a je třeba vykonat určité akce. Nejdříve si nastavíme referenci rodičovského okna, abychom jej mohli následně ovládat. Potom vytvoříme nový formulář a tlačítko hlavního panelu a taktéž si na ně uložíme reference, abychom s nimi mohli komunikovat. Naposled je ještě třeba přidat si kontrolování událostí, což se provede klíčovým slovem AddHandler, za kterým následuje událost, kterou chceme obsloužit a jméno procedury, pomocí které chcemu událost obsloužit.
'konstruktor
Public Sub New(ByVal myParent As Master)
'ulozime si instanci rodicovskeho okna
myMaster = myParent
'vytvorime a zobrazime nove okno
myMark = New Slave
myMark.MdiParent = myMaster
myMark.Show()
'vytvorime a pridame tlacitko do zalozkove listy
myButton = New ToolStripButton
myMaster.toolTabs.Items.Add(myButton)
'vytvorime odkaz na browser
myBrowser = myMark.wb
'pridame udalosti
'pokud klikneme, aktivujeme dany form
AddHandler myButton.Click, AddressOf myMark.tabActivate
'pokud se formular zavira, znicime tlacitko
AddHandler myMark.FormClosing, AddressOf Remove
'pokud se zmenil titulek stranky
AddHandler myBrowser.DocumentTitleChanged, AddressOf TitleChange
'pokud se zmenil stav nacitani dokumentu
AddHandler myBrowser.ProgressChanged, AddressOf ProgressChange
End Sub
Všiměte si, prosím, že například v případě, kdy se uzavírá formulář (tedy uživatel zavře záložkové okno), zavolá se rutina Remove. Rutina remove tedy odebere tlačítko z lišty záložek a zruší reference. Obdobná situace nastává se změnou titulku a stavu dokumentu. Při změně titulku stránky je třeba nový titulek nastavit jako nadpisy oken a tlačítka reprezentujícího danou záložku, o což se stará rutina "TitleChange". Při změně progresu se vypočítá stav načítání dokumentu a pošle se do hlavního formuláře, kde je zobrazen ve status-baru.
'zruseni zalozky
Private Sub Remove(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs)
'odebereme tlacitko z listy masteru a zrusime reference
myMaster.toolTabs.Items.Remove(myButton)
myButton = Nothing
myMark = Nothing
End Sub
'zmena titulku
Private Sub TitleChange(ByVal sender As Object, ByVal e As System.EventArgs)
'zjistime novy titulek okna a rozdistribuujeme ho, kam je treba
Dim text As String
text = myMark.wb.DocumentTitle
myMark.Text = text
myButton.Text = text
myMaster.updateTitle()
End Sub
'zmena progresu nacitani
Private Sub ProgressChange(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserProgressChangedEventArgs)
'spocitame progress a obnovime ho v hlavnim okne
Dim progress As Single
If myBrowser.IsBusy Then
If e.MaximumProgress = 0 Then
progress = 0
Else
progress = e.CurrentProgress / e.MaximumProgress
End If
Else
progress = 1
End If
If progress > 1 Then progress = 1
myMaster.updateProgress(progress)
End Sub
Hotovo
Nyní již můžete vyzkoušet projekt spustit a zkusit pracovat s prohlížečem. Jistě objevíte mnoho neohrabaností svého výtvoru. Zkuste je tedy jako cvičení odstranit. Pokud nemáte žádné nápady na vylepšování, tak nějaké nabízím:
- Aktualizace adresy v adresním řádku při přechodu na jinou stránku
- Grafická reprezentace příkazových tlačítek
- Nastavení vlastní domovské stránky
- Místo adresního text-boxu combo-box, který si bude pamatovat zadané adresy
- ...
Pokud chcete využít metod zpětného inženýrství, kompletní projekt je ke stažení zde.
Přeji mnoho zdaru...