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

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       19 044×

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.

Reklama
Reklama

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 Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Delphi 10.1.2 (Berlin Update 2) – na co se můžeme těšit

Touto roční dobou, kdy je zem pokrytá barevným listím a prsty křehnou v mrazivých ránech, se obvykle těšíme na zbrusu novou verzi RAD Studia. Letos si však ale budeme muset počkat na Godzillu a Linux až do jara. Vezměme tedy za vděk alespoň updatem 2 a jelikož dle vyjádření pánů z Embarcadero se budou nové věci objevovat průběžně, pojďme se na to tedy podívat.

Reklama
Reklama
Obrázek ke článku Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Konference: Moderní datová centra pro byznys dneška se koná už 24. 11.

Stále rostoucí zájem o cloudové služby i maximální důraz na pružnost, spolehlivost a bezpečnost IT vedou k výrazným inovacím v datových centrech. V infrastruktuře datových center hraje stále významnější roli software a stále častěji se lze setkat s hybridními přístupy k jejich budování i provozu.

Obrázek ke článku Konference: Mobilní technologie mají velký potenciál pro byznys

Konference: Mobilní technologie mají velký potenciál pro byznys

Firmy by se podle analytiků společnosti Gartner měly  rychle přizpůsobit skutečnosti, že mobilní technologie už zdaleka nejsou horkou novinkou, ale standardní součástí byznysu. I přesto - nebo možná právě proto - tu nabízejí velký potenciál. Kde tedy jsou ty největší příležitosti? I tomu se bude věnovat již čtvrtý ročník úspěšné konference Mobilní řešení pro business.

Obrázek ke článku Hackerský kongres přiveze v září do Prahy špičky světové kryptoanarchie

Hackerský kongres přiveze v září do Prahy špičky světové kryptoanarchie

Hackerský kongres HCPP16 pořádá od 30. září do 2. října nezisková organizace Paralelní Polis již potřetí, a to ve stejnojmenném bitcoinovém prostoru v pražských Holešovicích. Letos přiveze na třídenní konferenci přes 40 většinou zahraničních speakerů – lídrů z oblastí technologií, decentralizované ekonomiky, politických umění a aktivismu. Náměty jejich přednášek budou také hacking, kryptoměny, věda, svoboda nebo kryptoanarchie.

loadingtransparent (function() { var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true; po.src = 'https://apis.google.com/js/plusone.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s); })();
Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032016 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý