Aplikace ve Win32 API - 'průzkumník'
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Aplikace ve Win32 API - 'průzkumník'Aplikace ve Win32 API - 'průzkumník'

 

Aplikace ve Win32 API - 'průzkumník'

Google       Google       24. 3. 2010       24 122×

V předchozím dílu jsme si ukázali tvorbu komponent a nyní je na řadě slíbená první aplikace, která bude "něco dělat" a na které si ukážeme využití komponent: jednoduchá verze průzkumníka.

Průzkumník (z dílny Microsoftu) jako takový má mnoho funkcí, ale my se v tomto díle soustředíme pouze na strohé zobrazení seznamu/stromu disků, adresářů a souborů. Nebudeme vymýšlet nic převratného. Okno vertikálně rozdělíme na dvě části, do levé vložíme stromovou strukturu disků a jejich adresářů. Do pravé části umístíme seznam adresářů a souborů ve vybraném disku/adresáři v levé části. Funkčnost bude dost omezená. Nechceme přece udělat originálnímu Průzkumníku konkurenta (zatím :)).

Nejprve si připravíme komponenty, tj. komponentu pro zobrazení stromové struktury a komponentu pro zobrazení seznamu. Obě komponenty jsou již definovány - stromová struktura se zobrazuje pomocí TreeView (WC_TREEVIEW) a seznam se zobrazuje pomocí komponenty ListView (WC_LISTVIEW). Vzhledem k tomu, že se jedná o komponenty z common control DLL, tak je nutné udělat i jejich inicializaci, kterou můžeme provést přímo v konstruktoru těchto tříd. Pro inicializaci použijeme funkci InitCommonControlsEx.

CMyTreeView::CMyTreeView() : CMyWindow(WC_TREEVIEW)
{
	INITCOMMONCONTROLSEX	sInitCommonControl;

	sInitCommonControl.dwSize	= sizeof(INITCOMMONCONTROLSEX);
	sInitCommonControl.dwICC	= ICC_TREEVIEW_CLASSES;

	InitCommonControlsEx(&sInitCommonControl);
}
CMyListView::CMyListView() : CMyWindow(WC_LISTVIEW)
{
	INITCOMMONCONTROLSEX	sInitCommonControl;

	sInitCommonControl.dwSize	= sizeof(INITCOMMONCONTROLSEX);
	sInitCommonControl.dwICC	= ICC_LISTVIEW_CLASSES;

	InitCommonControlsEx(&sInitCommonControl);
}

Obě komponenty mají seznam zpráv, pomocí kterých se ovládají. Tyto zprávy mají svoje ekvivalenty v předdefinovaných makrech (seznam maker pro TreeView a seznam maker pro ListView). My si do naší komponenty implementujeme pouze volání těch zpráv/maker, která využijeme, ale stejným způsobem by bylo možné implementovat všechna volání. Nejdůležitější pro nás bude vkládání nových položek a mazání.

Nejprve pro TreeView:

BOOL CMyTreeView::DeleteAllItems()
{
	if (m_hWnd == NULL) return(FALSE);

	return(TreeView_DeleteAllItems(m_hWnd));
}


BOOL CMyTreeView::DeleteItem(HTREEITEM hItem)
{
	if (m_hWnd == NULL) return(FALSE);
	if (hItem == NULL) return(FALSE);

	return(TreeView_DeleteItem(m_hWnd, hItem));
}


HTREEITEM CMyTreeView::InsertItem(LPTVINSERTSTRUCT psItem)
{
	if (m_hWnd == NULL) return(NULL);
	if (psItem == NULL) return(NULL);

	return(TreeView_InsertItem(m_hWnd, psItem));
}

Pro ListView je to velice podobné:

BOOL CMyListView::DeleteAllItems()
{
	if (m_hWnd == NULL) return(FALSE);

	return(ListView_DeleteAllItems(m_hWnd));
}


BOOL CMyListView::DeleteItem(int nIndex)
{
	if (m_hWnd == NULL) return(FALSE);
	if (nIndex < 0) return(FALSE);

	return(ListView_DeleteItem(m_hWnd, nIndex));
}


int CMyListView::InsertItem(LPLVITEM psItem)
{
	if (m_hWnd == NULL) return(-1);
	if (psItem == NULL) return(-2);

	return(ListView_InsertItem(m_hWnd, psItem));
}

Vzhledem k tomu, že obsah TVINSERTSTRUCT nebo LVITEM je možné různě kombinovat, tak je naše funkce pro vkládání položek přes tyto struktury stejně univerzální. Stejně tak by bylo možné vytvořit funkce, které by byly speciální (jenom text, text a ikona apod.), např.:

int CMyListView::InsertItem(LPWSTR pwzText)
{
	LVITEM	sItem;

	if (m_hWnd == NULL) return(-1);
	if (pwzText == NULL) return(-2);

	ZeroMemory(&sItem, sizeof(LVITEM));

	sItem.mask	= LVIF_TEXT;
	sItem.pszText	= pwzText;
	sItem.item	= ListView_GetItemCount(m_hWnd);
	
	return(ListView_InsertItem(m_hWnd, &sItem));
}

Nyní máme vše potřebné pro vytvoření GUI stránky aplikace, takže můžeme pomalu naší aplikaci vdechnout život, tj. naprogramovat funkci stromové struktury a po výběru nějaké položky v této stromové struktuře naplnit seznam adresářů a souborů.

Strom naplníme při jeho inicializaci dostupnými diskovými jednotkami. Každé přiřadíme falešnou podpoložku, aby šlo expandovat strom, který ještě není načtený. Při expandování položky stromu pošle komponenta TreeView svému rodičovskému oknu notifikaci TVN_ITEMEXPANDING, na kterou budeme reagovat tak, že pro daný adresář načteme do stromu jeho podadresáře. Abychom mohli tuto notifikaci zachytávat, tak komponentu TreeView (resp. instanci třídy CMyTreeView) zapouzdříme do panelu CTreeViewPanel a v této třídě budeme zachytávat a zpracovávat notifikace. Notifikace posílá komponenta svému rodičovskému oknu, v našem případě to bude právě tento panel.

Druhou notifikací, na kterou budeme v třídě CTreeViewPanel reagovat, je TVN_SELCHANGED. Reakcí na tuto notifikaci (tj. na výběr nové položky) bude změna obsahu seznamu souborů (v ListView). Odešleme tomuto oknu zprávu s pointerem na řetězec obsahující úplnou cestu, kde má soubory/adresáře hledat. Komponenta ListView (resp. instance CMyListView) je opět zapouzdřena v panelové třídě CListViewPanel (nemusela by, protože s obsahem seznamu zatím nic neprovádíme, ale příště budeme).

V obou případech využijeme toho, že celá cesta je vlastně uložená v názvech jednotlivých položek stromu. Celou cestu tedy vytvoříme tak, že budeme odzadu spojovat jednotlivé názvy a prokládat je zpětnými lomítky. A protože máme společnou kořenovou položku (uloženou v m_hRoot), tak ta se stane i zarážkou pro skládání cesty.

// zaciname prazdnym retezcem
wcscpy_s(m_wzPath, MAX_PATH, L"");
// projdeme vsechny az do korene (m_hRoot)
while(hItem != m_hRoot) {
	sItem.hItem		= hItem;
	sItem.mask		= TVIF_HANDLE | TVIF_TEXT;
	sItem.pszText		= wzItem;
	sItem.cchTextMax	= MAX_PATH;

	// do wzItem nacteme nazev polozky
	m_hTreeView.GetItem(&sItem);

	// pridame ji na konec zpetne lomitko
	wcscat_s(wzItem, MAX_PATH, L"\\");
	// a pridame k ni aktualni zbytek cesty (nebot ji skladame odzadu)
	wcscat_s(wzItem, MAX_PATH, m_wzPath);
	// nove vytvorena cesta se stava aktualnim zbytkem cesty
	wcscpy_s(m_wzPath, MAX_PATH, wzItem);

	hItem = m_hTreeView.GetParent(hItem);
}

// po pruchodu cyklem mame v m_wzPath uplnou cestu
// (nebo nic, pokud se jednalo o kořenovou položku)

Takto získanou cestu přepošleme zprávou WM_COMMAND do rodičovského okna (MainView). Správně bychom měli použít zprávu WM_USER, ale ono je to (a nejenom v tomto případě) skoro jedno. V MainView tuto zprávu zachytíme a předáme pointer na řetězec s úplnou cestou do panelu, který obsahuje ListView.

V panelu ListView tento adresář použijeme jako výchozí adresář pro vyhledání souborů a adresářů. K tomuto účelu jsou ve Win32 funkce FindFirstFile, FindNextFile a FindClose. Projdeme všechny položky v daném adresáři, odfiltrujeme speciální adresáře ("." a "..") a rozdělíme ostatní položky na adresáře a soubory. Použití funkcí Find... v našem kódu je následující:

// v pwzFolder je adresar, ktery je vybrany v TreeView

HANDLE			hFind;
wchar_t			wzPath[MAX_PATH];
WIN32_FIND_DATA	sFindData;
int				nCount	= 0;

// vymazeme puvodni obsah ListView (vsechny polozky)
m_hListView.DeleteAllItems();

// hledame vse tj. napr. C:\abc\*
wcscpy_s(wzPath, MAX_PATH, pwzFolder);
wcscat_s(wzPath, MAX_PATH, L"*.*");

// zapocneme hledani - najdeme prvni soubor odpovidajici wzPath
// (v sFindData dostaneme informace o nalezenem souboru)
hFind = FindFirstFile(wzPath, &sFindData);

// hFind je HANDLE hledani, pokud je validni, tak muze hledani probihat
if (hFind != INVALID_HANDLE_VALUE) {
	do {
		// je nalezena polozka adresar?
		if ((sFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) {
			// adresar "." a ".." vynechej
			if  ((wcscmp(sFindData.cFileName, L".") != 0) && (wcscmp(sFindData.cFileName, L"..") != 0))
				// vloz do seznamu polozku (index bitmapy adresare je 0)
				m_hListView.InsertItem(nCount++, sFindData.cFileName, 0);	
		}
		// vloz do seznamu polozku - soubor (index bitmapy souboru je 1)
		else m_hListView.InsertItem(nCount++, sFindData.cFileName, 1);
	// najdi postupne vsechno
	} while(FindNextFile(hFind, &sFindData));
	// a nakonec je potreba hledani uzavrit
	FindClose(hFind);
}	

Tím vyplníme ListView dle obsahu daného adresáře. Jednotlivé položky (soubory i adresáře) jsou napřeskáčku, nejsou setříděné, ale to nám v tuto chvíli nevadí.

A to je pro tentokráte vše. Zdrojový kód aplikace je ke stažení zde. V dalším díle si aplikaci trochu rozšíříme. Jedním z důvodů je to, aby měla lepší a očekávanější funkci (jednoduše řečeno, aby nebyla tak strohá). A druhým důvodem bude ukázka přidání menu, tlačítkové lišty a stavového řádku.

×Odeslání článku na tvůj Kindle

Zadej svůj Kindle e-mail a my ti pošleme článek na tvůj Kindle.
Musíš mít povolený příjem obsahu do svého Kindle z naší e-mailové adresy kindle@programujte.com.

E-mailová adresa (např. novak@kindle.com):

TIP: Pokud chceš dostávat naše články každé ráno do svého Kindle, koukni do sekce Články do Kindle.

2 názory  —  2 nové  
Hlasování bylo ukončeno    
0 hlasů
Google
Autor se věnuje programování za peníze :)

Nové články

Obrázek ke článku Stavebnice umělé inteligence 1

Stavebnice umělé inteligence 1

Článek popisuje první část stavebnice umělé inteligence. Obsahuje lineární a plošnou optimalizaci.  Demo verzi je možné použít pro výuku i zájmovou činnost. Profesionální verze je určena pro vývojáře, kteří chtějí integrovat popsané moduly do svých systémů.

Obrázek ke článku Hybridní inteligentní systémy 2

Hybridní inteligentní systémy 2

V technické praxi využíváme často kombinaci různých disciplín umělé inteligence a klasických výpočtů. Takovým systémům říkáme hybridní systémy. V tomto článku se zmíním o určitém typu hybridního systému, který je užitečný ve velmi složitých výrobních procesech.

Obrázek ke článku Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Jak vést kvalitně tým v IT oboru: Naprogramujte si ty správné manažerské kvality

Vedení týmu v oboru informačních technologií se nijak zvlášť neliší od jiných oborů. Přesto však IT manažeři čelí výzvě v podobě velmi rychlého rozvoje a tím i rostoucími nároky na své lidi. Udržet pozornost, motivaci a efektivitu týmu vyžaduje opravdu pevné manažerské základy a zároveň otevřenost a flexibilitu pro stále nové výzvy.

Obrázek ke článku Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Síla týmů se na home office může vytrácet. Odborníci radí, jak z pracovních omezení vytěžit maximum

Za poslední rok se podoba práce zaměstnanců změnila k nepoznání. Především plošné zavedení home office, které mělo být zpočátku jen dočasným opatřením, je pro mnohé už více než rok každodenní realitou. Co ale dělat, když se při práci z domova ztrácí motivace, zaměstnanci přestávají komunikovat a dříve fungující tým se rozpadá na skupinu solitérů? Odborníci na personalistiku dali dohromady několik rad, jak udržet tým v chodu, i když pracovní podmínky nejsou ideální.

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý