Vsi nabori znakov v vašem računalniku

V dneh, ko “se ženijo ptički” in ko praznujemo uvoženi praznik zaljubljencev, se uporabniki spomnite, da bi lahko soljudem poslali kakšno misel, verz… nekaj lepega pač.

Seveda pa ne želite, da bi to izpadlo kar tako malo mimo, temveč bi želeli to izpisati s kakšno lepo pisavo in na računalniku imate 200 pisav, pa sploh ne veste:

  1. Kako izgledajo
  2. Ali znajo natisniti Č, Š in Ž

Continue reading Vsi nabori znakov v vašem računalniku

Ščitenje resursov v VBA končni primer

Za konec tega kratkega sprehoda skozi ščitenje resursov v okolju VBA (prvi del, drugi del in tretji del), si poglejmo še zaključni primer, torej ščitenje dostopa do datoteke.

Prikazal bom preprost razred, ki hrani številko (VBA do datotek prihaja preko številk, ki jih dodeli posamezni datoteki) in v kolikor je številka postavljena, kar pomeni, da je bila datoteka odprta, jo ob uničenju objekta zapre in uniči številko.

Z uporabo takšnega razreda oz. spremenljivke tega razreda lahko zanesemo na dejstvo, da bo vsaka datoteka, ki smo jo odprli tudi zaprta.

Razred za zaščito dostopa datotek

Option Explicit

' tu hranimo ID datoteke
Private idDatoteke

Private Sub Class_Initialize()
  ' na začetku ID-ja datoteke ne poznamo,
  ' saj datoteke še nismo odprli
  idDatoteke = -1
End Sub

Private Sub Class_Terminate()
  ' v kolikor smo datoteko odprli
  ' jo tudi zapremo
  If (idDatoteke > 0) Then
    Close #idDatoteke
  End If
End Sub

' s to funkcijo datoteko odpremo in tudi izvemo ali
' nam je odpiranje uspelo ali ne
Public Function Odpri(imeDatoteke As String, _
                      vhod As Boolean) As Boolean
  ' predpostavimo, da nam odpiranje ne bo usplo
  Odpri = False

  ' pridobimo novo število
  idDatoteke = FreeFile

  ' v primeru napake odregiramo
  On Error GoTo napaka

  ' ali želimo datoteko pisati ali brati
  If (vhod) Then
    Open imeDatoteke For Input As idDatoteke
  Else
    Open imeDatoteke For Output As idDatoteke
  End If

  ' če smo prišli do sem, je odpiranje uspelo
  Odpri = True

  ' končamo
  Exit Function

napaka:
  ' če smo tu, pomeni, da odpiranje ni uspelo
  idDatoteke = -1
End Function

' samo okrajšava gornje funkcije
Public Function OdpriZaBranje(imeDatoteke As String) _
                              As Boolean
  OdpriZaBranje = Me.Odpri(imeDatoteke, True)
End Function

' samo okrajšava gornje funkcije
Public Function OdpriZaPisanje(imeDatoteke As String) _
                              As Boolean
  OdpriZaPisanje = Me.Odpri(imeDatoteke, False)
End Function

' lastnost, ki nam vrne identifikacijsko
' številko datoteke, preko katere se bomo
' nanjo sklicevali
Public Property Get id()
  id = idDatoteke
End Property

Primer uporabe

Option Explicit

Sub beriDatoteko(ime As String)
  ' ustvarimo spremenljivko
  Dim dat As New clsDatoteka

  ' v kolikor datoteke ne moremo odpreti končamo
  If (Not dat.OdpriZaBranje(ime)) Then Exit Sub

  ' spremenljivka, kamor bomo prebrali vsebino
  Dim vrstica

  ' vrtimo se dokler ne pridemo na konec datoteke
  Do While Not EOF(dat.id)
    Line Input #1, vrstica ' preveremo vsebino
    MsgBox vrstica ' in jo izpišemo
  Loop

  ' datoteka se bo zaprla sama
End Sub

Sub pisiDatoteko(ime As String)
  ' ustvarimo spremenljivko
  Dim dat As New clsDatoteka

  ' v kolikor datoteke ne moremo odpreti končamo
  If (Not dat.OdpriZaPisanje(ime)) Then Exit Sub

  ' pišemo
  Print #dat.id, "Prva vrstica v datoteki"
  Print #dat.id, "Druga vrstica v datoteki"
  Print #dat.id, "Tretja vrstica v datoteki"
End Sub

Sub Test()
  Dim ime As String

  ime = "d:\test.out"

  ' to ne bo uspelo
  beriDatoteko ime

  ' če ste ustrezno ureili ime bo to uspelo
  pisiDatoteko ime

  ' če je uspelo pisanje, bo tudi branje
  beriDatoteko ime
End Sub

Ščitenje resursov v VBA III

V prejšnjem prispevku sem prikazal kako idejo o ščitenju realizirati v praksi, danes pa podajam še prvi konkretni primer, ki bo prikazal resnično uporabnost.

Hitrejše izvajanje makrov

Za hitrejše izvajanje makrov v Excelu je priporočljivo ustaviti preračunavanje, saj sicer Excel ob vsaki spremembi, ki bi vplivala na druge celice vse tiste celice preračunava in če to ponovimo 1000x se preračunavanje izvede 1000x!

Dobro je tudi preprečiti nepotrebno osveževanje ekrana, saj sicer uporabniku zaslon nenehno utripa in okna ter podatki skačejo sem ter tja.

Nenazadnje pa je dobro (če jih ne potrebujemo) izključiti tudi odzive na dogodke.

Vse skupaj lahko torej strnemo v sledečo kodo:

With Application
    .Calculation = xlCalculationManual  ' preprečimo preračunavanje
    .ScreenUpdating = False    ' ne osvežujemo ekrana
    .EnableEvents = False  ' ugasnemo dogodke
End With

Seveda pa je potrebno ob koncu makra vse to postaviti nazaj:

Sub VelikMakro()
  ' zamrznemo
  With Application
    .Calculation = xlCalculationManual
    .ScreenUpdating = False
    .EnableEvents = False
  End With

  ' tu vmes je veliko kode

  ' vzpostavimo nazaj
  With Application
    .Calculation = xlCalculationAutomatic
    .ScreenUpdating = True
    .EnableEvents = True
  End With
End Sub

Test

A da bo stvar bolj zanimiva, izvedimo majhen test. Poglejmo kako dolgo se bo izvajal sledeč makro:

Sub TestnaFunkcija()
  Range("A1").Formula = "=cos(A2)*tan(A2)/sin(a3)"
  Range("A2").Formula = "=1/A3"

  Dim i As Long
  For i = 1 To 100000
    Range("A3") = i
  Next
End Sub

Sub KlicTestneFunkcije()
  TestnaFunkcija
End Sub

Sub IzvediTest()
  Dim cas: cas = Now
    KlicTestneFunkcije
  MsgBox "Trajanje (v sec): "; ((Now - cas) * 24 * 60 * 60)
End Sub

Če izvedem makro IzvediTest, se na testnem računalniku izvaja 19 sekund.

Objekt, ki bo vzpostavil stanje

Napišimo torej objekt, ki bo ob inicializaciji »zamrznil« Excel in ga ob koncu makra vzpostavil nazaj:

Option Explicit

Private Sub Class_Initialize()
  With Application
    .Calculation = xlCalculationManual
    .ScreenUpdating = False
    .EnableEvents = False
  End With
End Sub

Private Sub Class_Terminate()
  With Application
    .Calculation = xlCalculationAutomatic
    .ScreenUpdating = True
    .EnableEvents = True
  End With
End Sub

Poimenujmo ga clsZamrzni.

Nov test

Popravimo sedaj funkcijo tako, da uporabimo pridobljeno znanje. Uporabimo torej objekt. Popravimo testni klic:

Sub KlicTestneFunkcije()
  Dim zamrzni As clsZamrzni

  Set zamrzni = New clsZamrzni
  TestnaFunkcija
End Sub

Če sedaj na mojem testnem računalniku izvedem funkcijo IzvediTest, se slednja izvede v manj kot sekundi… 😉

Ščitenje resursov v VBA II

V prejšnjem blogu sem omenil, da nam pri ščitenju resursov lahko pomagajo objekti in zdaj je čas, da si ogledamo kako.

Napišimo torej skrajno preprost objekt, ki ima samo konstruktor, destruktor ter inicializacijsko funkcijo, ki mu postavi ime, da mu lažje sledimo (poimenujmo ga objSciti):

Option Explicit

Private ime As String

Private Sub Class_Initialize()
  Debug.Print "NOV "
End Sub

Private Sub Class_Terminate()
  Debug.Print "BRIŠEM "; ime
End Sub

Public Sub init(aime As String)
  ime = aime
  Debug.Print "  POSTAVIM "; ime
End Sub

Uporabimo ga v preprosti proceduri:
Sub Proc()
  Dim a As New objSciti
  a.init "prvi"
End Sub

Če proceduro izvedemo, dobimo sledeč rezultat:
NOV
  POSTAVIM prvi
BRIŠEM prvi

Če funkcijo pogledamo, nam je jasno, da izpis niza ‘NOV’ povzroči prva vrstica kode, izpis niza ‘POSTAVIM prvi’ povzroči druga vrstica kode… Kaj pa izpis tretjega niza? Tretji niz pa izpiše destruktor, ki ga VBA pokliče sam ob zaključku procedure.

Malce nižje bomo sicer spoznali tudi, da pravzaprav prvi dve vrstici izpiše funkcija ‘init’, a to zdajle niti ni pomembno.

Kaj če funkcijo preoblikujemo tako, da sprejme ime in jo potem kličemo iz neke druge funkcije? Omenjena ideja je predstavljena spodaj:

Sub Proc2(ime As String)
  Dim a As New objSciti
  a.init ime
End Sub

Sub TestProc2()
  Dim i
  For i = 1 To 20
    Proc2 "spr"; i
  Next
End Sub

Če izvedemo testno proceduro ‘TestProc2‘, dobimo sledeč rezultat
NOV
  POSTAVIM spr1
BRIŠEM spr1
NOV
  POSTAVIM spr2
BRIŠEM spr2
… in tako dalje …
NOV
  POSTAVIM spr20
BRIŠEM spr20

To je torej lep dokaz, da se objekt ob zaključku funkcije avtomatično uniči in nam za to ni potrebno skrbeti. Iz rezultata je namreč vidno, da se funkcija izvede 20x in vsakič kliče proceduro, ki objekt ustvari in ga tudi uniči. In to preprosto dejstvo nam lahko reši neprespane noči ob iskanju hrošča 🙂

Konkreten primer uporabe vam bom prikazal naslednjič, za danes pa podajam samo še dve zelo pomembni opozorili.

Opozorilo1

V kolikor ste navajeni klasičnih programskih jezikov, kot sta recimo C in C++ lahko pridete na idejo, da vso pomembno programsko kodo postavite v konstruktor in ustrezno čiščenje v destruktor…

TODA, če v VBA-ju ne uporabite vsaj ene javne funkcije/ metede/ lastnosti objekta, ga VBA izvajalno okolje ne bo naredilo. Torej VBA takšnega objekta sploh nikoli ne bo ustvaril.

Če prejšnjo funkcijo preoblikujete takole:

Sub Proc2(ime As String)
  Dim a As New objSciti
' objekta nikoli ne uporabimo
' zato ga VBA sploh ne bo ustvaril!
End Sub

Program ne bo izpisal ničesar!

Opozorilo2

V kolikor ste navajeni klasičnih programskih jezikov, kot sta recimo C in C++ lahko pričakujete, da bo VBA uničil objekt ob koncu programskega bloka. A to v primeeru VBA-ja ne drži. VBA uničuje objekte samo na koncu funkcij /procedur.

Primer je lepo viden, če v testni proceduri ne kličemo procedure, temveč objekt direktno ustvarimo:

Sub TestProc3()
  Dim i
  For i = 1 To 20
    ' VBA bo objekt ustvaril samo 1x !
    Dim a As New objSciti

    ' lastnosti bo spreminjal ISTEMU objektu
    a.init "spr"; i
  Next  ' objekt a ne bo uničen tukaj

  ' temveč bo uničen šele tukaj
End Sub

Sedaj pa je izpis povsem drugačen:
NOV
  POSTAVIM spr1
  POSTAVIM spr2
… in tako dalje …
  POSTAVIM spr20
BRIŠEM spr20

Na primeru je lepo vidno, da VBA ustvari en sam objekt. Bodite pozorni na to!

Ščitenje resursov v VBA

Kot klasični C/C++ programer sem obseden od ščitenja resursov!

Da najprej razčistimo, kaj resursi sploh so. V računalništvu so resursi pravzaprav vse kar računalnik uporablja, kot programerja pa nas najbolj zanimajo pomnilnik, datoteke in zunanje naprave.

Pri ščitenju resursov je ideja v tem, da vedno zagotavljate dvoje:

  1. Če resurs zasežete ga tudi sprostite.
  2. Vse resurse sproščajte čim prej. Če jih ne potrebujete več jih sprostite!

Primer je recimo odpiranje datoteke. Program odpre datoteko, piše vanjo in jo na koncu zapre… Toda, kaj če jo pozabi zapreti? Kaj če se v programski kodi zgodi napaka in se datoteka ne zapre? To je težava in nanjo je potrebno biti pozoren.

V Excelu pa se večkrat srečamo s povsem enakovrednim problemom preračunavanja. Da bi makro v Excelu tekel hitreje v večini primerov na začetku postavimo preračunavanje na ročno – izvedemo makro in postavimo preračunavanje nazaj na avtomatično

A kaj če pozabimo oz. se zgodi napaka 🙁 ? Uporabnik ostane z delovnim zvezkom, ki se ročno preračunava in seveda je zmeden…!

Sub Delujoce()
  Dim oldCalculation
  oldCalculation = Application.Calculation
  Application.Calculation = xlCalculationManual

  ' tu vmes je veliko vrstic kode…
  Dim i As Long
  For i = 1 To 10000
    Debug.Print i
  Next

  Application.Calculation = oldCalculation
End Sub

Toda čez nekaj časa kodo popravljamo in zapišemo nekaj takšnega…?
Sub NEDelujoce()
  Dim oldCalculation
  oldCalculation = Application.Calculation
  Application.Calculation = xlCalculationManual

  ' tu vmes je veliko vrstic kode…
  Dim i As Long
  For i = 1 To 10000
    Debug.Print i

    ' PROBLEM!!!
    If (i Mod 123 = 12) Then Exit Sub
  Next

  Application.Calculation = oldCalculation
End Sub

Sedaj se bo v nekem primeru funkcija zaključila prej in Excel ostane v ročnem preračunu! Napaka!

Rešitev

Rešitev ponuja objektno programiranje oz ideja konstruktorjev ~ destruktorjev. Konstruktor je funkcija, ki se izvede ob ustvarjanju objekta, destruktor pa se zgodi ob uničenju objekta. Lepota obeh funkcij je v tem, da sta privzeti in ju ni potrebno eksplicitno klicati.

Dobro; konstruktor pokličemo vedno ko objekt ustvarimo – to kot programerji zagotovo naredimo. A objekt se ob koncu ob koncu funkcije uniči avtomatično. No natančneje rečeno,  se objekt uniči ob koncu njegove življenske dobe, ki je odvisna od tega,kje ga ustvarimo… A to zdajle ni tako pomembno.

In to je ključ do uspeha. V konstruktorju zasežemo resurse, ob destruktorju pa se slednji avtomatično sprostijo in vse je lepo in prav.

Kako to izvesti v VBA-ju pa pokažem naslednjič.

Add-in Express razvoj dodatka – dodatek je izdelan

V prejšnjih blogih sem prikazal:

