Kisebb kitekintés és más területeken való kalandozás után a mai posztban térjünk vissza a VBA-hoz, amelyet legalább alapszinten mindenkinek célszerű megismernie, aki sokat dolgozik Excelben, hiszen nem kell programozónak lenni ahhoz, hogy mondjuk egy állandóan elvégzett Pivot-táblás copy-paste műveletet automatizálni tudjunk.
Szóval a mai kérdés a következő kis tábla köré összpontosul:
Tegyük fel, hogy kirándultunk egy nagyobbat az országban, felkerestünk néhány települést és az ezeken a helyeken megvásárolt dolgokról vezettünk egy kis Excel-táblázatot, de arra már nem figyeltünk, hogy mivel jelöltük az egyes cellákban, hogy mit vásároltunk, tehát szöveg, betű vagy éppen szám egyaránt található a táblában. A kérés annak meghatározása lenne, hogy a termékek egységárát figyelembe véve, pontosan mennyit költöttünk, ha a cellákba beírt érték nem számít, csak az, hogy írtunk-e be valamit vagy sem - értelemszerűen ha írtunk valamit, azt tekintsük egynek.
A feladvány jópár úton megoldható, de VBA-ban sem tartozik a nehéz feladatok közé, ezért aki még csak az érdeklődő fázisban tart, ő mindenképpen próbálja saját maga megoldani.
Alt + F11 billentyűkombinációval ugorjunk át a VBA-editorba és kezdjünk is neki Szamitas() nevű szubrutinunk összedobásának, amelyet most már biztosan a változók deklarálásával kezdünk. Tekintve, hogy tartományról van szó és ciklusra lesz szükségünk, célszerű a tartománynak is létrehozni egy változót (én ezt most rng néven Range típussal meg is teszem) illetve kell egy másik változó, amelyben a kalkulációnk eredményét tároljuk a ciklus során (én ezt a megszokott i néven Integer típussal alkottam meg). Szóval megvannak a változóink, az rng névre hallgatót fel is tudjuk tölteni táblázatunk paramétereivel.
Hangsúlyozom, egyszerű feladványról van szó, tehát aki érdeklődik VBA-ismeretek iránt, az mindenképpen kapcsolódjon be és saját maga fejezze be a megoldást - a saját verziójában.
Szóval most jön a ciklusunk, amelyet én általában simán szövegként gondolok végig (egy-két írónak volt hasonló módon megírt oktatási anyaga), azaz most minden egyes cellát nézzen meg a ciklusunk a tartományban (For Each cell in rng) és ha a cella (If Cell.Value) nem üres (cell.Value <> "") akkor (Then) ezt a cellát tegye az aktív cellánkká (cell.Activate). Majd ezután a fentebb deklarált i változó legyen egyenlő a korábban benne lévő értékkel, hozzáadva a most aktív cellánk oszlopának második sorában szereplő értéket (i = i + Cells(2, ActiveCell.Column) - persze itt is simán elkerülhetjük a konstans sorszám használatát, ha akarjuk. Ezután zárjuk le az If feltételvizsgálatot és ugorjunk a következő cellára a tartományban.
Innen már csak az van hátra, hogy kiírassuk az eredményt a képernyőre egy MsgBox segítségével, illetve kiürítsük i változónkat és bezárjuk a szubrutint:
És ezután már tuningolhatjuk, ahogy akarjuk, innen könnyen be tudjuk állítani akár azt is, hogy ha szám van, akkor ne csak egyszer számolja az egységárat, hanem a számmal szorozza meg, de akár kitölthetjük az üres cellákat is, gombhoz is hozzárendelhetjük, de akárhogy is teszünk, a fentinek meg is van szépen az eredménye:

Szövegként a kód:
Sub Szamitas()
Dim rng As Range
Dim i As Integer
Set rng = Range("B3:D8")
For Each cell In rng
If cell.Value <> "" Then
cell.Activate
i = i + Cells(2, ActiveCell.Column)
End If
Next
MsgBox i
i = 0
End Sub

És kész is vagyunk:
Ezt és még egyéb, taskokhoz kapcsolódó beállítást is meg tudunk tenni, ha az Outlook Optionsben a Tasks menüre kattintunk.
Színeket, default reminder időpontot tudunk babrálgatni itt, sőt még status riportot is kérhetünk, ha megoldunk egy hozzánk rendelt feladatot.
Ilyenkor legegyszerűbben úgy tudjuk mégis indulásra késztetni levelezőnket, ha a Start menüből közvetlenül is indítható Command prompt segítségével a /resetnavpane paraméterrel indítjuk az Outlookot:

Fogjuk ezt a fájlt és nevezzük át a kiterjesztését .zip-re. Ha ezt megpróbáljuk megtenni, kapunk egy figyelmeztetést, hogy esetleg használhatatlanná válik így a fájlunk, de ezen lépjünk túl egyszerűen:
Ezután csomagoljuk ki ezt a tömörített állományt és már látjuk is, hogy miből áll a .docx fájlunk valójában:
Ha itt a könyvtárstruktúrában belépünk a word almappába, akkor a következő kép tárul elénk:
A legfontosabbak közül az első, amiket a mostani kérdéskör megválaszolásához ismernünk kell, az embeddings mappa, ugyanis itt találjuk meg a WORD fájlunkba beágyazott dokumentumokat:
A media mappában találjuk a beszúrt képeket, videókat, zenéket stb.:
Magáról a fájlban lévő szövegünkről pedig a document.xml fájl fog segíteni nekünk kideríteni dolgokat:
Ha ezt megnyitjuk mondjuk Notepadben, akkor eléggé kaotikus formában, de meg tudjuk nézni, hogy mit írtunk anno a dokumentumba:
A jobb olvasási élmény érdekében természetesen használhatunk XML editorokat is, amelyek segítenek jóval átláthatóbbá tenni ezt az xml fájlt. A többi könyvtár alapvetően nem létfontosságú számunkra, úgyhogy csak röviden érinteném őket:
Mielőtt rátérünk a következő lépésre, célszerű a Ribbonunk Drawing Tools - Format füle alatt megnézni, hogy milyen méretű az első körünk, ugyanis a másodikat is ilyen méretűre kell majd elkészítenünk.
Általánosságban tapasztalatom szerint a Harvey Balls színei a szürke és fekete különféle árnyalatai, így színezzük át mindkét körünket a következők szerint:
- A második körünk legyen jóval erősebb szürke kitöltéssel, de körvonalak nélkül. Ezt a körre kattintva tudjuk elérni a fentebb már említett Shape Fill és Shape Outline funkciók segítségével.
Ezután fogjuk meg a körszeletünket és szépen illesszük bele az első körünkbe. Ha ez megvan, akkor a két kört együtt kijelölve és jobb gombbal kattintva elérjük a Group funkciót, amivel egyesíteni tudjuk a két kört és máris elkészült az első gömbünk:
Mit kell most tennünk? Készítsünk ebből a gömbből még párat legalább:
Ha ez megvan, akkor bármelyik kis labdánkban ha belekattintunk a körszeletbe, akkor tudjuk méretezni a szeletet a kis sárga nyilak segítségével és ezzel bármikor olyan állást tudunk beállítani, amilyet akarunk:
Röviden tehát ennyi lenne, máris elkészültek a "Harvey-labdák", prezentálhatjuk a projektjeinket vagy amit csak akarunk.
Ezt valamennyire megkönnyíthetjük azzal, ha a kijelölésünk elején lenyomjuk a SHIFT+F8 kombinációt, amellyel élesítjük az ADD TO SELECTION parancsot és innentől kezdve a CTRL-t nem is kell nyomnunk, csak kattintgatnunk a különböző celláinkra, tartományainkra. Ezt a SHIFT+F8 újbóli lenyomásával tudjuk kikapcsolni.
Azt meg már valószínűleg szintén sokan ismerik, hogy ha csak azon celláinkat akarjuk kijelölni, amelyek tartalmaznak értéket, akkor egyszerűen a Ribbonunk Home füle alatt található Find&Select utasításcsoportból válasszuk ki a Go To Special parancsot és az itteni lehetőségekből mondjuk válasszuk ki az összes konstans számértéket, mint kijelölendő cellákat:
És ha még mindig szeretnénk ragaszkodni a billentyűkombinációkhoz, akkor a kijelölt különböző celláink szummáját is meg tudjuk adni mindenféle kattintgatás nélkül, hiszen elég csak azon cellákat a fenti SHIFT+F8 és F8 módszerrel kijelölni, amelyek felett összegezni kívánt számaink vannak:
Ezután pedig elég egy ALT+= kombinációt nyomnunk, hogy megszülessenek a végeredményeink minden kis táblánál:
Ahogy fentebb szó volt róla, hogy az F8 segítségével tudjuk bekapcsolni az EXTEND SELECTIOn nevű parancsot, de nem ez az egyetlen ilyen, kijelölést segítő parancscsoport, az END lenyomásával például az END metódust tudjuk bekapcsolni, amellyel nem-üres celláink között tudunk ugrálni END majd SHIFT és nyilak használatával.
Ennek a problémának a legegyszerűbb és leggyakrabban használt kiküszöbölési módja a RAND függvény bevetése és egy segédoszlop alkalmazása, hiszen a RAND 0 és 1 között fog nekünk egy véletlen számot generálni, amelynél a duplikáció kialakulása szinte lehetetlen. Ha valakit érdekel ez a megoldási forma, az jelezze és akkor kitérek rá, de most inkább egy olyan irányt vázolok fel, amely lehetővé teszi, hogy egyetlen tömbfüggvény segítségével, segédoszlopok nélkül eliminálhassuk a duplikációk lehetőségét RANDBETWEEN esetén.
Ahogy mindig, most is hangsúlyozni kell, hogy ez csak egy a lehetséges megoldások közül, szóval továbbra is nyitott vagyok más javaslatokra/ötletekre.
FSO a fentebb már említett FileSystemObject objektum, amelyet azért hozunk mindjárt létre, hogy hozzáférjünk a fájlrendszerhez, a Folder és File változók értelemszerűen könyvtár és fájl objektumok tárolására szolgálnak majd, i változónkra pedig a ciklushoz lesz majd szükségünk.
Ezzel konkrétan már a folderben vagyunk, most jön a ciklusunk, amely egyesével végigmegy a folderben lévő fájlokon és azok nevét egymást követő cellákba írja be.
Vegyük észre, hogy File objektumunknak minden tulajdonságához hozzáférünk, így a nevéhez, elérési útjához is, de ezen analógia mentén férünk hozzá a létrehozási dátumához, utolsó megnyitási időpontjához vagy akár méretéhez is.
Persze ez nem egy mindennap felmerülő igény, az tény, de ettől függetlenül mi van, ha régi történelmi személyiségek pontos életkorát szeretnénk napban megadni születésük és haláluk időpontja alapján? Vagy teljesen más okból lenne erre szükségünk?
Alapból itt most fejből is meg tudjuk mondani az eredményt, de a cél az, hogy bármely dátum és bármennyi dátum esetén működjön ez a logika. Összesen három függvényt fogunk felhasználni a különbség meghatározásához, a fentebb már említett DATEDIF formula mellett egy LEN és egy RIGHT is kelleni fog majd - plusz az, hogy a dátumok egységes formátumban legyenek (ezen függvényekről hosszabban nem írok már, elég sok posztban bemutattam őket, úgyhogy valószínűleg minden Olvasó előtt ismertek).
Majd újra hozzátesszük az évet, de nem ugyanúgy, hanem a dátumaink tartományát figyelembe véve hozzáadunk még több száz évet:
Ezt teljesen ugyanezzel a módszerrel megismételjük a másik dátumra is:
Ez biztosan nem a legszebb megoldás, de elvileg olyan makró nélküli eredmény, amire megbízhatóan támaszkodhatunk - ennek ellenére további ötleteket, javaslatokat szívesen fogadok.
Alapvetően feltételezzük, hogy a képek valamilyen formában szekvenciálisan sorakoznak a könyvtárunkban, másrészt azt is feltételezzük, hogy egyetlen specifikus könyvtárról van szó, de ahogy mindjárt látni fogjuk, ezek nem kizáró feltételek, a feladat a lenti minta mentén bármilyen formában megoldható.
Ezzel az is érthetővé vált, hogy honnan tölthetjük be nagyon egyszerűen képeink listáját a "Kép neve" oszlopba, ahonnan pedig szintén több utunk van a linkjeink gyors kitöltésére.
Mi történik, ha mondjuk Január oszlopban mindkét sort kijelölve egyesítem a cellákat a Ribbon Home füle alatt található Alignment szekció Merge & Center parancsával?
Ez az elvárt viselkedés, azt kaptuk, amit szerettünk volna, ha szummában összeadjuk a kiadásainkat, akkor a kalkuláció is helyes értéket mutat. Mi történik azonban, ha a Ribbonunk Home füle alatt található Format Painter segítségével ezt a Merged Cell formátumot átmásoljuk Februártól kezdve a többi hónapra is?
Még mindig azt kaptuk, amit vártunk - vagy mégsem? Amit látunk, az elvileg az, amit szerettünk volna elérni, de ha például összeadjuk Április-Május-Június hónapok értékeit, láthatjuk, hogy 3000 helyett 4500 lesz az eredmény:
A lenti állapotjelzőn is 4500-at mutat az automatikus kalkuláció, ahogy a SUM függvény is ezt az eredményt adja, de ha egyesével adjuk össze a cellákat, akkor azt a 3000-es értéket kapjuk, amire vártunk. Tehát a konkluzió az, hogy Format Painter segítségével semmiképpen ne másoljunk cellaegyesítést, mert az csak a formátumot viszi, a háttérben ugyanúgy ott tárolja annak a cellának az értékét, amelyről azt hisszük, hogy elveszett.
Mi a furcsa benne? Ha december 27-én kezdődött az 53. hét, akkor január elsején miért első hétről beszélünk, annak még nem az 53. hétnek kellene lennie? A megoldást a Microsoft hivatalos leírása vagy egyáltalán, a formula második paraméterének segítsége adja meg:
Mik a lehetőségeink? Az Excel 1,2,11,12,13,13,15,16,17 és 21 return_type lehetőségét adja meg nekünk, System 1 és System 2 (bár ez csak a 21-es return type-nél létezik) opcióval, ahogy láthatjuk is a legördülő kis segítségben. Ez lenne ezen opciók leírása:
Maga az első két oszlop elég egyértelmű értékeket tartalmaz, viszont a harmadik, a System talán magyarázatra szorul. A Microsoft leírása szerint System 1 az a hétszámozási rendszer, amelyben az a hét az év első hete, amelyben január elseje megtalálható - ergó a példámban ezért vált 53 után egyre az Excel. A System 2 pedig az ISO8601:2000-es hétszámozási standardnek megfelelő számozás, ahol az év első csütörtökjét tartalmazó hét számít az első hétnek. Példánkat eszerint 21-es return typera átírva:
Ezzel a magyarázatot meg is leltük a furcsaságra, de azért a poszt végén említsük meg, hogy valójában a világon nem csak ez a kettő hétszámozási rendszer létezik, hanem van még két másik is. System 1 és System 2 opciót már tisztáztuk, de System 1-nek két változata van, az egyikben január elsején kezdődik az első hét és a második a következő hétfőn folytatódik, a másikban január elsején kezdődik szintén az első hét, de a második már vasárnap folytatódik. Ezen a három verzión kívül van a legegyszerűbb, amikor január elsején elindul az első hét és január 8-án folytatódik a második, napoktól függetlenül.