In sedaj je čas, da namestitveno datoteko tudi zaženemo :)…

Po namestitvi, ki je klasična Windows instalacija, se na računalniku ne zgodi nič posebnega… dokler ne zaženemo katerega izmed Office programov. Naš dodatek smo razvili za Word, Excel in PowerPoint.

Če na mojem razvojem računalniku instaliram omenjen dodatek in zaženem MS Office 2007, dobim sledečo sliko, kjer se lepo vidijo trakovi z našim gumbom

Če zaženem katerega izmed programov MS Office 2010 (ki so celo v angleški različici) dobim trak z našim gumbom

In če isto datoteko instaliram na računalniku, kjer tečejo Okna XP in MS Office 2003, dobim novo Office 2003 orodno vrstico

In to je bistvo vsega… Razvijemo en dodatek in stvar magično teče na vseh-mogočih in nemogočih verzijah MS Pisarne… Božansko 🙂 🙂 …

Moje osebno mnenje o Add-in Express

Osebno menim, da je Add-in Express čudovit programski paket, ki neizmerno olajša razvoj Office dodatkov, predvsem se njegova moč pokaže, če morate razvijati dodatke za različne verzije MS Pisarne – v tem primeru gre za nepogrešljiv dodatek. Trenutno je njegova edina slaba stran dejstvo, da ne morete (vsaj ne dokaj preprosto) izdelati slovenske namestitvene datoteke – škoda(!) – upam da se bo to kmalu (tudi z mojo pomočjo) izboljšalo!

Add-in Express razvoj dodatka – Izdelava namestitvenega programa

Ko program izdelamo, ga je potrebno še zapakirati tako, da ga lahko uporabniki uporabijo. Tu pa se lahko stvari zakomplicirajo, saj je v primeru razvoja Office dodatkov potrebno pisati po registru in na različnih mestih dodajati in popravljati ključe…

Zato je najbolje, da izdelavo namestitvenega programa prepustimo kar Add-in Expressu. Ob tem imamo Slovenci trenutno problem, saj Add-in Expres ne zna izdelati poslovenjenega namestitvenega programa a upam, da se bomo lahko zmenili in uredili tudi to.

Iz priročnega menija našega projekta izberemo torej opcijo za izdelavo namestitvenega programa

in zažene se čarovnik, kjer v prvem koraku določimo osnovne elemente programa,

V drugem koraku pa ime namestitvene datoteke in lokalizacijo. Kot omenjeno slovenskega jezika zaenkrat ni možno izbrati 🙁 …

Ko čarovnik izvede svojo čarovnijo se nam v razvojnem okolju pojavi nov projekt.

Ko projekt prevedemo pa na disku – pričakovano – dobimo instalacijsko datoteko našega dodatka.

Add-in Express razvoj dodatka – Razvoj

Ko Add-in projekt pripravimo tako kot je opisano v prejšnjem blogu, nas pričaka pripravljen projekt in lahko pričnemo s pisanjem programske kode. Komunikacija z Office programi bo potekala preko modula AddinModule.cs, v katerem bomo Office okolje zvezali z našim programom.


V programskem delu modula nas čakajo že pripravljeni objekti za dostop do vseh programov, ki smo si jih izbrali pri pripravi projekta.

Če pa odpremo AddinModule.cs v vpoglednem načinu (design mode), pa se nam odpre prazna delovna površina na katero lahko dodajamo različne Office elemente, preko katerih bomo komunicirali s programi.

V testnem primeru se bomo z Office programi pogovarjali preko gumba na traku (Office 2007 in 2010) tre preko gumba na orodni vrstici (Office 2000, XP in 2003). Odziv na sam dogodek pa bo v obeh primerih enak.

Zgradimo torej orodno vrstico z gumbom za Office 2000, XP in 2003.

Ter ustrezen trak za Office 2007 in Office 2010.

Ker sta podpisa funkcij za odziv na klik gumba na traku in v orodni vrstici različna, se moramo odzvati na oba, a v njiju lahko kličemo isto funkcijo, ki bo pač naredila, tisto, kar želimo:

private void doClick()
{
System.Windows.Forms.MessageBox.Show("Pozdrav iz Add-in Express");
}

private void RibbonBtn_Click(object sender, AddinExpress.MSO.IRibbonControl control, bool pressed)
{
doClick();
}

private void CommandBarBtn_click(object sender)
{
doClick();
}

Ko projekt prevedemo, ga moramo obvezno tudi registrirati, kar lahko storimo kar znotraj VS.

Ker dodatek sam zase seveda ne more teči, moramo VS-u pred zagonom dodatka povedati, kateri program naj zažene ob testu dodatka. Slednje seveda določimo na lastnostih projekta, kjer definiramo program za zagon, kot je prikazano na spodnji sliki.

Sam sem izbral Excel in kar na razvojnem računalniku uporabljam Excel 2007 sem v traku dobil nov zavihek z gumbom.

Če gumb kliknem dobim pričakovan odziv.

Add-in Express razvoj dodatka – Priprava projekta

V prejšnjem blogu sem opisal programski paket Add-in Express, v tem blogu pa bom prikazal, kako izgleda razvoj takšnega MS Office dodatka.

Skozi pripravo projekta nas vodi čarovnik, ki pa ga moramo najprej zagnati. Ob ustvarjanju novega projekta v VS izberemo opcijo Other Project Types / Extensibility, pod katero se skrivajo vsi možni Add-in Express dodatki. Na vrhu določimo še .NET okolje, ki je lahko 2.0, 3.0, 3.5 ali 4.0. Osebno izbiram 2.0, saj imajo tako uporabniki najmanj problemov. .NET 2.0 je namreč bolj ali manj prisoten že na vseh Windows računalnikih.

V naslednjem koraku se odločimo za programski jezik ter verzijo Office produktov. Lahko izberemo specifično verzijo in s tem tudi vse njene prednosti/slabosti, lahko pa izberemo tki. neutralen projekt, s pomočjo katere lahko razvijamo dodatek, ki bo tekel na vseh verzijah Office-a.

V naslednjem koraku izberemo konkretne Office produkte, in kot rečeno so na voljo vsi. V mojem primeru sem izbral Excel, Word in PowerPoint.

In to je to; projekt je pripravljen

Add-in Express prvič

V dosedanjih blogih s tematiko programiranja za Office (Razvoj dodatkov za Excel in Razvoj Excelovih dodatkov v .NET okolju) sem se dotaknil manjše primerjave med različnimi možnostmi razvoja dodatkov v Excelu.

Danes pa se bom malce bolj posvetil programski opremi Add-in Express, ki je namenjena celostnemu razvoju programskih dodatkov za Office v okolju .NET.

Dosedaj sem ta produkt primerjal samo v povezavi z razvojem v Excelu, saj je to primarno področje delovanja mojega podjetja, a sem bil v tem primeru do njega krivičen. V tem blogu pa ga bom poskušal predstaviti malce bolj obširno.

Kaj je Add-in Express?

Add-in Expres je dodatek razvojnemu okolju Visual Studio, s pomočjo katerega poenostavimo razvoj dodatkov za Office. Prednost njegova prednost pred konkurenti pa je predvsem v fleksibilnosti in hitrosti razvoja

Razvojno okolje

Add-in Expres lahko uporabljate v vseh generacijah Visual Studia: VS 2005, VS 2008 in VS 2010. In tudi v vseh različicah, torej tako v VS Express, VS Professional, VS Ultimate in VS Team System.

Podprte različice Office-a

Podprte so vse različice Office-a od 2000 dalje; torej Office 2000, Office XP, Office 2003, Office 2007 in Office 2010.

Podprti programi

Podprti so vsi programi MS pisarne; torej Excel, Word, PowerPoint, Outlook, Visio…

Največja prednost, ki nam jo produkt ponudi pa je v dejstvu, da lahko za vse programe hkrati razvijam en sam dodatek, ki bo tekel na vseh programih. Torej situacija je sledeča: