Příručka aplikace Base 7.3
Kapitola 9
Makra
Tento dokument je chráněn autorskými právy © 2022 týmem pro dokumentaci LibreOffice. Přispěvatelé jsou uvedeni níže. Dokument lze šířit nebo upravovat za podmínek licence GNU General Public License (https://www.gnu.org/licenses/gpl.html), verze 3 nebo novější, nebo the Creative Commons Attribution License (https://creativecommons.org/licenses/by/4.0/), verze 4.0 nebo novější.
Všechny ochranné známky uvedené v této příručce patří jejich vlastníkům.
flywire |
Jean-Pierre Ledure |
Jean Hollis Weber |
Steve Fanning |
Olivier Hallot |
|
Robert Großkopf |
Pulkit Krishna |
Jost Lange |
Jean-Pierre Ledure |
Andrew Pitonyak |
Alain Romedenne |
Hazel Russman |
Jochen Schiffers |
Jean Hollis Weber |
Jakékoli připomínky nebo návrhy k tomuto dokumentu prosím směřujte do fóra dokumentačního týmu na adrese https://community.documentfoundation.org/c/documentation/loguides/ (registrace je nutná) nebo pošlete e-mail na adresu: loguides@community.documentfoundation.org.
Poznámka
Vše, co napíšete do fóra, včetně vaší e-mailové adresy a dalších osobních údajů, které jsou ve zprávě napsány, je veřejně archivováno a nemůže být smazáno. E-maily zaslané do fóra jsou moderovány.
Vydáno Srpen 2022. Založeno na LibreOffice 7.3 Community.
Jiné verze LibreOffice se mohou lišit vzhledem a funkčností.
Některé klávesové zkratky a položky nabídek jsou v systému macOS jiné než v systémech Windows a Linux. V následující tabulce jsou uvedeny nejdůležitější rozdíly, které se týkají informací v této knize. Podrobnější seznam se nachází v nápovědě aplikace.
Windows nebo Linux |
Ekvivalent pro macOS |
Akce |
Výběr v nabídce Nástroje > Možnosti |
LibreOffice > Předvolby |
Otevřou se možnosti nastavení. |
Klepnutí pravým tlačítkem |
Ctrl + klepnutí a/nebo klepnutí pravým tlačítkem v závislosti na operačním systému počítače |
Otevře se místní nabídka. |
Ctrl (Control) |
⌘ (Command) |
Používá se také s dalšími klávesami. |
Alt |
⌥ (Option) |
Používá se také s dalšími klávesami. |
Ctrl+Q |
⌘ + Q |
Ukončí LibreOffice |
Databázi v systému Base lze v zásadě spravovat bez maker. Někdy však mohou být nezbytná pro:
Účinnější prevence chyb při zadávání.
Zjednodušení některých úloh zpracování (přechod z jednoho formuláře do druhého, aktualizace dat po zadání do formuláře atd.).
Snadnější vyvolání některých příkazů SQL než v samostatném editoru SQL.
Sami se musíme rozhodnout, jak intenzivně chceme makra v Base používat. Makra mohou zlepšit použitelnost, ale vždy jsou spojena s malým snížením rychlosti programu a někdy i s větším (při špatném kódování). Z dlouhodobého hlediska může také způsobit problémy s údržbou kódu. Vždy je lepší začít plným využitím možností databáze a nastavením konfigurace formulářů, než se pokusíme zajistit další funkce pomocí maker. Makra by se měla vždy testovat na větších databázích, aby se zjistil jejich vliv na výkon.
Makra jsou vytvořena pomocí Nástroje > Makra > Správce maker > Základní. Zobrazí se okno s přístupem ke všem makrům. V případě Base odpovídá důležitá oblast názvu souboru Base.
Obrázek 1: Dialogové okno Nový modul
Tlačítko Nový v dialogovém okně makra LibreOffice Basic otevře dialogové okno Nový modul, ve kterém je požadován název modulu (složka, ve které bude makro uloženo). Název lze v případě potřeby později změnit.
Jakmile je zadán, zobrazí se editor maker. Jeho vstupní oblast již obsahuje klauzule Start a End for podprogramu:
REM ***** BASIC *****
Sub Main
End Sub
Pokud chceme použít makra, je nutné provést následující kroky:
Pomocí Nástroje > Možnosti > Zabezpečení > Zabezpečení maker by měla být úroveň zabezpečení snížena na střední. V případě potřeby můžeme na kartě Důvěryhodné zdroje navíc nastavit cestu k vlastním souborům maker, abychom zabránili pozdějším dotazům na aktivaci maker.
Po vytvoření prvního modulu makra je nutné databázový soubor zavřít a znovu otevřít.
Některé základní zásady pro použití kódu Basic v LibreOffice:
Řádky nemají ve výchozím nastavení žádná čísla řádků (ačkoli je možné je povolit) a musí končit zakončením řádku (hard return).
U funkcí, rezervovaných výrazů a podobných prvků se nerozlišují velká a malá písmena. "String" je tedy totéž co "STRING" nebo "string" nebo jakákoli jiná kombinace velkých a malých písmen. Velká písmena by se měla používat pouze pro zlepšení čitelnosti. Názvy konstant a výčtů však při prvním průchodu překladačem maker rozlišují malá a velká písmena, proto je lepší je vždy psát se správnými velkými písmeny.
Rozlišujeme procedury (začínající Sub) a funkce (začínající Function). Procedury byly původně programové segmenty bez návratové hodnoty, zatímco funkce vracejí hodnoty, které lze dále zpracovávat. Toto rozlišení však stále více ztrácí na významu. Lidé dnes používají termíny jako „metoda“ nebo „rutina“ bez ohledu na to, zda existuje návratová hodnota, nebo ne. Procedura může mít také návratovou hodnotu (kromě „Variant“).
Sub myProcedure As Integer 'Tato syntaxe pro Sub není oficiálně podporována.
End Sub
Další podrobnosti nalezneme v kapitole 13, Začínáme s makry, v příručce Začínáme s LibreOffice.
Poznámka
Makra ve verzích PDF a ODT této kapitoly jsou barevně odlišena podle pravidel editoru maker LibreOffice:
Popis makra
Komentář makra
Operátor makra
Rezervovaný výraz makra
Číslo makra
Řetězec znaků makra
Poznámka
V této kapitole je několik odkazů na Odkazy na LibreOffice API. V elektronické verzi kapitoly budou tyto odkazy hypertextové. Pro ty, kteří čtou tištěnou verzi, je odkaz na rozhraní API k dispozici na adrese https://api.libreoffice.org/docs/idl/ref/.
„Přímý způsob“ pomocí Nástroje > Makra > Spustit makro je možný, ale pro základní makra není obvyklý. Makro je obvykle přiřazeno k události a spouští se, když tato událost nastane. Použití maker je na následující:
Zpracování událostí ve formulářích.
Úprava zdroje dat uvnitř formuláře.
Přepínání mezi ovládacími prvky formuláře.
Reakce na to, co uživatel dělá uvnitř ovládacího prvku.
„Přímá cesta“ není možná, a to ani pro testování, když má být používán jeden z objektů thisComponent (viz „Přístup k formulářům” na straně 1) nebo oEvent (viz „Přístup k prvkům formuláře” na straně 1).
Má-li být makro spuštěno událostí, musí být nejprve definováno. Poté jej lze přiřadit k události. K těmto událostem lze přistupovat na dvou místech.
Akce, které se provádějí při otevření nebo zavření formuláře, se zaznamenávají následujícím způsobem:
Obrázek 2: Dialogové okno Přizpůsobení, karta Události
Při návrhu formuláře otevřeme kartu Události v Nástroje > Přizpůsobit.
Vybereme příslušnou událost. Některá makra lze spustit pouze při zvolení události Pohled vytvořen. Jiná makra, například pro vytvoření celoobrazovkového formuláře, by měla být spuštěna příkazem Otevřít dokument.
Pomocí tlačítka Makro vyhledáme požadované makro a potvrdíme výběr.
V části Uložit do zadáme název formuláře.
Potvrdíme pomocí OK.
Po otevření okna, které zobrazuje celkový obsah formuláře, lze přistupovat k jednotlivým prvkům formuláře. To zahrnuje prvky, které jsme formuláři přiřadili.
K prvkům formuláře lze přistupovat pomocí Navigátoru formulářem, jak je znázorněno na obrázku níže. Stejně dobře k nim lze přistupovat pomocí místních nabídek jednotlivých ovládacích prvků v rozhraní formuláře.
Všechny události uvedené pod Vlastnosti formuláře > Události se odehrávají při otevření okna formuláře. Lze je nastavit samostatně pro každý formulář nebo podformulář v okně formuláře.
Obrázek 3: Dialogové okno Vlastnosti formuláře, karta Události
Poznámka
Base používá slovo „formulář“ jak pro okno otevřené pro zadávání dat, tak pro prvky v tomto okně, které jsou vázány na konkrétní zdroj dat (tabulku nebo dotaz).
Jedno okno formuláře může obsahovat několik formulářů s různými zdroji dat. V Navigátoru formulářem se vždy nejprve zobrazí termín Formuláře, který v případě jednoduchého formuláře obsahuje pouze jednu podřízenou položku.
Všechna ostatní makra se registrují pomocí vlastností podformulářů a ovládacích prvků na kartě Události.
Otevřeme okno vlastností ovládacího prvku (pokud jsme tak ještě neučinili).
Na kartě Události vybereme vhodnou událost.
K úpravě zdroje dat použijeme události, které odkazují na položku Záznam, Aktualizovat nebo Obnovit.
Pro tlačítka nebo volby v polích seznamu nebo možností by byla událost Provést akci první volbou.
Všechny ostatní události závisí na typu ovládání a požadované akci.
Kliknutím na tlačítko ... vpravo otevřeme dialogové okno Přiřadit akci.
Kliknutím na tlačítko Makro vybereme makro definované pro danou akci.
Kliknutím na OK potvrdíme přiřazení.
Obrázek 4: Dialogové okno Přiřadit akci
V této části jsou vysvětleny některé makrojazyky, které se v Base běžně používají, zejména ve formulářích. Pokud je to možné (a rozumné), jsou příklady uvedeny ve všech následujících oddílech.
Definice makra začíná jeho typem – Sub nebo Function – a končí End Sub nebo End Function. Makro, které je přiřazeno události, může přijímat argumenty (hodnoty); jediný užitečný je argument oEvent. Všechny ostatní rutiny, které by mohly být takovým makrem volány, mohou být definovány s návratovou hodnotou nebo bez ní, v závislosti na jejich účelu, a v případě potřeby opatřeny argumenty.
Sub update_loan
End Sub
Sub from_Form_to_Form(oEvent As Object)
End Sub
Function confirm_delete(oEvent As Object) As Boolean
confirm_delete = False
End Function
Je užitečné si tento framework ihned zapsat a následně do něj vložit obsah. Nezapomeňte přidat komentáře k vysvětlení makra a pamatujte na pravidlo „Tolik, kolik je třeba, co nejméně je možné“. Jazyk Basic navíc nerozlišuje mezi velkými a malými písmeny. Obvykle se pevně stanovené pojmy jako SUB píšou přednostně velkými písmeny, ostatní pojmy smíšenými.
V dalším kroku, na začátku rutiny, se pomocí příkazu Dim definují proměnné, které se budou v rutině vyskytovat, každá s příslušným datovým typem. Samotný Basic to nevyžaduje; akceptuje všechny nové proměnné, které se v programu vyskytnou. Programový kód je však „bezpečnější“, pokud jsou proměnné, zejména jejich datové typy, deklarovány. Mnozí programátoři to vyžadují a při psaní modulu používají volbu Explicit jazyka Basic. To znamená „Neuznávej žádnou starou proměnnou, ale pouze tu, kterou jsem předem deklaroval“.
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm As Object
Dim sName As String
Dim bOKEnabled As Boolean
Dim iCounter As Integer
Dim dBirthday As Date
V názvech proměnných lze používat pouze abecední znaky (A-Z nebo a-z), čísla a znak podtržení „_“. Žádné speciální znaky nejsou povoleny. Mezery jsou za určitých podmínek povoleny, ale je lepší se jim vyhnout. První znak musí být abecední.
Běžnou praxí je uvádět datový typ v prvním znaku. Pak ji lze rozpoznat všude, kde se proměnná v kódu vyskytuje. Doporučují se také „expresivní názvy“, aby byl význam proměnné zřejmý z jejího názvu.
Poznámka
Pokud je to možné, měli bychom to upřesnit, protože pouze jedno písmeno neumožňuje rozlišit mezi datovými typy „Double“ a „Date“ nebo „Single“ a „String“.
Seznam možných datových typů v jazyce Star Basic najdeme v příloze A této knihy. Na různých místech se liší od typů v databázi a v rozhraní API (Application Programming Interface) LibreOffice. Tyto změny jsou jasně uvedeny v příkladech.
Zejména u databází je důležité sestavení několika proměnných do záznamu. Pokud je několik proměnných uloženo společně na jednom společném místě, nazývá se pole. Před zápisem dat do pole musí být pole definováno.
Dim arData()
vytvoří prázdné pole.
arData = Array("Lisa","Schmidt")
vytvoří pole určité velikosti (2 prvky) a předá mu hodnoty.
Použití
Print arData(0), arData(1)
způsobí, že se na obrazovce zobrazí dva definované prvky. Počet prvků začíná číslem 0.
Dim arData(2)
arData(0) = "Lisa"
arData(1) = "Schmidt"
arData(2) = "Cologne"
Tím se vytvoří pole, do kterého lze uložit tři prvky libovolného typu, například záznam pro "Lisa""Schmidt""Cologne". Do tohoto pole nelze vložit více než tři prvky. Pokud chceme uložit více prvků, musíme pole zvětšit. Pokud je však velikost pole předefinováno za běhu makra, je pole zpočátku prázdné, stejně jako nové pole.
ReDim Preserve arData(3)
arData(3) = "18.07.2003"
Přidáním Preserve se zachovávají předchozí údaje, takže pole je skutečně rozšířeno o položku data (zde ve formě textu).
Výše uvedené pole může uchovávat pouze jeden záznam. Pokud chceme uložit několik záznamů, jako je tomu u tabulky v databázi, musíme definovat dvourozměrné pole.
Dim arData(2,1)
arData(0,0) = "Lisa"
arData(1,0) = "Schmidt"
arData(2,0) = "Cologne"
arData(0,1) = "Egon"
arData(1,1) = "Müller"
arData(2,1) = "Hamburg"
I zde je možné rozšířit dříve definované pole a zachovat stávající obsah pomocí Preserve.
Formulář leží v aktuálně aktivním dokumentu. Oblast, která je zde reprezentována, se nazývá drawpage. Kontejner, ve kterém jsou uloženy všechny formuláře, se nazývá forms; v Navigátoru formulářů se zobrazuje jako primární záhlaví s připojenými jednotlivými formuláři. Výše uvedené proměnné získávají své hodnoty takto:
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm = oDrawpage.forms.getByName("Filter")
Formulář, ke kterému se má přistupovat, se nazývá Filter. Jedná se o název, který je viditelný v nejvyšší úrovni Navigátoru formulářem (ve výchozím nastavení se první formulář jmenuje MainForm). Dílčí formuláře jsou v rámci hlavního formuláře hierarchicky uspořádány a lze k nim přistupovat postupně:
Dim oSubForm As Object
Dim oSubSubForm As Object
oSubForm = oForm.getByName("Readerselect")
oSubSubForm = oSubForm.getByName("Readerdisplay")
Namísto použití přechodných proměnných můžeme přejít přímo na konkrétní formulář. Přechodný objekt, který může být použit více než jednou, je třeba deklarovat a přiřadit mu samostatnou hodnotu. V následujícím příkladu se oSubForm již nepoužívá.
oForm = thisComponent.drawpage.forms.getByName("Filter")
oSubSubForm = oForm.getByName("readerselect").getByName("readerdisplay")
Poznámka
Pokud se název skládá pouze z písmen ascii a čísel bez mezer a speciálních znaků, lze jej použít přímo v příkazu přiřazení.
oForm = thisComponent.drawpage.forms.Filter
oSubSubForm = oForm.readerselect.readerdisplay
Na rozdíl od běžného používání jazyka Basic je nutné tyto názvy psát se správnými velkými a malými písmeny.
Jiný způsob přístupu k formuláři poskytuje událost, která makro spouští.
Pokud je makro spuštěno z události formuláře, například Vlastnosti formuláře > Před záznamem, lze se k samotnému formuláři dostat následujícím způsobem:
Sub MacroexampleCalc(oEvent As Object)
oForm = oEvent.Source
...
End Sub
Pokud je makro spuštěno z události na ovládacím prvku formuláře, například Textové pole > Při ztrátě zaměření, zpřístupní se formulář i pole:
Sub MacroexampleCalc(oEvent As Object)
oField = oEvent.Source.Model
oForm = oField.Parent
...
End Sub
Přístup k událostem má tu výhodu, že se nemusíme starat o to, zda se jedná o hlavní nebo podformulář. Také název formuláře nemá pro fungování makra žádný význam.
K prvkům ve formulářích se přistupuje podobným způsobem: deklarujeme vhodnou proměnnou jako objekt a vyhledáme příslušný ovládací prvek ve formuláři:
Dim btnOK As Object ' Button »OK»
btnOK = oSubSubForm.getByName("button 1") ' z formuláře readerdisplay
Tato metoda funguje vždy, když víme, se kterým prvkem má makro pracovat. Pokud je však prvním krokem určení, která událost makro spustila, je užitečná výše uvedená metoda oEvent. Proměnná je deklarována v rámci makra „framework“ a při spuštění makra je jí přiřazena hodnota. Vlastnost Source vždy uvádí prvek, který makro spustil, zatímco vlastnost Model podrobně popisuje ovládací prvek:
Sub confirm_choice(oEvent As Object)
Dim btnOK As Object
btnOK = oEvent.Source.Model
End Sub
Pokud chceme, můžeme s objektem získaným touto metodou provádět další akce.
Upozorňujeme, že podformuláře se počítají jako součásti formuláře.
Přístup k databázi se obvykle řídí pomocí formulářů, dotazů, sestav nebo funkce hromadné korespondence (mailmerge), jak bylo popsáno v předchozích kapitolách. Pokud se tyto možnosti ukážou jako nedostatečné, může makro přistupovat k databázi několika způsoby.
Nejjednodušší metoda používá stejné připojení jako formulář. oForm se určí podle výše uvedeného.
Dim oConnection As Object
oConnection = oForm.activeConnection()
Nebo můžeme zdroj dat (tj. databázi) načíst prostřednictvím dokumentu a pro makro použít jeho existující připojení:
Dim oDatasource As Object
Dim oConnection As Object
oDatasource = thisComponent.Parent.dataSource
oConnection = oDatasource.getConnection("","")
Další způsob umožňuje vytvořit připojení k databázi za běhu:
Dim oDatasource As Object
Dim oConnection As Object
oDatasource = thisComponent.Parent.CurrentController
If Not (oDatasource.isConnected()) Then oDatasource.connect()
oConnection = oDatasource.ActiveConnection()
Podmínka If řídí pouze jeden řádek, takže End If není nutná.
Pokud má být makro spuštěno prostřednictvím uživatelského rozhraní, a ne z události ve formuláři, je vhodná následující varianta:
Dim oDatasource As Object
Dim oConnection As Object
oDatasource = thisDatabaseDocument.CurrentController
If Not (oDatasource.isConnected()) Then oDatasource.connect()
oConnection = oDatasource.ActiveConnection()
Přístup k databázím mimo aktuální databázi je možný následujícím způsobem:
Dim oDatabaseContext As Object
Dim oDatasource As Object
Dim oConnection As Object
oDatabaseContext = createUnoService("com.sun.star.sdb.DatabaseContext")
oDatasource = oDatabaseContext.getByName("registered name of Database in LO")
oConnection = oDatasource.GetConnection("","")
Připojení k databázím, které nejsou registrovány v LibreOffice, jsou také možná. V takových případech musí být místo registrovaného názvu uvedena cesta k databázi jako file:///....../database.odb.
Rozšířené pokyny pro připojení k databáze jsou uvedeny v části „Vytvoření připojení k databázi“ (strana 1).
S databází pracujeme pomocí příkazů SQL. Ty je třeba vytvořit a odeslat do databáze; výsledek se určí podle typu příkazu a výsledky lze dále zpracovávat. Direktiva createStatement vytvoří k tomuto účelu vhodný objekt.
Dim oSQL_Statement As Object ' objekt, který provede SQL příkaz
Dim stSql As String ' Text aktuálního SQL příkazu
Dim oResult As Object ' výsledek executeQuery
Dim iResult As Integer ' výsledek executeUpdate
oSQL_Statement = oConnection.createStatement()
Pro dotaz na data zavoláte metodu executeQuery; výsledek se pak vyhodnotí. Názvy tabulek a polí se obvykle uvádějí s dvojitými uvozovkami. Makro je musí maskovat dalšími dvojitými uvozovkami, aby se v příkazu objevily.
stSql = "SELECT * FROM ""Table1"""
oResult = oSQL_Statement.executeQuery(stSql)
Chceme-li upravit data – tedy INSERT, UPDATE nebo DELETE – nebo ovlivnit strukturu databáze, zavoláme metodu executeUpdate. V závislosti na příkazu a databázi se buď nezjistí nic užitečného (nula), nebo se zjistí počet změněných záznamů.
stSql = "DROP TABLE ""Suchtmp"" IF EXISTS"
iResult = oSQL_Statement.executeUpdate(stSql)
Pro úplnost je třeba zmínit ještě jeden speciální případ: má-li být oSQL_Statement používán různými způsoby pro SELECT nebo pro jiné účely, je k dispozici ještě jedna metoda, a to execute. Nebudeme ji zde používat. Další informace nalezneme v části Odkazy API.
Ve všech případech, kdy je třeba do příkazu SQL převést ruční zadání uživatele, je jednodušší a bezpečnější nevytvářet příkaz jako dlouhý řetězec znaků, ale připravit si jej předem a použít jej s parametry. To usnadňuje formátování čísel, dat a řetězců (zmizí neustálé dvojité uvozovky) a zabraňuje ztrátě dat při nekorektním vstupu.
Při použití této metody se vytvoří a připraví objekt pro konkrétní příkaz SQL:
Dim oSQL_Statement As Object 'objekt, který provede SQL příkaz
Dim stSql As String ' Text aktuálního SQL příkazu
stSql = "UPDATE author " _
& "SET lastname = ?, firstname = ?" _
& "WHERE ID = ?"
oSQL_Statement = oConnection.prepareStatement(stSql)
Objekt je vytvořen pomocí prepareStatement, takže příkaz SQL je předem znám. Každý otazník označuje pozici, která později – před provedením příkazu – získá skutečnou hodnotu. Protože je příkaz připraven předem, databáze ví, jaký typ záznamu – v tomto případě dva řetězce a číslo – se očekává. Jednotlivé pozice jsou rozlišeny číslem (počítáno od 1).
Poté se hodnoty přenesou pomocí vhodných příkazů a provede se příkaz SQL. Zde jsou hodnoty převzaty z ovládacích prvků formuláře, ale mohou pocházet i z jiných maker nebo mohou být zadány jako prostý text:
oSQL_Statement.setString(1, oTextfeld1.Text) ' Text pro příjmení (surname)
oSQL_Statement.setString(2, oTextfeld2.Text) ' Text pro křestní jmeno (first name)
oSQL_Statement.setLong(3, oZahlenfeld1.Value) ' hodnota pro odpovídající ID
iResult = oSQL_Statement.executeUpdate
Úplný seznam přiřazení je uveden v části "Parametry pro připravené příkazy SQL" (strana 1).
Další informace o výhodách této metody nalezneme níže (externí odkazy):
V závislosti na požadavcích existuje několik způsobů, jak přenést informace z databáze do makra, aby mohly být dále zpracovány.
Upozornění: odkazy na formulář zahrnují i podformuláře. Tím je myšlen formulář nebo část formuláře, která je vázána na určitý zdroj dat.
Aktuální záznam a jeho data jsou vždy k dispozici prostřednictvím formuláře, který zobrazuje příslušná data (tabulka, dotaz, SELECT). Existuje několik metod typu getdata_, jako např.:
Dim ID As Long
Dim sName As String
Dim dValue AS Currency
Dim dEntry As New com.sun.star.util.Date
ID = oForm.getLong(1)
sName = oForm.getString(2)
dValue = oForm.getDouble(4)
dEntry = oForm.getDate(7)
Všechny tyto metody vyžadují číslo sloupce ze zdroje dat; počítadlo začíná od 1.
Poznámka
U všech metod, které pracují s databázemi, začíná počítání od hodnoty 1. To platí pro sloupce i řádky.
Pokud pro práci s podkladovým zdrojem dat (tabulkou, dotazem, pohledem) dáváme přednost použití názvů sloupců před jejich čísly, lze číslo sloupce určit pomocí findColumn. Zde je příklad pro vyhledání sloupce s názvem Name.
Dim sName As String
nName = oForm.findColumn("Name")
sName = oForm.getString(nName)
Typ vracené hodnoty vždy odpovídá typu metody, je však třeba upozornit na následující zvláštní případy:
Pro data typu Decimal, Currency apod., která se používají pro komerčně přesné výpočty, neexistují žádné metody. Protože Basic automaticky provede příslušný převod, můžeme použít getDouble.
Při použití getBoolean je třeba vzít v úvahu způsob, jakým jsou v databázi definovány hodnoty TRUE a FALSE. Obvyklé definice (logické hodnoty, 1 jako TRUE) jsou zpracovány správně.
Hodnoty data lze definovat nejen pomocí datového typu Date, ale také (jak je uvedeno výše) jako util.Date. To usnadňuje čtení a úpravu roku, měsíce a dne.
U celých čísel si dáme pozor na různé datové typy. Výše uvedené příklady používají getLong; ID proměnné Basicu musí mít také datový typ Long, protože to odpovídá datovému typu Integer v databázi.
Úplný seznam těchto metod najdeme v části "Úprava řádků dat" (strana 1).
Tip
Pokud mají být hodnoty z formuláře použity přímo pro další zpracování v SQL (například pro vstup do jiné tabulky), je mnohem jednodušší nedotazovat se na typ pole.
Následující makro, které je vázáno na Vlastnosti: Tlačítko > Události > Provést akci načte první pole ve formuláři nezávisle na typu, který je nutný pro další zpracování v Basicu.
SUB ReadValues(oEvent As Object)
Dim oForm As Object
Dim stFeld1 As String
oForm = oEvent.Source.Model.Parent
stFeld1 = oForm.getString(1)
End Sub
Pokud jsou pole načtena pomocí getString(), je zachováno veškeré formátování potřebné pro další zpracování SQL. Datum, které se zobrazí jako 08.03.19, se načte ve formátu 2019-03-08 a lze jej použít přímo v SQL.
Čtení ve formátu odpovídající typu je povinné pouze tehdy, má-li být hodnota dále zpracována v rámci makra, například při výpočtu.
Stejným způsobem lze použít i sadu výsledků dotazu. V sekci Příkazy SQL najdeme pro tuto sadu výsledků proměnnou oResult, která se obvykle čte takto:
While oResult.next ' jeden záznam za druhým
REM převádí výsledek do proměnných
stVar = oResult.getString(1)
inVar = oResult.getLong(2)
boVar = oResult.getBoolean(3)
REM udělá něco s těmito hodnotami
Wend
Podle typu SQL příkazu, očekávaného výsledku a jeho účelu lze smyčku WHILE zkrátit nebo zcela vypustit. V zásadě lze ale vždy takto vyhodnotit množinu výsledků.
Pokud se má vyhodnotit pouze první záznam.
oResult.next
přistupuje k řádku tohoto záznamu a pomocí
stVar = oResult.getString(1)
přečte obsah prvního pole. Zde smyčka končí.
Dotaz pro výše uvedený příklad má v prvním sloupci text, ve druhém celé číslo (Integer v databázi odpovídá Long v jazyce Basic) a ve třetím pole Ano/Ne. K polím se přistupuje pomocí indexu pole, který na rozdíl od indexu pole začíná od 1.
Navigace přes takový výsledek není možná. Povoleny jsou pouze jednotlivé kroky k dalšímu záznamu. Aby bylo možné se v záznamu pohybovat, musí být při vytváření dotazu znám ResultSetType. K tomu se přistupuje pomocí
oSQL_Result.ResultSetType = 1004
nebo
oSQL_Result.ResultSetType = 1005
Typ 1004 – SCROLL_INTENSIVE umožňuje volný pohyb, ale nezachycuje změny v původních datech. Typ 1005 – SCROLL_SENSITIVE rozpozná změny v původních datech , které mohou ovlivnit výsledek dotazu.
Celkový počet řádků v sadě výsledků lze určit až po zadání číselného typu výsledku. Provádí se takto:
Dim iResult As Long
If oResult.last ' přejde na poslední záznam, pokud je to možné
iResult = oResult.getRow ' průběžné číslo je součet
Else
iResult = 0
End If
Pokud je ovládací prvek vázán na zdroj dat, lze hodnotu načíst přímo, jak je popsáno v následující části. To však může vést k problémům. Bezpečnější je použít postup popsaný v kapitole „Používání formulářů“ (strana 1) nebo následující metodu, která je uvedena pro několik různých typů ovládání:
sValue = oTextField.BoundField.Text ' příklad pro Textové pole
nValue = oNumericField.BoundField.Value ' příklad číselného pole
dValue = oDateField.BoundField.Date ' příklad pole pro datum
BoundField představuje spojení mezi viditelným ovládacím prvkem a skutečným obsahem datové sady.
V předposledním příkladu byla použita metoda Next pro přechod z jednoho řádku výsledkové sady na další. Existují další podobné metody a testy, které lze použít jak pro data ve formuláři – reprezentovaná proměnnou oForm –, tak pro množinu výsledků. Například pomocí metody popsané v části „Automatická aktualizace formulářů“ (strana 1) lze znovu vybrat předchozí záznam:
Dim loRow As Long
loRow = oForm.getRow() ' uloží aktuální číslo řádku
oForm.reload() ' znovu načte množinu záznamů
oForm.absolute(loRow) ' vrátí se zpět ke stejnému řádku
V části „Automatická aktualizace formulářů“ jsou uvedeny všechny metody, které jsou k tomu vhodné.
Poznámka
Existuje chyba, která ovlivňuje formuláře. Při změně dat ve formuláři nastaví aktuální číslo řádku na hodnotu „0“. Viz https://bugs.documentfoundation.org/show_bug.cgi?id=82591. Chceme-li získat správné číslo aktuálního řádku, přiřadíme k události Formulář > Vlastnosti > Události > Po změně záznamu následující makro.
Global loRow As Long
Sub RowCounter(oEvent As Object)
loRow = oEvent.Source.Row
End Sub
Nové číslo řádku se načte a přiřadí do globální proměnné loRow. Tato proměnná má být umístěna na začátku všech modulů a zachová si svůj obsah, dokud neukončíme aplikaci Base nebo nezměníme hodnotu opětovným voláním RowCounter.
Aby bylo možné záznamy upravovat, musí spolupracovat několik věcí:
Informace musí uživatel zadat do ovládacího prvku pomocí klávesnice.
Datová sada za formulářem musí být o změně informována. K tomu dochází, když se přesuneme z pole do nového pole.
Je třeba upravit samotnou databázi. K tomu dochází při přechodu z jednoho záznamu na druhý.
Při provádění tohoto postupu pomocí makra je třeba vzít v úvahu všechny tyto dílčí kroky. Pokud některý z nich chybí nebo je proveden chybně, změny se ztratí a v databázi se neobjeví. Především se změna nesmí týkat zobrazené hodnoty ovládacího prvku, ale samotné sady dat. Proto je zbytečné měnit vlastnost Text ovládacího prvku.
Upozorňujeme, že tabulky jsou jediné datové sady, které lze měnit, aniž by to způsobilo problémy. U ostatních datových sad jsou úpravy možné pouze za zvláštních okolností.
Pokud chceme změnit pouze jednu hodnotu, lze použít vlastnost BoundField ovládacího prvku s vhodnou metodou. Poté musí být změna přenesena do databáze. Zde je příklad pole pro datum, do kterého se zadává skutečné datum:
Dim unoDate As New com.sun.star.util.Date
unoDate.Year = Year(Date)
unoDate.Month = Month(Date)
unoDate.Day = Day(Date)
oDateField.BoundField.updateDate( unoDate )
oForm.updateRow() ' změna je přenesena do databáze
Pro BoundField se použije metoda updateXxx, která odpovídá datovému typu pole. V tomto příkladu se jedná o pole Date. Jako argument se předává nová hodnota – v tomto případě aktuální datum převedené do formátu, který makro vyžaduje.
Předchozí metoda je nevhodná, pokud je třeba změnit několik hodnot v řádku. Pro každé pole by totiž musel existovat ve formuláři ovládací prvek, což často není žádoucí ani užitečné. Pro každé pole musí být také načten objekt. Jednoduchý a přímý způsob používá tento formulář:
Dim unoDate As New com.sun.star.util.Date
unoDate.Year = Year(Date)
unoDate.Month = Month(Date)
unoDate.Day = Day(Date)
oForm.updateDate(3, unoDate )
oForm.updateString(4, "ein Text")
oForm.updateDouble(6, 3.14)
oForm.updateInt(7, 16)
oForm.updateRow()
Pro každý sloupec v datové sadě se zavolá metoda updateXxx odpovídající jeho typu. Argumenty jsou číslo sloupce (počítáno od 1) a požadovaná hodnota. Poté se změny přenesou do databáze.
Pojmenované změny se vztahují k aktuálnímu řádku datové sady, která je základem formuláře. Za určitých okolností je nutné zavolat metodu z kapitoly „Navigace v datové sadě“ (strana 1). Je třeba provést následující kroky:
Vybereme aktuální záznam.
Změníme hodnoty podle popisu v předchozí části.
Změnu potvrdíme následujícím příkazem:
oForm.updateRow()
Ve zvláštních případech je možné zrušit a vrátit se do předchozího stavu:
oForm.cancelRowUpdates()
Pro nový záznam existuje speciální metoda srovnatelná s přechodem na nový řádek v ovládacím prvku tabulky. To se provádí následujícím způsobem:
Připravíme se na nový záznam:
oForm.moveToInsertRow()
Zadáme všechny potřebné/požadované hodnoty. To se provádí pomocí metod updateXxx, jak je uvedeno v předchozí části.
Nová data potvrdíme následujícím příkazem:
oForm.insertRow()
Nový záznam nelze snadno vrátit zpět. Místo toho budeme muset nový záznam odstranit.
Pro odstranění záznamu existuje jednoduchý příkaz; postupujeme takto:
Zvolíme požadovaný záznam a provedeme jeho aktualizaci, stejně jako v případě změny.
K jeho odstranění použijeme následující příkaz:
oForm.deleteRow()
Tip
Aby bylo zajištěno, že se změny přenesou do databáze, je třeba je explicitně potvrdit pomocí updateRow nebo insertRow. Zatímco při stisknutí tlačítka Uložit se automaticky použije příslušná funkce, u makra je třeba před uložením určit, zda se jedná o nový záznam (Insert) nebo o úpravu stávajícího (Update).
If oForm.isNew Then
oForm.insertRow()
Else
oForm.updateRow()
End If
Kromě obsahu datové sady lze z kontroly vyčíst, upravit a modifikovat mnohem více informací. To platí zejména pro vlastnosti, jak je popsáno v kapitole 4, Formuláře.
Několik příkladů v části „Zlepšení použitelnosti“ (strana 1) používá doplňkové informace v poli:
Dim stTag As String
stTag = oEvent.Source.Model.Tag
Jak bylo uvedeno v předchozí části, vlastnost Text lze užitečně měnit pouze tehdy, pokud ovládací prvek není vázán na datovou sadu. Existují však i další vlastnosti, které jsou určeny jako součást definice formuláře, ale lze je upravit za běhu. Například popisek může mít jinou barvu textu, pokud představuje spíše varování než informaci:
Sub showWarning(oField As Object, iType As Integer)
Select Case iType
Case 1
oField.TextColor = RGB(0,0,255) ' 1 = blue
Case 2
oField.TextColor = RGB(255,0,0) ' 2 = red
Case Else
oField.TextColor = RGB(0,255,0) ' 0 = green (neither 1 nor 2)
End Select
End Sub
Zatímco návrhář formuláře může pro vlastnosti a přístup k datům používat označení v rodném jazyce, v jazyce Basic lze používat pouze anglické názvy. Ty jsou uvedeny v následujícím přehledu.
Vlastnosti, které se obvykle nastavují pouze v definici formuláře, zde nejsou obsaženy. Stejně tak metody (funkce a/nebo procedury), které se používají jen zřídka nebo jsou vyžadovány pouze u složitějších deklarací.
Přehled obsahuje následující informace:
Název – Název, který se použije pro vlastnost v makrokódu
Datový typ – Datový typ Basic. U funkcí je to návratový typ. Není zahrnuto pro procedury.
R/W – Označuje způsob použití hodnoty:
R – pouze pro čtení
W – pouze zápis (úprava)
(R) – Čtení možné, nevhodné k úpravám
(W) – Psaní je možné, ale není vhodné
R+W – vhodné pro čtení a psaní
Další informace nalezneme v Přehledu API po vyhledání anglického názvu ovládacího prvku. Existuje užitečný nástroj Xray, který umožňuje zjistit, které vlastnosti a metody jsou pro daný prvek k dispozici.
Sub Main(oEvent)
Xray(oEvent)
End Sub
Tím se spustí rozšíření Xray pro daný argument.
Model ovládacího prvku popisuje jeho vlastnosti. Podle situace může být hodnota vlastnosti přístupná pouze pro čtení nebo pouze pro zápis. Pořadí je stejné jako v seznamech „Vlastnosti řídicích polí“ v kapitole 4, Formuláře.
V každém ovládacím prvku, který zobrazuje text, lze přizpůsobit vlastnosti písma.
Tabulka 1: Vlastnosti písma
Název |
Datový typ |
R/W |
Vlastnost |
FontName |
string |
R+W |
Název písma |
FontHeight |
single |
R+W |
Velikost písma |
FontWeight |
single |
R+W |
Tučné nebo normální |
FontSlant |
integer |
R+W |
Kurzíva nebo latinka |
FontUnderline |
integer |
R+W |
Podtržené či nikoliv |
FontStrikeout |
integer |
R+W |
Přeškrtnuté či nikoliv |
Anglický termín: Form
Tabulka 2: Vlastnosti vzorce
Název |
Datový typ |
R/W |
Vlastnost |
ApplyFilter |
boolean |
R+W |
Použitý filtr |
Filtr |
string |
R+W |
Aktuální filtr pro záznam |
FetchSize |
long |
R+W |
Počet záznamů načtených najednou |
Row |
long |
R |
Aktuální číslo řádku |
RowCount |
long |
R |
Počet záznamů |
Ovládací prvek – viz také FormComponent
Tabulka 3: Vlastnosti platné pro všechny ovládací prvky
Název |
Datový typ |
R/W |
Vlastnost |
Název |
string |
R+(W) |
Název pole |
Enabled |
boolean |
R+W |
Aktivní: Pole lze vybrat. |
EnableVisible |
boolean |
R+W |
Zobrazí se pole. |
ReadOnly |
boolean |
R+W |
Obsah pole nelze měnit. |
TabStop |
boolean |
R+W |
Do pole se dostaneme pomocí klávesy Tab |
Zarovnání |
integer |
R+W |
Vodorovné zarovnání: |
BackgroundColor |
long |
R+W |
Barva pozadí |
Tag |
string |
R+W |
Další informace |
HelpText |
string |
R+W |
Text nápovědy jako Tip zobrazený po najetí |
Tabulka 4: Vlastnosti platné pro mnoho ovládacích prvků
Název |
Datový typ |
R/W |
Vlastnost |
Text |
string |
(R+W) |
Zobrazený obsah pole. V textových polích je lze přečíst a dále zpracovat, ale u jiných typů to obvykle nefunguje. |
Spin |
boolean |
R+W |
Číselník začleněný do formátovaného pole. |
TextColor |
long |
R+W |
Barva textu (popředí). |
DataField |
string |
R |
Název pole v datové sadě. |
BoundField |
objekt |
R |
Objekt představující připojení k datové sadě a poskytující přístup k obsahu pole. |
Tabulka 5: Další vlastnosti textového pole
Název |
Datový typ |
R/W |
Vlastnost |
String |
string |
R+W |
Zobrazený obsah pole. |
MaxTextLen |
integer |
R+W |
Maximální délka textu. |
DefaultText |
string |
R+W |
Výchozí text. |
MultiLine |
boolean |
R+W |
Označuje, zda existuje více než jeden řádek. |
EchoChar |
(integer) |
R+W |
Znak zobrazený při zadávání hesla. |
Tabulka 6: Vlastnosti číselného pole
Název |
Datový typ |
R/W |
Vlastnost |
ValueMin |
double |
R+W |
Minimální přijatelná vstupní hodnota |
ValueMax |
double |
R+W |
Maximální přijatelná vstupní hodnota |
Hodnota |
double |
R+(W) |
Aktuální hodnota |
ValueStep |
double |
R+W |
Interval odpovídající jednomu kliknutí kolečkem myši nebo spinboxem. |
DefaultValue |
double |
R+W |
Výchozí hodnota. |
DecimalAccuracy |
integer |
R+W |
Počet desetinných míst. |
ShowThousandsSeparator |
boolean |
R+W |
Zobrazení oddělovače tisíců podle nastavení národního prostředí. |
Hodnoty data jsou definovány datovým typem long a zobrazují se ve formátu ISO: RRRRMMDD, například 20190304 pro 04. března 2019. Chceme-li použít tento typ s funkcí getDate a updateDate, a s typem com.sun.star.util.Date, podíváme se na příklady.
Tabulka 7: Vlastnosti pole Datum
Název |
Datový typ |
Datový typ od LO 4.1.1 |
R/W |
Vlastnost |
DateMin |
long |
com.sun.star.util.Date |
R+W |
Minimální akceptované zadané datum. |
DateMax |
long |
com.sun.star.util.Date |
R+W |
Maximální akceptované zadané datum. |
Datum |
long |
com.sun.star.util.Date |
R+(W) |
Aktuální hodnota |
DateFormat |
integer |
|
R+W |
Formát data specifický pro operační systém: |
DefaultDate |
long |
com.sun.star.util.Date |
R+W |
Výchozí hodnota. |
DropDown |
boolean |
|
R+W |
Zobrazení rozevíracího měsíčního kalendáře |
Hodnoty času jsou také typu long.
Tabulka 8: Vlastnosti pole pro čas
Název |
Datový typ |
Datový typ z LO 4.1.1 |
R/W |
Vlastnost |
TimeMin |
long |
com.sun.star.util.Time |
R+W |
Minimální přijatelná vstupní hodnota. |
TimeMax |
long |
com.sun.star.util.Time |
R+W |
Maximální přijatelná vstupní hodnota. |
Čas |
long |
com.sun.star.util.Time |
R+(W) |
Aktuální hodnota |
TimeFormat |
integer |
|
R+W |
Formát času: |
DefaultTime |
long |
com.sun.star.util.Time |
R+W |
Výchozí hodnota. |
Měnové pole je číselné pole s následujícími dalšími možnostmi.
Tabulka 9: Vlastnosti měnového pole
Název |
Datový typ |
R/W |
Vlastnost |
CurrencySymbol |
string |
R+W |
Symbol měny pouze pro zobrazení. |
PrependCurrencySymbol |
boolean |
R+W |
Před číslem se zobrazí symbol. |
Formátovaný ovládací prvek lze použít podle potřeby pro čísla, měnu nebo datum/čas. Platí zde velmi mnoho již popsaných vlastností, ale s jinými názvy.
Tabulka 10: Vlastnosti formátovaného pole
Název |
Datový typ |
L/S |
Vlastnost |
CurrentValue |
varianta |
R |
Aktuální hodnota obsahu. Skutečný typ dat závisí na jejich obsahu a formátu. |
EffectiveValue |
R+(W) |
||
EffectiveMin |
double |
R+W |
Minimální přijatelná vstupní hodnota. |
EffectiveMax |
double |
R+W |
Maximální přijatelná vstupní hodnota. |
EffectiveDefault |
varianta |
R+W |
Výchozí hodnota. |
FormatKey |
long |
R+(W) |
Formát pro zobrazení a zadání. Pomocí makra jej nelze jednoduše změnit. |
EnforceFormat |
boolean |
R+W |
Formát se testuje při zadávání. Povoleny jsou pouze určité znaky a kombinace. |
Přístup ke čtení a zápisu hodnoty ležící za vybraným řádkem je poněkud komplikovaný, ale možný.
Tabulka 11: Vlastnosti seznamu
Název |
Datový typ |
R/W |
Vlastnost |
ListSource |
pole řetězců |
R+W |
Zdroj dat: Zdroj obsahu seznamu nebo název datové sady, která poskytuje viditelnou položku. |
ListSourceType |
integer |
R+W |
Typ zdroje dat: |
StringItemList |
pole řetězců |
R |
Seznam položek, které lze vybrat. |
ItemCount |
integer |
R |
Počet dostupných položek seznamu |
ValueItemList |
pole řetězců |
R |
Seznam hodnot, které mají být předány z formuláře do tabulky. |
DropDown |
boolean |
R+W |
Rozevírací seznam. |
LineCount |
integer |
R+W |
Celkový počet zobrazených řádků při úplném rozbalení. |
MultiSelection |
boolean |
R+W |
Určeno pro vícenásobný výběr. |
SelectedItems |
pole celých čísel |
R+W |
Seznam vybraných položek jako seznam pozic v celkovém seznamu položek. |
První vybraný prvek z pole seznamu se získá takto:
oControl = oForm.getByName("Name of the Listbox")
sEintrag = oControl.ValueItemList( oControl.SelectedItems(0) )
Poznámka
Od verze LibreOffice 4.1 lze hodnotu předanou do databáze určit přímo.
oControl = oForm.getByName("Name of the Listbox")
iD = oControl.getCurrentValue()
getCurrentValue() vrací hodnotu, která bude uložena v databázové tabulce. U polí se seznamem to závisí na poli, ke kterému jsou vázány ( BoundField ).
Až do verze LibreOffice 4.0 včetně vracela tato funkce zobrazený obsah, nikoli základní hodnotu v tabulce.
Vezměme prosím na vědomí, že položka je „pole řetězců“, pokud se dotaz na pole seznamu vymění za omezení možnosti výběru:
Sub Listenfeldfilter
Dim stSql(0) As String
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm As Object
Dim oFeld As Object
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm = oDrawpage.forms.getByName("MainForm")
oFeld = oForm.getByname("Listenfeld")
stSql(0) = "SELECT ""Name"", ""ID"" FROM ""Filter_Name"" ORDER BY ""Name"""
oFeld.ListSource = stSql
oFeld.refresh
End Sub
Přestože mají podobné funkce jako seznamy, vlastnosti polí se seznamem se poněkud liší. Viz příklad „Pole se seznamem jako seznamy s možností zadání“ na straně 1.
Tabulka 12: Vlastnosti pole se seznamem
Název |
Datový typ |
R/W |
Vlastnost |
Automatické dokončování |
boolean |
R+W |
Vyplňuje se automaticky. |
StringItemList |
pole řetězců |
R+W |
Položky seznamu, které jsou k dispozici k použití. |
ItemCount |
integer |
R |
Počet dostupných položek seznamu. |
DropDown |
boolean |
R+W |
Rozevírací seznam. |
LineCount |
integer |
R+W |
Počet řádků zobrazených při rozbalení. |
Text |
string |
R+W |
Aktuálně zobrazený text. |
DefaultText |
string |
R+W |
Výchozí položka. |
ListSource |
string |
R+W |
Název zdroje dat, který poskytuje položky seznamu. |
ListSourceType |
integer |
R+W |
Typ zdroje dat. Stejné možnosti jako u polí se seznamem (pouze výběr seznamu hodnot je ignorován). |
Lze použít také tlačítka volby.
Tabulka 13: Vlastnosti zaškrtávacích políček a přepínačů
Název |
Datový typ |
R/W |
Vlastnost |
Popisek |
string |
R+W |
Název (štítek) |
Stav |
short |
R+W |
Stav |
MultiLine |
boolean |
R+W |
Zalomení řádků pro dlouhý text. |
Kromě vlastností pro jednoduchý text jsou zajímavé následující:
Tabulka 14: Vlastnosti pole vzorku
Název |
Datový typ |
R/W |
Vlastnost |
EditMask |
string |
R+W |
Vstupní maska. |
LiteralMask |
string |
R+W |
Maska znaků. |
StrictFormat |
boolean |
R+W |
Testování formátu při zadávání. |
Tabulka 15: Vlastnosti prvku tabulky
Název |
Datový typ |
R/W |
Vlastnost |
Počet |
long |
R |
Počet sloupců. |
ElementNames |
pole řetězců |
R |
Seznam názvů sloupců. |
HasNavigationBar |
boolean |
R+W |
K dispozici je navigační panel. |
RowHeight |
long |
R+W |
Výška řádku. |
Tabulka 16: Vlastnosti pevného textu / popisku
Název |
Datový typ |
R/W |
Vlastnost |
Popisek |
string |
R+W |
Zobrazený text. |
MultiLine |
boolean |
R+W |
Zalomení řádků pro dlouhý text. |
Pro skupinové rámečky, které se běžně zpracovávají pomocí maker, nejsou k dispozici žádné vlastnosti. Důležitý je stav jednotlivých polí možností.
CommandButton nebo ImageButton
Tabulka 17: Vlastnosti příkazového a obrazového tlačítka
Název |
Datový typ |
R/W |
Vlastnost |
Popisek |
string |
R+W |
Nadpis – Text popisku. |
Stav |
short |
R+W |
Výchozí stav vybraný pro přepínání. |
MultiLine |
boolean |
R+W |
Zalomení řádků pro dlouhý text. |
DefaultButton |
boolean |
R+W |
Zda se jedná o výchozí tlačítko. |
Další vlastnosti a metody spojené s navigací – například filtry a změna ukazatele záznamu – se ovládají pomocí formuláře.
Tabulka 18: Vlastnosti lišty navigace
Název |
Datový typ |
R/W |
Vlastnost |
IconSize |
short |
R+W |
Velikost ikon. |
boolean |
R+W |
Polohu lze zadat a zobrazí se. |
|
ShowNavigation |
boolean |
R+W |
Umožňuje navigaci. |
ShowRecordActions |
boolean |
R+W |
Umožňuje provádět záznamové akce. |
boolean |
R+W |
Umožňuje třídění podle filtru. |
Datový typ parametru je označen zkratkou:
číslo sloupce pro požadované pole v datovém souboru, počítáno od 1.
číselná hodnota – může to být celé nebo desetinné číslo.
s – String; maximální délka závisí na definici tabulky.
b – Boolean (logický) – true nebo false
d – Hodnota data
Tyto metody fungují jak ve formulářích, tak v sadě výsledků dotazu.
„Kurzor“ v popisu znamená ukazatel záznamu.
Tabulka 19: Navigační metody: Testování polohy kurzoru
Název |
Datový typ |
Popis |
isBeforeFirst |
boolean |
Kurzor je před prvním záznamem. To platí v případě, že po zadání ještě nebyl vynulován. |
isFirst |
boolean |
Zobrazí, zda je kurzor na prvním záznamu. |
isLast |
boolean |
Zobrazí, zda je kurzor na posledním záznamu. |
isAfterLast |
boolean |
Kurzor je po přesunutí na další řádek za posledním řádkem. |
getRow |
long |
Aktuální číslo řádku. |
Tabulka 20: Navigační metody: Nastavení kurzoru
Pro logické datové typy znamená True, že navigace proběhla úspěšně.
Název |
Datový typ |
Popis |
beforeFirst |
– |
Přesune se před první řádek. |
first |
boolean |
Přesune se na první řádek. |
previous |
boolean |
Vrací se o jeden řádek zpět. |
next |
boolean |
Přesune se o jeden řádek dopředu. |
last |
boolean |
Přejde na poslední záznam. |
afterLast |
– |
Přejde po posledním záznamu. |
absolute(n) |
boolean |
Přejde na řádek se zadaným číslem řádku. |
relative(n) |
boolean |
Přejde zpět nebo dopředu o zadanou hodnotu: dopředu kladná hodnota a dozadu pro záporná hodnota argumentu. |
Tabulka 21: Navigační metody: Metody ovlivňující aktuální stav záznamu
Název |
Datový typ |
Popis |
refreshRow |
– |
Zpětně načte původní hodnoty řádku. |
rowInserted |
boolean |
Označuje, zda se jedná o nový řádek. |
rowUpdated |
boolean |
Ukazuje, zda byl aktuální řádek změněn. |
rowDeleted |
boolean |
Ukazuje, zda byl aktuální řádek smazán. |
Metody používané pro čtení jsou k dispozici pro jakýkoli formulář nebo soubor dat. Metody pro změnu a ukládání lze použít pouze pro upravitelné datové sady (obvykle tabulky, nikoli dotazy).
Tabulka 22: Metody pro úpravu řádků dat: Metody pro celý řádek
Název |
Datový typ |
Popis |
insertRow |
– |
Uloží nový řádek. |
updateRow |
– |
Potvrdí změnu aktuálního řádku. |
deleteRow |
– |
Odstraní aktuální řádek. |
cancelRowUpdates |
– |
Obrátí změny v aktuálním řádku. |
moveToInsertRow |
– |
Přesune kurzor na řádek odpovídající novému záznamu. |
moveToCurrentRow |
– |
Po zadání nového záznamu vrátí kurzor na předchozí pozici. |
Tabulka 23: Metody pro úpravu řádků dat: Čtení hodnot
Název |
Datový typ |
Popis |
getString(c) |
string |
Předává obsah sloupce jako řetězec znaků. |
getBoolean(c) |
boolean |
Předává obsah sloupce jako logickou hodnotu. |
getByte(c) |
byte |
Udává obsah sloupce jako jeden bajt. |
getShort(c) |
short |
Udává obsah sloupce jako celé číslo. |
getInt(c) |
integer |
Udává obsah sloupce jako celé číslo. |
getLong(c) |
long |
Udává obsah sloupce jako celé číslo. |
getFloat(c) |
float |
Udává obsah sloupce jako desetinné číslo s jednoduchou přesností. |
getDouble(c) |
double |
Udává obsah sloupce jako desetinné číslo s dvojnásobnou přesností. Díky automatickým převodům prováděným Basicem je tento typ vhodný pro desetinná a měnová pole. |
getBytes(c) |
pole bajtů |
Předává obsah sloupce jako pole jednotlivých bajtů. |
getDate(c) |
Datum |
Předává obsah sloupce jako datum. |
getTime(c) |
Čas |
Předává obsah sloupce jako časovou hodnotu. |
getTimestamp(c) |
DateTime |
Předává obsah sloupce jako časové razítko (datum a čas).
|
wasNull |
boolean |
Ukazuje, zda hodnota naposledy načteného sloupce byla NULL. |
Poznámka
V samotném jazyce Basic mají hodnoty data a času typ DATE. Pro přístup k datům v datových sadách jsou k dispozici různé typy: com.sun.star.util.Date pro datum, com.sun.star.util.Time pro čas a com.sun.star.util.DateTime pro časovou značku.
Tabulka 24: Metody ukládání hodnot
Název |
Datový typ |
Popis |
updateNull(c) |
– |
Nastaví obsah sloupce na hodnotu NULL. |
updateBoolean(c,b) |
– |
Změní obsah sloupce c na logickou hodnotu b. |
updateByte(c,x) |
– |
Uloží bajt x do sloupce c. |
updateShort(c,n) |
– |
Uloží celé číslo n do sloupce c. |
updateInt(c,n) |
– |
Uloží celé číslo n do sloupce c. |
updateLong(c,n) |
– |
Uloží celé číslo n do sloupce c. |
updateFloat(c,n) |
– |
Uloží desetinné číslo n do sloupce c. |
updateDouble(c,n) |
– |
Uloží desetinné číslo n do sloupce c. |
updateString(c,s) |
– |
Uloží řetězec s do sloupce c. |
updateBytes(c,x) |
– |
Uloží pole bajtů x do sloupce c. |
updateDate(c,d) |
– |
Uloží datum d do sloupce c. |
updateTime(c,d) |
– |
Uloží čas d do sloupce c. |
updateTimestamp(c,d) |
– |
Uloží časové razítko d do sloupce c. |
Tato metoda používá vlastnost BoundField ovládacího prvku ke čtení nebo úpravě obsahu příslušného sloupce. Odpovídá téměř přesně metodě popsané v předchozí části s tím rozdílem, že se neuvádí číslo sloupce.
Tabulka 25: Metody úprav jednotlivých hodnot: čtení hodnot
Název |
Datový typ |
Popis |
getString |
string |
Předává obsah pole jako řetězec znaků. |
getBoolean |
boolean |
Předává obsah pole jako logickou hodnotu. |
getByte |
byte |
Předává obsah pole jako jeden bajt. |
getShort |
short |
Udává obsah pole jako celé číslo. |
getInt |
integer |
Udává obsah pole jako celé číslo. |
getLong |
long |
Udává obsah pole jako celé číslo. |
getFloat |
float |
Udává obsah pole jako desetinnou hodnotu s přesností na jedno desetinné místo. |
getDouble |
double |
Udává obsah pole jako desetinné číslo s přesností na dvě desetinná místa. Díky automatickým převodům prováděným Basicem je tento typ vhodný pro desetinná a měnová pole. |
getBytes |
pole bajtů |
Předává obsah pole jako pole bajtů. |
getDate |
Datum |
Udává obsah pole jako datum. |
getTime |
Čas |
Udává obsah pole jako čas. |
getTimestamp |
DateTime |
Udává obsah pole jako časové razítko. |
wasNull |
boolean |
Ukazuje, zda hodnota naposledy načteného sloupce byla NULL. |
Poznámka
V samotném jazyce Basic mají hodnoty data a času typ DATE. Pro přístup k datům v datových sadách jsou k dispozici různé typy: com.sun.star.util.Date pro datum, com.sun.star.util.Time pro čas a com.sun.star.util.DateTime pro časovou značku.
Tabulka 26: Metody úprav jednotlivých hodnot: ukládání hodnot
Název |
Datový typ |
Popis |
updateNull |
– |
Nastaví obsah sloupce na hodnotu NULL. |
updateBoolean(b) |
– |
Nastaví obsah sloupce na logickou hodnotu b. |
updateByte(x) |
– |
Uloží bajt x do sloupce. |
updateShort(n) |
– |
Uloží celé číslo n do sloupce. |
updateInt(n) |
– |
Uloží celé číslo n do sloupce. |
updateLong(n) |
– |
Uloží celé číslo n do sloupce. |
updateFloat(n) |
– |
Uloží do sloupce desetinné číslo n. |
updateDouble(n) |
– |
Uloží do sloupce desetinné číslo n. |
updateString(s) |
– |
Uloží řetězec znaků s do sloupce. |
updateBytes(x) |
– |
Uloží pole bajtů x do sloupce. |
updateDate(d) |
– |
Uloží datum d do sloupce. |
updateTime(d) |
– |
Uloží čas d do sloupce. |
updateTimestamp(d) |
– |
Uloží časové razítko d do sloupce. |
Metody, které přenášejí hodnotu předpřipraveného příkazu SQL (viz „Předpřipravené příkazy SQL s parametry“ na straně 1), jsou podobné jako v předchozí části. První parametr (označený I) je číslovaná pozice v příkazu SQL.
Tabulka 27: Metody přenosu hodnoty předpřipraveného příkazu SQL
Název |
Datový typ |
Popis |
setNull(i, n) |
– |
Nastaví obsah sloupce na hodnotu NULL. N je datový typ SQL, jak je uveden v Popisu API. |
setBoolean(i, b) |
– |
Vloží do příkazu SQL zadanou logickou hodnotu b. |
setByte(i, x) |
– |
Vloží zadaný bajt x do příkazu SQL. |
setShort(i, n) |
– |
Vloží do příkazu SQL zadané celé číslo n. |
setInt(i, n) |
– |
Vloží do příkazu SQL zadané celé číslo n. |
setLong(i, n) |
– |
Vloží do příkazu SQL zadané celé číslo n. |
setFloat(i, n) |
– |
Vloží zadané desetinné číslo do příkazu SQL. |
setDouble(i, n) |
||
setString(i, s) |
– |
Vloží zadaný řetězec znaků do příkazu SQL. |
setBytes(i, x) |
– |
Vloží zadané pole bajtů x do příkazu SQL. |
setDate(i, d) |
– |
Vloží zadané datum d do příkazu SQL. |
setTime(i, d) |
– |
Vloží do příkazu SQL zadaný čas d. |
setTimestamp(i, d) |
– |
Vloží do příkazu SQL zadané časové razítko d. |
clearParameters |
– |
Odstraní předchozí hodnoty všech parametrů příkazu SQL. |
U této první kategorie použití maker si ukážeme různé možnosti, jak zlepšit použitelnost formulářů aplikace Base.
Často se ve formuláři něco změní a tato změna se musí objevit v druhém formuláři na stejné stránce. Následující úryvek kódu zavolá metodu Reload druhého formuláře a způsobí jeho obnovení.
Sub Update
Nejprve je makro pojmenováno. Výchozí označení makra je Sub. Může být napsáno velkými nebo malými písmeny. Sub umožňuje spuštění podprogramu bez vrácení hodnoty. Dále je naopak popsána funkce, která vrací hodnotu.
Makro má název Update. Proměnné nemusíme deklarovat, protože LibreOffice Basic automaticky vytváří proměnné při jejich použití. Pokud proměnnou napíšeme špatně, LibreOffice Basic vytvoří novou proměnnou, aniž by si stěžoval. Použijeme Option Explicit chceme-li LibreOffice Basicu zabránit v automatickém vytváření proměnných; většina programátorů tento postup doporučuje.
Proto obvykle začínáme deklarací proměnných. Všechny zde deklarované proměnné jsou objekty (nikoli čísla nebo text), proto na konec deklarace přidáme As Object. Abychom si později připomněli typ proměnných, uvádíme jejich názvy s písmenem "o". V zásadě si však můžeme zvolit téměř libovolné názvy proměnných.
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm As Object
Formulář leží v aktuálně aktivním dokumentu. Kontejner, ve kterém jsou uloženy všechny formuláře, se jmenuje drawpage. V navigátoru formulářem se jedná o koncept nejvyšší úrovně, kterému jsou všechny formuláře podřízeny.
V tomto příkladu je formulář, ke kterému se má přistupovat, pojmenován Display. Display je název viditelný v navigátoru formulářem. Tak například první formulář se ve výchozím nastavení jmenuje Form1.
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm = oDrawpage.forms.getByName("Display")
Protože je nyní formulář zpřístupněn a bod, ve kterém je přístupný, je uložen v proměnné oForm, je nyní znovu načten (obnoven) příkazem reload().
oForm.reload()
End Sub
Podprogram začíná SUB, takže musí končit End Sub.
Toto makro lze nyní vybrat ke spuštění při uložení jiného formuláře. Například v pokladně, pokud se do jednoho formuláře zadá celkový počet prodaných položek a jejich skladová čísla (načtená snímačem čárových kódů), může se v jiném formuláři ve stejném otevřeném okně zobrazit název všech položek a celková cena, jakmile se formulář uloží.
Samotný filtr může bez problémů fungovat v podobě popsané v kapitole 8, Úlohy databáze. Níže uvedená varianta nahrazuje tlačítko Uložit a znovu načítá seznamy, takže zvolený filtr z jednoho seznamu může omezit možnosti dostupné v druhém seznamu.
Poznámka
Viz také databáze Example_Search_and_Filter.odb související s touto knihou.
Sub Filter
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm1 As Object
Dim oForm2 As Object
Dim oFieldList1 As Object
Dim oFieldList2 As Object
oDoc = thisComponent
oDrawpage = oDoc.drawpage
Nejprve jsou definovány a nastaveny proměnné pro přístup k sadě formulářů. Tato sada obsahuje dva formuláře "Filter" a "Display". Pole seznamu jsou ve formuláři "Filter" a mají názvy "List_1" a "List_2".
oForm1 = oDrawpage.forms.getByName("filter")
oForm2 = oDrawpage.forms.getByName("display")
oFieldList1 = oForm1.getByName("listbox1")
oFieldList2 = oForm1.getByName("listbox2")
Nejprve se obsah polí se seznamem přenese do základního formuláře pomocí commit(). Přenos je nutný, protože jinak by se změna v poli se seznamem při ukládání neprojevila. Instrukci commit() je třeba použít pouze na poli se seznamem, ke kterému byl právě uskutečněn přístup. Poté se záznam uloží pomocí updateRow(). Naše filtrační tabulka obsahuje v zásadě pouze jeden záznam, který je zapsán jednou na začátku. Tento záznam je proto průběžně přepisován pomocí příkazu update.
oFieldList1.commit()
oFieldList2.commit()
oForm1.updateRow()
Pole se seznamem se mají navzájem ovlivňovat. Pokud například jedno pole se seznamem slouží k omezení zobrazených médií na CD, druhé pole se seznamem by nemělo zahrnovat všechny autory knih ve svém seznamu autorů. Výběr v druhém seznamu by pak příliš často vedl k prázdnému filtru. To je důvod, proč je třeba seznamy znovu načíst. Přesně řečeno, příkaz refresh() je třeba provést pouze na seznamu, který nebyl otevřen.
Poté se znovu načte form2, který má zobrazit filtrovaný obsah.
oFieldList1.refresh()
oFieldList2.refresh()
oForm2.reload()
End Sub
Pole se seznamem, která mají být touto metodou ovlivněna, mohou být doplněna pomocí různých dotazů.
Nejjednodušší variantou je, že pole seznamu přebírá svůj obsah z výsledků filtru. Jediný filtr pak určuje, který obsah dat bude dále filtrován.
SELECT "Field_1" || ' - ' || "Count" AS "Display", "Field_1"
FROM ( SELECT COUNT( "ID" ) AS "Count", "Field_1" FROM "searchtable" GROUP BY "Field_1" )
ORDER BY "Field_1"
Zobrazí se obsah pole a počet nálezů. K získání počtu shod se používá dílčí dotaz. To je nezbytné, protože jinak se v seznamu zobrazí pouze počet shod bez dalších informací z pole.
Makro touto akcí poměrně rychle vytvoří seznamy, které jsou vyplněny pouze jednou hodnotou. Pokud pole se seznamem není NULL, bere se při filtrování v úvahu. Po aktivaci druhého pole se seznamem jsou v obou polích se seznamem k dispozici pouze prázdná pole a jedna zobrazená hodnota. To se může zdát praktické pro omezené vyhledávání. Ale co když knihovní katalog jasně ukazuje zařazení položky, ale neukazuje jednoznačně, zda se jedná o knihu, CD nebo DVD? Pokud je nejprve vybrána klasifikace a poté je druhé pole seznamu nastaveno na "CD", musí být pro následné vyhledávání zahrnující knihy nastaveno na NULL. Bylo by praktičtější, kdyby se v druhém seznamu přímo zobrazovaly různé dostupné typy médií s odpovídajícím počtem položek.
K dosažení tohoto cíle je sestaven následující dotaz, který již nevychází přímo z výsledků filtru. Počet odpovídajících položek je třeba získat jiným způsobem.
SELECT
IFNULL( "Field_1" || ' - ' || "Count", 'empty - ' || "Count" ) AS "Display",
"Field_1"
FROM
( SELECT COUNT( "ID" ) AS "Count", "Field_1" FROM "Table"
WHERE "ID" IN
( SELECT "Table"."ID" FROM "Filter", "Table"
WHERE "Table"."Field_2" = IFNULL( "Filter"."Filter_2",
"Table"."Field_2" ) )
GROUP BY "Field_1" )
ORDER BY "Field_1"
Tento velmi složitý dotaz lze rozdělit. V praxi se běžně používá VIEW pro poddotaz. Pole se seznamem získává svůj obsah z dotazu vztahujícího se k tomuto VIEW.
Podrobný dotaz: Dotaz obsahuje dva sloupce. První sloupec obsahuje zobrazení, které vidí osoba s otevřeným formulářem. Tento pohled ukazuje obsah pole a shody pro obsah tohoto pole oddělené pomlčkou. Druhý sloupec přenáší svůj obsah do základní tabulky formuláře. Zde máme k dispozici pouze obsah pole. Pole se seznamem tak čerpají svůj obsah z dotazu, který je ve formuláři prezentován jako výsledek filtru. Pouze tato pole jsou k dispozici pro další filtrování.
Tabulka, ze které se tyto informace čerpají, je vlastně dotaz. V tomto dotazu se počítají pole primárního klíče (SELECT COUNT("ID" ) AS "Count"). Ta se pak seskupí podle hledaného výrazu v poli (GROUP BY "Field_1"). Tento dotaz zobrazuje termín v samotném poli jako druhý sloupec. Tento dotaz je zase založen na dalším poddotazu:
SELECT "Table"."ID" FROM "Filter", "Table"
WHERE "Table"."Field_2" =
IFNULL( "Filter"."Filter_2", "Table"."Field_2" )
Tento poddotaz se zabývá dalším filtrovaným polem. Toto další pole musí v zásadě také odpovídat primárnímu klíči. Pokud existují další filtry, lze tento dotaz rozšířit:
SELECT "Table"."ID" FROM "Filter", "Table" WHERE
"Table"."Field_2" = IFNULL( "Filter"."Filter_2", "Table"."Field_2" )
AND
"Table"."Field_3" = IFNULL( "Filter"."Filter_3", "Table"."Field_3" )
To umožňuje, aby všechna další pole, která mají být filtrována, kontrolovala, co se nakonec zobrazí v seznamu prvního pole "Field_1".
Nakonec je celý dotaz seřazen podle základního pole.
Jak vlastně vypadá výsledný dotaz, který je základem zobrazeného formuláře, se dozvíme v kapitole 8, Úlohy databáze.
Následující makro může prostřednictvím pole se seznamem řídit, která pole se seznamem se musí uložit a která se musí znovu načíst.
Následující podprogram předpokládá, že vlastnost Další informace pro každé pole se seznamem obsahuje čárkou oddělený seznam všech názvů polí se seznamem bez mezer. První název v seznamu musí být název tohoto pole se seznamem.
Sub Filter_more_info(oEvent As Object)
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm1 As Object
Dim oForm2 As Object
Dim sTag As String
sTag = oEvent.Source.Model.Tag
Vytvoří se pole (kolekce dat přístupná pomocí indexového čísla) a naplní se názvy polí se seznamem. První název v seznamu je název pole seznamu spojeného s událostí.
aList() = Split(sTag, ",")
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm1 = oDrawpage.forms.getByName("filter")
oForm2 = oDrawpage.forms.getByName("display")
Pole je procházeno od své dolní hranice ('Lbound()') k horní hranici ('Ubound()') v jedné smyčce. Všechny hodnoty, které byly v doplňkových informacích odděleny čárkami, se nyní přenášejí postupně.
For i = LBound(aList()) To UBound(aList())
If i = 0 Then
Pole se seznamem, které makro spustilo, musí být uloženo. Nachází se v proměnné aList(0). Nejprve se informace pro pole seznamu přenesou do základní tabulky a poté se záznam uloží.
oForm1.getByName(aList(i)).commit()
oForm1.updateRow()
Else
Ostatní seznamy je třeba obnovit, protože nyní obsahují různé hodnoty v závislosti na prvním seznamu.
oForm1.getByName(aList(i)).refresh()
End If
Next
oForm2.reload()
End Sub
Dotazy pro toto použitelnější makro jsou přirozeně stejné jako ty, které již byly uvedeny v předchozí části.
Při ukládání dat do příkazu SQL mohou apostrofy v názvech, například „O'Connor“, způsobit problémy. Je to proto, že jednoduché uvozovky ('') se používají k uzavření textu, který má být vložen do záznamů. V takových případech potřebujeme zprostředkující funkci, která data vhodně připraví.
Function String_to_SQL(st As StringString)
If InStr(st,"'") Then
st = Join(Split(st,"'"),"''")
End If
String_to_SQL = st
End Function
Všimneme si, že se jedná o funkci, nikoli o podřízený prvek. Funkce přijímá jako argument hodnotu a poté vrací hodnotu.
V textu, který se má přenést, se nejprve vyhledá, zda neobsahuje apostrof. V takovém případě se text v tomto místě rozdělí – apostrof je sám o sobě oddělovačem – a opět se spojí dvěma apostrofy. Tím se zakryje kód SQL. Výsledek funkce se získá následujícím voláním:
stTextnew = String_to_SQL(stTextold)
To jednoduše znamená, že proměnná stTextold se přepracuje a výsledek se uloží do proměnné stTextnew. Tyto dvě proměnné nemusí mít ve skutečnosti odlišné názvy. Volání lze provést pomocí:
stText = String_to_SQL(stText)
Tato funkce se opakovaně používá v následujících makrech, aby bylo možné apostrofy ukládat také pomocí příkazů SQL.
Hodnoty, které lze vypočítat pomocí databázových funkcí, nejsou v databázi uloženy samostatně. Výpočet neprobíhá během zadávání do formuláře, ale až po uložení záznamu. Pokud se formulář skládá pouze z jednoho ovládacího prvku tabulky, je to jen malý rozdíl. Vypočtenou hodnotu lze odečíst ihned po zadání údajů. Pokud však formuláře obsahují sadu různých jednotlivých polí, nemusí být předchozí záznam viditelný. V takových případech má smysl, aby se hodnoty, které se jinak počítají uvnitř databáze, zobrazovaly v příslušných polích.
Poznámka
Viz databáze Example_direct_Calculation_Form.odb spojená s touto knihou.
Následující tři makra ukazují, jak lze takovou věc v zásadě provést. Obě makra jsou spojena s výstupem z daného pole. To také umožňuje zohlednit skutečnost, že hodnota v existujícím poli může být následně změněna.
Sub Calculation_without_Tax(oEvent As Object)
Dim oForm As Object
Dim oField As Object
Dim oField2 As Object
oField = oEvent.Source.Model
oForm = oField.Parent
oField2 = oForm.getByName("price_without_tax")
oField2.BoundField.UpdateDouble(oField.getCurrentValue / 1.19)
If Not IsEmpty(oForm.getByName("quantity").getCurrentValue()) Then
total_calc2(oForm.getByName("quantity"))
End If
End Sub
Pokud je do pole Price zadána hodnota, makro se spustí při opuštění tohoto pole. Ve stejném formuláři jako pole Price je pole nazvané price_without_tax. Pro toto pole se použije BoundField.UpdateDouble pro výpočet ceny bez DPH. Datové pole je odvozeno z dotazu, který v zásadě provádí stejný výpočet, ale s použitím uložených dat. Tímto způsobem je vypočtená hodnota viditelná při zadávání dat a také později při procházení záznamu, aniž by byla uložena.
Pokud pole quantity obsahuje hodnotu, provede se další výpočet pro pole, která jsou s ním svázána.
Sub Calculation_Total(oEvent As Object)
oField = oEvent.Source.Model
Calculation_Total2(oField)
End Sub
Tento krátký postup slouží pouze k přenosu řešení následujícího postupu při opuštění pole quantity na formuláři.
Sub Calculation_Total2(oFeld As Object)
Dim oForm As Object
Dim oField2 As Object
Dim oField3 As Object
Dim oField4 As Object
oForm = oFeld.Parent
oField2 = oForm.getByName("price")
oField3 = oForm.getByName("total")
oField4 = oForm.getByName("tax_total")
oField3.BoundField.UpdateDouble(oField.getCurrentValue * oField2.getCurrentValue)
oField4.BoundField.UpdateDouble(oField.getCurrentValue * oField2.getCurrentValue -
oField.getCurrentValue * oField2.getCurrentValue / 1.19)
End Sub
Tento postup je pouze způsob, jak ovlivnit několik polí najednou. Postup se spouští z jednoho pole quantity, které obsahuje počet nakoupených položek. Pomocí tohoto pole a pole price se vypočítá celková částka a tax_total (daň celkem, pozn. překl.) a přenese se do příslušných polí.
Tyto postupy a dotazy mají jeden nedostatek: sazba DPH je v programu zakódována napevno. Bylo by lepší použít argument související s cenou, protože DPH se může lišit a nemusí být u všech výrobků stejná. V takových případech by bylo třeba příslušnou hodnotu DPH vyčíst z pole formuláře.
LibreOffice verze 4.1 přinesl některé změny v polích se seznamem a hodnotách data, kvůli kterým je nutné při spouštění maker v těchto oblastech určit aktuální verzi. K tomuto účelu slouží následující kód:
Function OfficeVersion()
Dim aSettings, aConfigProvider
Dim aParams2(0) As New com.sun.star.beans.PropertyValue
Dim sProvider$, sAccess$
sProvider = "com.sun.star.configuration.ConfigurationProvider"
sAccess = "com.sun.star.configuration.ConfigurationAccess"
aConfigProvider = createUnoService(sProvider)
aParams2(0).Name = "nodepath"
aParams2(0).Value = "/org.openoffice.Setup/Product"
aSettings = aConfigProvider.createInstanceWithArguments(sAccess, aParams2())
OfficeVersion() = Array(aSettings.ooName,aSettings.ooSetupVersionAboutBox)
End Function
Tato funkce vrací pole, jehož prvním prvkem je LibreOffice a druhým úplné číslo verze, například 4.1.5.2.
Od verze LibreOffice 4.1 se do databáze ukládá hodnota vrácená polem se seznamem do pole CurrentValue. V předchozích verzích, ani v OpenOffice nebo Apache OpenOffice tomu tak nebylo. Výpočet provede následující funkce. Je třeba zkontrolovat, zda verze LibreOffice není novější než LibreOffice 4.0.
Function ID_Determination(oField As Object) As Integer
a() = OfficeVersion()
If a(0) = "LibreOffice" And (LEFT(a(1),1) = 4 And RIGHT(LEFT(a(1),3),1) > 0) Or LEFT(a(1),1) > 4 Then
stContent = oField.currentValue
Else
Před verzí LibreOffice 4.1 se předávaná hodnota načítala ze seznamu hodnot pole se seznamem. Viditelně vybraný záznam je SelectedItems(0). '0', protože v seznamu lze vybrat několik dalších hodnot.
stContent = oField.ValueItemList(oField.SelectedItems(0))
End If
If IsEmpty(stContent) Then
-1 je hodnota, která se nepoužívá jako automatická hodnota, a proto nebude existovat ve většině tabulek jako cizí klíč.
ID_Determination = -1
Else
ID_Determination = Cint(stContent)
Převod na celé číslo
End If
End Function
Funkce přenáší hodnotu jako celé číslo. Většina primárních klíčů jsou automaticky se zvětšující celá čísla. Pokud cizí klíč toto kritérium nesplňuje, musí být návratová hodnota upravena na příslušný typ.
Zobrazenou hodnotu pole se seznamem lze dále určit pomocí vlastnosti zobrazení pole.
Sub Listfielddisplay
Dim oDoc As Object
Dim oForm As Object
Dim oListbox As Object
Dim oController As Object
Dim oView As Object
oDoc = thisComponent
oForm = oDoc.Drawpage.Forms(0)
oListbox = oForm.getByName("Listbox")
oController = oDoc.getCurrentController()
oView = oController.getControl(oListbox)
print "Displayed content: " & oView.SelectedItem
End Sub
Kontrolér slouží k přístupu k zobrazení formuláře. To určuje, co se zobrazí ve vizuálním rozhraní. Vybraná hodnota je SelectedItem.
Někdy se může stát, že obsah polí se seznamem naroste do příliš velkých rozměrů. V takových případech je pro urychlení vyhledávání vhodné omezit obsah pole seznamu na hodnoty uvedené zadáním jednoho nebo více počátečních znaků. Samotné pole se seznamem je opatřeno příkazem SQL, který slouží jako zástupný příkaz. Může to být:
SELECT "Name", "ID" FROM "Table" ORDER BY "Name" LIMIT 5
Tím se zabrání tomu, aby aplikace Base musela při otevření formuláře načítat obrovský seznam hodnot.
Následující makro je propojeno s Vlastnosti: Vlastnosti: Pole se seznamem > Události > Klávesa uvolněna.
Global stListStart As String
Global lTime As Long
Nejprve se vytvoří globální proměnné. Tyto proměnné jsou nezbytné k tomu, aby bylo možné vyhledávat nejen jednotlivá písmena, ale po stisknutí dalších kláves také kombinace písmen.
Zadaná písmena se postupně ukládají do globální proměnné stListStart.
Globální proměnná lTime slouží k uložení aktuálního času v sekundách. Pokud je mezi jednotlivými stisky kláves dlouhá pauza, měla by se proměnná stListStart vynulovat. Z tohoto důvodu je dotazován časový rozdíl mezi po sobě následujícími záznamy.
Sub ListFilter(oEvent As Object)
oField = oEvent.Source.Model
If oEvent.KeyCode < 538 Then
Makro se spouští stiskem klávesy. V rámci rozhraní API má každý klíč číselný kód, který lze vyhledat v com::sun::star::awt::Key (skupiny konstant části rozhraní API).Speciální znaky jako ä, ö, a ü má kód 0. Všechna ostatní písmena a číslice mají kód KeyCode menší než 538.
Je důležité zkontrolovat KeyCode, protože stisknutí klávesy Tab pro přechod do jiného pole spustí také makro. KeyCode pro klávesu Tab je 1282, takže další kód v makru nebude proveden.
Dim stSql(0) As String
Kód SQL pro pole se seznamem je uložen v poli. Příkazy SQL se však počítají jako jednotlivé datové prvky, takže pole je dimenzováno jako stSql(0).
Při čtení kódu SQL z pole se seznamem si uvědomíme, že kód SQL není přímo přístupný jako text. Místo toho je kód k dispozici jako jeden prvek pole: oField.ListSource(0).
Po deklaraci proměnných pro budoucí použití se příkaz SQL rozdělí. Abychom získali pole, které má být filtrováno, rozdělíme kód na první čárku. Pole proto musí být v příkazu uvedeno jako první. Poté je tento kód opět rozdělen na první znak uvozovek, který zavádí název pole. Zde je to provedeno pomocí jednoduchých polí. Proměnná stField musí mít na začátku uvozovky. Kromě toho se používá Rtrim, aby se na konci výrazu nevyskytovala mezera.
Dim stText As String
Dim stField As String
Dim stQuery As String
Dim ar0()
Dim ar1()
ar0() = Split(oField.ListSource(0),",", 2)
ar1() = Split(ar0(0),"""", 2)
stFeld = """" & Rtrim(ar1(1))
Dále se v kódu SQL očekává instrukce třídění. Příkazy v jazyce SQL však mohou být ve velkých, malých nebo smíšených písmenech, proto se k nalezení řetězce znaků ORDER používá funkce inStr místo funkce Split. Poslední parametr této funkce je 1, což znamená, že vyhledávání by nemělo rozlišovat velká a malá písmena. Vše nalevo od řetězce ORDER se použije pro konstrukci nového kódu SQL. Tím je zajištěno, že kód může obsluhovat i pole se seznamem, která pocházejí z různých tabulek nebo byla definována v kódu SQL pomocí dalších podmínek.
stQuery = Left(oField.ListSource(0), inStr(1,oField.ListSource(0), "ORDER",1)-1)
If inStr(stQuery, "LOWER") > 0 Then
stQuery = Left(stQuery, inStr(stQuery, "LOWER")-1)
ElseIf inStr(1,stQuery, "WHERE",1) > 0 Then
stQuery = stQuery & " AND "
Else
stQuery = stQuery & " WHERE "
End If
Pokud dotaz obsahuje výraz LOWER, znamená to, že byl vytvořen pomocí této procedury ListFilter. Proto při konstrukci nového dotazu musíme jít pouze do této pozice.
Pokud tomu tak není a dotaz již obsahuje výraz WHERE (velkými nebo malými písmeny), je třeba k dalším podmínkám dotazu připojit AND.
Pokud není splněna ani jedna z těchto podmínek, připojí se ke stávajícímu kódu WHERE.
If lTime > 0 And Timer() - lTime < 5 Then
stListStart = stListStart & oEvent.KeyChar
Else
stListStart = oEvent.KeyChar
End If
lTime = Timer()
Pokud je v globální proměnné uložena hodnota času a rozdíl mezi ní a aktuálním časem je menší než 5 sekund, připojí se zadané písmeno k předchozímu. V opačném případě je písmeno považováno za nový jednopísmenný záznam. Pole se seznamem bude poté znovu filtrováno podle této položky. Poté se aktuální čas uloží do lTime.
stText = LCase( stListStart & "%")
stSql(0) = stQuery + "LOWER("+stField+") LIKE '"+stText+"' ORDER BY "+stField+""
oFeld.ListSource = stSql
oField.refresh
End If
End Sub
Kód SQL je konečně sestaven. Verze obsahu pole s malými písmeny se porovná s verzí zadaného písmene (písmen) s malými písmeny. Kód se vloží do pole se seznamem a pole se aktualizuje tak, aby bylo možné vyhledat pouze filtrovaný obsah.
Function DateValue(oField As Object) As Date
a() = OfficeVersion()
If a(0) = "LibreOffice" And (LEFT(a(1),1) = 4 And RIGHT(LEFT(a(1),3),1) > 0)
Or LEFT(a(1),1) > 4 Then
Zde jsou zachyceny všechny verze LibreOffice od verze 4.1. Za tímto účelem se číslo verze rozdělí na jednotlivé prvky a zkontroluje se hlavní a vedlejší číslo verze. Tato funkce bude fungovat až do verze LibreOffice 9.
Dim stMonth As String
Dim stDay As String
stMonth = Right(Str(0) & Str(oField.CurrentValue.Month),2)
stDay = Right(Str(0) & Str(oField.CurrentValue.Day),2)
Datumswert = CDateFromIso(oField.CurrentValue.Year & stMonth & stDay)
Else
DateValue = CDateFromIso(oField.CurrentValue)
End If
End Function
Od verze LibreOffice 4.1.2 jsou data v ovládacích prvcích formuláře ukládána jako pole. To znamená, že aktuální hodnotu ovládacího prvku nelze použít k přístupu k samotnému datu. Má-li být datum dále použito v makrech, je třeba jej znovu vytvořit ze dne, měsíce a roku.
Záznamy v databázi můžeme prohledávat bez použití makra. Odpovídající dotaz, který je třeba nastavit, však může být velmi složitý. Makro může tento problém vyřešit pomocí smyčky.
Následující podprogram načte pole v tabulce, interně vytvoří dotaz, a nakonec vypíše seznam čísel primárních klíčů záznamů v tabulce, které jsou vyhledány pomocí tohoto vyhledávacího výrazu. V následujícím popisu je tabulka s názvem Searchtmp, která se skládá z pole primárního klíče s automatickým nárůstem (ID) a pole s názvem Nr., které obsahuje všechny primární klíče získané z prohledávané tabulky. Název tabulky je podprogramu zpočátku předáván jako proměnná.
Chceme-li získat správný výsledek, musí tabulka obsahovat hledaný obsah jako text, nikoli jako cizí klíče. V případě potřeby můžeme vytvořit VIEW, které makro použije.
Poznámka
Viz databáze Example_Search_and_Filter.odb související s touto knihou.
Sub Searching(stTable As String)
Dim oDataSource As Object
Dim oConnection As Object
Dim oSQL_Command As Object
Dim stSql As String
Dim oResult As Object
Dim oDoc As Object
Dim oDrawpage As Object
Dim oForm As Object
Dim oForm2 As Object
Dim oField As Object
Dim stContent As String
Dim arContent() As String
Dim inI As Integer
Dim inK As Integer
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm = oDrawpage.forms.getByName("searchform")
oField = oForm.getByName("searchtext")
stContent = oField.getCurrentValue()
stContent = LCase(stContent)
Obsah vyhledávacího textového pole je zpočátku převeden na malá písmena, takže následná vyhledávací funkce musí porovnávat pouze malá písmena.
oDataSource = ThisComponent.Parent.DataSource
oConnection = oDataSource.GetConnection("","")
oSQL_Command = oConnection.createStatement()
Nejprve je třeba zjistit, zda byl vyhledávací výraz skutečně zadán. Pokud je pole prázdné, předpokládá se, že vyhledávání není vyžadováno. Všechny záznamy se zobrazí bez dalšího vyhledávání.
Pokud byl zadán hledaný výraz, načtou se názvy sloupců z prohledávané tabulky, aby mohl dotaz přistupovat k polím.
If stContent <> "" Then
stSql = "SELECT ""COLUMN_NAME"" FROM ""INFORMATION_SCHEMA"".""SYSTEM_COLUMNS"" WHERE ""TABLE_NAME"" = '" + stTable + "' ORDER BY ""ORDINAL_POSITION"""
oResult = oSQL_Statement.executeQuery(stSql)
Poznámka
Vzorce SQL v makrech musí být nejprve umístěny do dvojitých uvozovek jako běžné znakové řetězce. Názvy polí a tabulek jsou uvnitř vzorce SQL již ve dvojitých uvozovkách. Pro vytvoření konečného kódu, který správně přenáší dvojité uvozovky, musí být názvy polí a tabulek opatřeny dvěma sadami těchto uvozovek.
stSql = "SELECT ""Name"" FROM ""Table"";"
se při zobrazení příkazem MsgBox stSql,
.SELECT "Name" FROM "Table";
Index pole, do kterého se zapisují názvy polí, je zpočátku nastaven na 0. Poté se začne číst dotaz. Protože velikost pole není známa, je třeba ji průběžně upravovat. Proto smyčka začíná 'ReDim Preserve arContent(inI)', aby se nastavila velikost pole a zároveň se zachoval jeho stávající obsah. Poté se načtou pole a index pole se zvýší o 1. Poté se pole znovu dimenzuje a lze do něj uložit další hodnotu.
InI = 0
While oResult.next
ReDim Preserve arContent(inI)
arContent(inI) = oResult.getString(1)
inI = inI + 1
Wend
stSql = "DROP TABLE ""searchtmp"" IF EXISTS"
oSQL_Command.executeUpdate (stSql)
Nyní je dotaz sestaven v rámci smyčky a následně aplikován na tabulku definovanou na začátku. Jsou povoleny všechny kombinace malých a velkých písmen, protože obsah pole v dotazu je převeden na malá písmena.
Dotaz je sestaven tak, aby výsledky skončily v tabulce "searchtmp". Předpokládá se, že primárním klíčem je první pole tabulky (arContent(0)).
stSql = "SELECT """+arContent(0)+""" INTO ""searchtmp"" FROM """ + stTable
+ """ WHERE "
For inK = 0 To (inI - 1)
stSql = stSql+"LCase("""+arContent(inK)+""") LIKE '%"+stContent+"%'"
If inK < (inI - 1) Then
stSql = stSql+" OR "
End If
Next
oSQL_Command.executeQuery(stSql)
Else
stSql = "DELETE FROM ""searchtmp"""
oSQL_Command.executeUpdate (stSql)
End If
Zobrazovací formulář je třeba znovu načíst. Jeho zdrojem dat je dotaz, v tomto případě Searchquery.
oForm2 = oDrawpage.forms.getByName("display")
oForm2.reload()
End Sub
Tím se vytvoří tabulka, která bude vyhodnocena dotazem. Pokud je to možné, dotaz by měl být sestaven tak, aby jej bylo možné následně upravovat. Je zobrazen vzorový dotaz:
SELECT * FROM "searchtable" WHERE "Nr." IN ( SELECT "Nr." FROM "searchtmp" ) OR "Nr." = CASE WHEN ( SELECT COUNT( "Nr." ) FROM "searchtmp" ) > 0 THEN '0' ELSE "Nr." END
Jsou zahrnuty všechny prvky searchtable včetně primárního klíče. V přímém dotazu se neobjevuje žádná jiná tabulka, proto není potřeba žádný primární klíč z jiné tabulky a výsledek dotazu zůstává editovatelný.
Primární klíč je v tomto příkladu uložen pod názvem Nr. Makro načte právě toto pole. Provede se počáteční kontrola, zda se obsah pole Nr. objeví v tabulce searchtmp. Operátor IN je kompatibilní s více hodnotami. Dílčí dotaz může poskytnout i několik záznamů.
Při větším množství dat se přiřazování hodnot pomocí operátoru IN rychle zpomaluje. Proto není dobré použít prázdné vyhledávací pole, abychom jednoduše přenesli všechna pole primárního klíče z tabulky searchtable do tabulky searchtmp a poté data zobrazovali stejným způsobem. Místo toho prázdné vyhledávací pole vytvoří prázdnou tabulku searchtmp, takže nejsou k dispozici žádné záznamy. To je účelem druhé poloviny podmínky:
OR "Nr." = CASE WHEN ( SELECT COUNT( "Nr." ) FROM "searchtmp" ) > 0 THEN '-1' ELSE "Nr." END
Pokud je v tabulce Searchtmp nalezen záznam, znamená to, že výsledek prvního dotazu je větší než 0. V tomto případě: "Nr." = '-1' (zde potřebujeme číslo, které se nemůže vyskytovat jako primární klíč, takže "-1 "je dobrá hodnota). Pokud je výsledkem dotazu přesně 0 (což je případ, kdy nejsou přítomny žádné záznamy), pak "Nr." = "Nr.". Tímto se vypíše každý záznam, který má Nr. a Nr. je primární klíč, což znamená všechny záznamy.
U rozsáhlého textového pole často není jasné, kde se vyskytují shody s hledaným výrazem. Bylo by hezké, kdyby formulář uměl zvýraznit zápasy. Mělo by to vypadat jako na obrázku 5.
Obrázek 5: Formulář pro zvýraznění shody při vyhledávání
K tomu, aby formulář takto fungoval, potřebujeme několik dalších položek v naší sadě triků.
Poznámka
Viz databáze Example_Autotext_Searchmarkin_Spelling.odb související s touto knihou.
Fungování takového vyhledávacího pole již bylo vysvětleno. Je vytvořena tabulka filtrů a formulář slouží k zápisu aktuálních hodnot jednoho záznamu do této tabulky. Hlavní formulář je opatřen obsahem pomocí dotazu, který vypadá takto:
SELECT "ID", "memo"
FROM "table"
WHERE LOWER ( "memo" ) LIKE '%' || LOWER (
( SELECT "searchtext" FROM "filter" WHERE "ID" = TRUE ) ) || '%'
Po zadání hledaného textu se zobrazí všechny záznamy v tabulce „Table“, které mají hledaný text v poli „memo“. Při vyhledávání se nerozlišují velká a malá písmena.
Pokud není zadán žádný vyhledávací text, zobrazí se všechny záznamy v tabulce. Jelikož je primární klíč této tabulky obsažen v dotazu, lze jej upravovat.
Obrázek 6: Nastavení typu textu na víceřádkový s formátováním
Ve formuláři je kromě pole ID pro primární klíč také pole s názvem MemoFormat, které bylo nakonfigurováno (pomocí Vlastnosti > Obecné > Typ textu > Víceřádkový s formátováním) tak, aby zobrazovalo barevný i černý text. Při pozorném zkoumání vlastností textového pole zjistíme, že karta Data nyní zmizela. Je to proto, že do pole nelze zadávat data s dodatečným formátováním, které databáze sama o sobě nedokáže uložit. Přesto je možné do tohoto pole dostat text, označit jej a po aktualizaci jej přenést pomocí makra.
Procedura ContentRead slouží k přenosu obsahu databázového pole „memo“ do formátovaného textového pole MemoFormat a k jeho formátování tak, aby byl zvýrazněn text odpovídající textu ve vyhledávacím poli.
Postup je vázán na Formulář > Události > Po změně záznamu.
Sub ContentRead(oEvent As Object)
Dim inMemo As Integer
Dim oField As Object
Dim stSearchtext As String
Dim oCursor As Object
Dim inSearch As Integer
Dim inSearchOld As Integer
Dim inLen As Integer
oForm = oEvent.Source
inMemo = oForm.findColumn("memo")
oField = oForm.getByName("MemoFormat")
oField.Text = oForm.getString(inMemo)
Nejprve jsou definovány proměnné. Poté se z formuláře vyhledá pole tabulky „memo“ a pomocí funkce getString() se načte text z očíslovaného sloupce. Ten se přenáší do pole, které lze formátovat, ale které nemá vazbu na databázi: MemoFormat.
První testy ukázaly, že se formulář otevřel, ale nástrojová lišta formuláře v dolní části se již nevytvořila. Proto byla do systému zabudována velmi krátká čekací doba 5/1000 sekund. Poté se zobrazený obsah načte z formuláře FormFilter (který je v hierarchii formulářů paralelní s formulářem Form).
Wait 5
stSearchtext = oForm.Parent.getByName("FormFilter").getByName("Search").Text
Aby bylo možné formátovat text, musí být v poli, které obsahuje text, vytvořen (neviditelný) TextCursor. Výchozí zobrazení textu používá 12bodové písmo serif, které se nemusí vyskytovat v jiných částech formuláře a nelze jej přímo přizpůsobit pomocí vlastností ovládacího prvku formuláře. Při tomto postupu se hned na začátku nastaví požadovaný vzhled textu. Pokud se tak nestane, mohou rozdíly ve formátování způsobit odříznutí horního okraje textu v poli. Při prvních testech byly čitelné pouze 2/3 prvního řádku.
Aby neviditelný kurzor označil text, nastaví se nejprve na začátek pole a poté na jeho konec. Argumentem je v obou případech true. Poté následují specifikace velikosti, tvaru, barvy a gramáže písma. Pak se kurzor vrátí na začátek.
oCursor = oField.createTextCursor()
oCursor.gotoStart(true)
oCursor.gotoEnd(true)
oCursor.CharHeight = 10
oCursor.CharFontName = "Arial, Helvetica, Tahoma"
oCursor.CharColor = RGB(0,0,0)
oCursor.CharWeight = 100.000000 'com::sun::star::awt::FontWeight
oCursor.gotoStart(false)
Pokud je v poli text a byl zadán požadavek na vyhledávání, je nyní tento text prohledáván, aby byl nalezen hledaný řetězec. Vnější smyčka se nejprve ptá, zda jsou tyto podmínky splněny; vnitřní smyčka zjišťuje, zda se hledaný řetězec skutečně nachází v textu v poli MemoFormat. Tato nastavení lze ve skutečnosti vynechat, protože dotaz, na němž je formulář založen, zobrazuje pouze text, který tyto podmínky splňuje.
If oField.Text <> "" And stSearchtext <> "" Then
If inStr(oField.Text, stSearchtext) Then
inSearch = 1
inSearchOld = 0
inLen = Len(stSearchtext)
V textu se hledá hledaný řetězec. To probíhá ve smyčce, která skončí, jakmile se nezobrazí žádná další shoda. InStr() vrací umístění prvního znaku hledaného řetězce v zadaném formátu zobrazení, nezávisle na velikosti písmen. Smyčka je řízena požadavkem, aby na konci každého cyklu byl začátek inSearch zvýšen o 1 (-1 v prvním řádku smyčky a +2 v posledním řádku). V každém cyklu se kurzor přesune na počáteční pozici bez označení pomocí oCursor.goRight(Position, false) a poté doprava s označením podle délky hledaného řetězce. Poté se použije požadované formátování (modré a poněkud tučnější) a kurzor se přesune zpět do výchozího bodu pro další běh.
Do While inStr(inSearch, oField.Text, stSearchtext) > 0
inSearch = inStr(inSearch, oField.Text, stSearchtext) - 1
oCursor.goRight(inSearch-inSearchOld,false)
oCursor.goRight(inLen,true)
oCursor.CharColor = RGB(102,102,255)
oCursor.CharWeight = 110.000000
oCursor.goLeft(inLen,false)
inSearchOld = inSearch
inSearch = inSearch + 2
Loop
End If
End If
End Sub
Procedura ContentWrite slouží k přenosu obsahu textového pole MemoFormat do databáze. To probíhá nezávisle na tom, zda dojde k nějaké změně.
Postup je vázán na Formulář > Události > Před změnou záznamu.
Sub ContentWrite(oEvent As Object)
Dim oForm As Object
Dim inMemo As Integer
Dim loID As Long
Dim oField As Object
Dim stMemo As String
oForm = oEvent.Source
If InStr(oForm.ImplementationName, "ODatabaseForm") Then
Spouštěcí událost je implementována dvakrát. Správný přístup k záznamu umožňuje pouze název implementace, který končí na OdatabaseForm (implementace jsou vysvětleny na straně 1).
If Not oForm.isBeforeFirst() And Not oForm.isAfterLast() Then
Při načítání formuláře nebo při opětovném načtení stojí kurzor před aktuálním záznamem. Pokud se o to pokusíme, zobrazí se zpráva „Invalid cursor status“.
inMemo = oForm.findColumn("memo")
loID = oForm.findColumn("ID")
oField = oForm.getByName("MemoFormat")
stMemo = oField.Text
If stMemo <> "" Then
oForm.updateString(inMemo,stMemo)
End If
If stMemo <> "" And oForm.getString(loID) <> "" Then
oForm.UpdateRow()
End If
End If
End If
End Sub
Pole tabulky „memo“ se nachází ve zdroji dat formuláře spolu s polem „ID“. Pokud pole MemoFormat obsahuje text, přenese se do pole Memo zdroje dat pomocí oForm.updateString(). Pouze pokud je v poli ID záznam (jinými slovy byl nastaven primární klíč), následuje aktualizace. V opačném případě je nový záznam vložen běžnou prací s formulářem; formulář změnu rozpozná a uloží ji samostatně.
Toto makro lze použít pro víceřádková formátovaná textová pole. Stejně jako v předchozí kapitole je třeba nejprve zapsat obsah každého záznamu a poté lze nový záznam načíst do ovládacího prvku formuláře. Procedury TransferContent a WriteContent se liší pouze v tom, v jakém okamžiku lze funkci vyhledávání vyřadit ze závorky.
Obrázek 7: Formulář pro kontrolu pravopisu
Kontrola pravopisu se ve výše uvedeném formuláři spustí vždy, když je v ovládacím prvku formuláře stisknuta mezera nebo návrat. Jinými slovy, spustí se na konci každého slova. Mohlo by to být také spojeno se ztrátou zaměření ovládacího prvku, aby se zajistilo, že bude zkontrolováno poslední slovo.
Postup je vázán na Formulář > Události > Klávesa uvolněna.
SUB MarkWrongWordsDirect(oEvent As Object)
GlobalScope.BasicLibraries.LoadLibrary("Tools")
Funkce RTrimStr slouží k odstranění interpunkčního znaménka na konci řetězce. Jinak by se všechna slova, která končí čárkou, tečkou nebo jiným interpunkčním znaménkem, zobrazovala nahoře jako pravopisné chyby. Kromě toho se funkce LTrimChar používá k odstranění závorek na začátku slov.
Dim aProp() As New com.sun.star.beans.PropertyValue
Dim oLinuSvcMgr As Object
Dim oSpellChk As Object
Dim oField As Object
Dim arText()
Dim stWord As String
Dim inlenWord As Integer
Dim ink As Integer
Dim i As Integer
Dim oCursor As Object
Dim stText As Object
oLinguSvcMgr = createUnoService("com.sun.star.linguistic2.LinguServiceManager")
If Not IsNull(oLinguSvcMgr) Then
oSpellChk = oLinguSvcMgr.getSpellChecker()
End If
Nejprve se deklarují všechny proměnné. Poté je zpřístupněn modul Basic pro kontrolu pravopisu SpellChecker. Právě tento modul bude skutečně kontrolovat správnost jednotlivých slov.
oField = oEvent.Source.Model
ink = 0
If oEvent.KeyCode = 1280 Or oEvent.KeyCode = 1284 Then
Událostí, která makro spustí, je stisknutí klávesy. Tato událost obsahuje kód KeyCode pro každou jednotlivou klávesu. KeyCode pro klávesu Return je 1280, pro mezeru 1284. Stejně jako mnoho dalších informací se tyto položky získávají pomocí nástroje Xray. Po stisknutí mezerníku nebo klávesy Enter se zkontroluje pravopis. Jinými slovy se spouští na konci každého slova. Pouze test posledního slova neprobíhá automaticky.
Při každém spuštění makra se zkontrolují všechna slova v textu. Kontrola jednotlivých slov by byla také možná, ale vyžadovala by mnohem více práce.
Text je rozdělen na jednotlivá slova. Oddělovačem je znak mezery. Předtím je třeba slova rozdělená zalomeními řádků opět spojit, jinak by mohlo dojít k záměně těchto částí za celá slova.
stText = Join(Split(oField.Text,CHR(10))," ")
stText = Join(Split(stText,CHR(13))," ")
arText = Split(RTrim(stText)," ")
For i = LBound(arText) To Ubound(arText)
stWord = arText(i)
inlenWord = len(stWord)
stWord = Trim( RtrimStr( RtrimStr( RtrimStr( RtrimStr( RtrimStr(
RtrimStr(stWord,","), "."),"?"),"!"),"."),")"))
stWord = LTrimChar(stWord,"(")
Jednotlivá slova jsou přečtena. Jejich nezkrácená délka je potřebná pro následující krok úprav. Jen tak lze určit pozici slova v rámci celého textu (což je nezbytné pro konkrétní zvýraznění pravopisných chyb).
Funkce Trim se použije pro odstranění mezer, zatímco RTrimStr odstraní čárky a tečky na konci textu a LTrimChar jakákoliv interpunkční znaménka na začátku.
If stWord <> "" Then
oCursor = oField.createTextCursor()
oCursor.gotoStart(false)
oCursor.goRight(ink,false)
oCursor.goRight(inLenWord,true)
If Not oSpellChk.isValid(stWord, "en", aProp()) Then
oCursor.CharUnderline = 9
oCursor.CharUnderlineHasColor = True
oCursor.CharUnderlineColor = RGB(255,51,51)
Else
oCursor.CharUnderline = 0
End If
End If
ink = ink + inLenWord + 1
Next
End If
End Sub
Pokud slovo není nulové, vytvoří se textový kurzor. Tento kurzor se přesune bez zvýraznění na začátek textu v zadávaném poli. Pak skočí dopředu doprava, stále bez zvýraznění, na výraz uložený v proměnné ink. Tato proměnná začíná jako 0, ale po spuštění první smyčky je rovna délce slova (+1 za následující mezeru). Pak se kurzor posune doprava o délku aktuálního slova. Vlastnosti písma jsou upraveny tak, aby vytvořily zvýrazněnou oblast.
Spustí se kontrola pravopisu. Jako argumenty vyžaduje slovo a kód země; bez kódu země se vše považuje za správné. Argument pole je obvykle prázdný.
Pokud slovo není ve slovníku, je označeno červenou vlnovkou. Tento typ podtržení je zde reprezentován '9'. Pokud je slovo nalezeno, není podtrženo ('0'). Tento krok je nutný, protože jinak by se slovo rozpoznané jako chybné a následně opravené nadále zobrazovalo červenou vlnovkou. Nikdy by nebyl odstraněn, protože nebyl dán žádný konfliktní formát.
Tabulku s jedním záznamem lze vytvořit přímo pomocí polí se seznamem a neviditelných číselných polí a odpovídající primární klíč zadat do jiné tabulky.
Tip
Použití polí se seznamem namísto seznamů nalezneme v databázi Example_Combobox_Listfield.odb, která je přiřazena k této knize.
Ovládací prvek Pole se seznamem zachází s formulářovými poli pro kombinované zadávání a výběr hodnot (pole se seznamem) jako se seznamem s možností zadání. Za tímto účelem se kromě polí se seznamem ve formuláři ukládají hodnoty klíčových polí, které se mají přenést do podkladové tabulky, do samostatných číselných polí. Pole lze deklarovat jako neviditelná. Klíče z těchto polí jsou načteny při načtení formuláře a pole se seznamem je nastaveno tak, aby zobrazovalo odpovídající obsah. Pokud se obsah pole se seznamem změní, uloží se a nový primární klíč se přenese do příslušného číselného pole, které se uloží do hlavní tabulky.
Pokud se místo tabulek používají upravitelné dotazy, lze text, který se má zobrazit v kombinačních polích, určit přímo z dotazu. Pro tento krok pak není nutné používat makro.
Předpokladem pro fungování makra je, že primárním klíčem tabulky, která je zdrojem dat pro kombinační pole, je automaticky se zvyšující celé číslo. Předpokládá se také, že název pole pro primární klíč je ID.
Tento podprogram má zobrazit text v poli se seznamem podle hodnoty neviditelných polí cizího klíče z hlavního formuláře. Lze ji použít i pro seznamy, které odkazují na dvě různé tabulky. K tomu může dojít, pokud je například poštovní směrovací číslo v poštovní adrese uloženo odděleně od města. V takovém případě lze poštovní směrovací číslo načíst z tabulky, která obsahuje pouze cizí klíč pro město. V seznamu by se mělo zobrazit poštovní směrovací číslo a město společně.
Sub ShowText(oEvent As Object)
Toto makro by mělo být vázáno na následující událost formuláře: 'Po změně záznamu'.
Makro se volá přímo z formuláře. Spouštěcí událost je zdrojem všech proměnných, které makro potřebuje. Některé proměnné již byly deklarovány globálně v samostatném modulu a nejsou zde znovu deklarovány.
Dim oForm As Object
Dim oFieldList As Object
Dim stFieldValue As String
Dim inCom As Integer
Dim stQuery As String
oForm = oEvent.Source
Ve formuláři je skrytý ovládací prvek, ze kterého lze získat názvy všech různých polí se seznamem. Tato pole se seznamem jsou jedno po druhém zpracována makrem.
aComboboxes() = Split(oForm.getByName("combofields").Tag,",")
For inCom = LBound(aComboboxes) TO Ubound(aComboboxes)
...
Next inCom
Doplňující informace (Tag) připojené ke skrytému ovládacímu prvku obsahují tento seznam názvů polí se seznamem oddělených čárkami. Názvy jsou zapsány do pole a poté zpracovány v rámci smyčky. Smyčka končí výrazem NEXT.
Pole se seznamem, které nahradilo seznam, se nazývá oFieldList. Abychom získali cizí klíč, potřebujeme správný sloupec v tabulce, která je základem formuláře. To je dostupné pomocí názvu pole tabulky, který je uložen v doplňkových informacích pole se seznamem.
oFieldList = oForm.getByName(Trim(aComboboxes(inCom)))
stFieldID = oForm.getString(oForm.findColumn(oFieldList.Tag))
oFieldList.Refresh()
Pole se seznamem se znovu načte pomocí Refresh()v případě, že se obsah pole změnil vložením nových dat.
Dotaz potřebný k zobrazení viditelného obsahu pole se seznamem je založen na poli, které je základem ovládacího prvku, a na hodnotě určené pro cizí klíč. Aby byl kód SQL použitelný, jsou odstraněny všechny případné operace třídění. Poté se zkontrolují případné definice relací (které budou začínat slovem WHERE). Ve výchozím nastavení funkce InStr() nerozlišuje mezi velkými a malými písmeny, takže zahrnuje všechny kombinace velkých a malých písmen. Pokud existuje relace, znamená to, že dotaz obsahuje pole ze dvou různých tabulek. Potřebujeme najít tabulku, která poskytuje cizí klíč pro odkaz. Makro zde závisí na tom, že primární klíč v každé tabulce se nazývá ID.
Pokud není definována žádná relace, dotaz přistupuje pouze k jedné tabulce. Informace o tabulce lze vynechat a podmínku formulovat přímo pomocí hodnoty cizího klíče.
If stFieldID <> "" Then
stQuery = oFieldList.ListSource
If InStr(stQuery,"order by") > 0 Then
stSql = Left(stQuery, InStr(stQuery,"order by")-1)
Else
stSql = stQuery
End If
If InStr(stSql,"where") Then
st = Right(stSql, Len(stSql)-InStr(stSql,"where")-4)
If InStr(Left(st, InStr(st,"=")),".""ID""") Then
a() = Split(Right(st, Len(st)-InStr(st,"=")-1),".")
Else
a() = Split(Left(st, InStr(st,"=")-1),".")
End If
stSql = stSql + "AND "+a(0)+".""ID"" = "+stFieldID
Else
stSql = stSql + "WHERE ""ID"" = "+stFieldID
End If
Každý název pole a tabulky musí být do příkazu SQL zadán se dvěma sadami uvozovek. Uvozovky jsou normálně interpretovány Basicem jako oddělovače textových řetězců, takže se při předávání kódu do jazyka SQL již nezobrazují. Zdvojení uvozovek zajistí, že se předá jedna sada. ""ID"" značí, že v dotazu bude použito pole "ID" s jednou sadou uvozovek, kterou SQL vyžaduje.
Nyní se provede dotaz uložený v proměnné stSql a jeho výsledek se uloží do proměnné oResult.
oDatasource = ThisComponent.Parent.CurrentController
If Not (oDatasource.isConnected()) Then
oDatasource.connect()
End If
oConnection = oDatasource.ActiveConnection()
oSQL_Command = oConnection.createStatement()
oResult = oSQL_Command.executeQuery(stSql)
Výsledek dotazu je načten ve smyčce. Stejně jako u dotazu v grafickém uživatelském rozhraní lze zobrazit několik polí a záznamů. Konstrukce tohoto dotazu však vyžaduje pouze jeden výsledek, který se nachází v prvním sloupci (1) množiny výsledků dotazu. Jedná se o záznam, který poskytuje zobrazený obsah pole se seznamem. Obsahem je text (getString()), proto příkaz oResult.getString(1).
While oResult.next
stFieldValue = oResult.getString(1)
Wend
Nyní musí být pole se seznamem nastaveno na textovou hodnotu získanou dotazem.
oFieldList.Text = stFieldValue
Else
Pokud v poli cizího klíče oField není žádná hodnota, dotaz se nezdařil a pole se seznamem je nastaveno na prázdný řetězec.
oFieldList.Text = ""
End If
Next inCom
End Sub
Tento postup spravuje kontakt mezi polem se seznamem a cizím klíčem dostupným v poli zdroje dat formuláře. To by mělo stačit k zobrazení správných hodnot v polích se seznamem. Uložení nových hodnot by vyžadovalo další postup.
Pokud je do pole se seznamem zadána nová hodnota (a to je koneckonců účel, pro který bylo toto makro vytvořeno), musí být odpovídající primární klíč zadán do základní tabulky formuláře jako cizí klíč.
Sub TextSelectionSaveValue(oEvent As Object)
Toto makro by mělo být vázáno na následující událost formuláře: 'Před akcí záznamu'.
Po deklarování proměnných (zde nejsou uvedeny) musíme nejprve přesně určit, která událost má makro spustit. Před akcí záznamu se postupně zavolají dvě implementace. Je důležité, aby makro samo načetlo objekt formuláře. To lze provést v obou implementacích, ale různými způsoby. Zde je odfiltrována implementace s názvem OdatabaseForm.
If InStr(oEvent.Source.ImplementationName,"ODatabaseForm") Then
...
End If
End Sub
Tato smyčka se vytvoří na stejném začátku jako procedura Display_text:
oForm = oEvent.Source
aComboboxes() = Split(oForm.getByName("combofields").Tag,",")
For inCom = LBound(aComboboxes) To Ubound(aComboboxes)
...
Next inCom
Pole oFieldList zobrazuje text. Může se nacházet uvnitř ovládacího prvku tabulky a v takovém případě k němu není možné přistupovat přímo z formuláře. V takových případech by doplňkové informace pro skryté ovládací prvky polí se seznamem měly obsahovat cestu k poli pomocí pole se seznamem „tablecontrol“. Rozdělení této položky odhalí, jakým způsobem se má k poli se seznamem přistupovat.
a() = Split(Trim(aComboboxen(inCom)),">")
If Ubound(a) > 0 Then
oFieldList = oForm.getByName(a(0)).getByName(a(1))
Else
oFieldList = oForm.getByName(a(0))
End If
Poté je dotaz načten z pole se seznamem a rozdělen na jednotlivé části. U jednoduchých polí se seznamem jsou nezbytnými informacemi název pole a název tabulky:
SELECT "Field" FROM "Table"
To by v některých případech mohlo být doplněno o pokyn k třídění. Kdykoli mají být v poli se seznamem dvě pole pohromadě, bude třeba více práce s jejich oddělením.
SELECT "Field1"||' '||"Field2" FROM "Table"
Tento dotaz spojí dvě pole a vloží mezi ně mezeru. Protože oddělovačem je mezera, makro ji vyhledá a rozdělí text na dvě části. To samozřejmě bude spolehlivě fungovat pouze tehdy, pokud Field již neobsahuje text, ve kterém jsou mezery povoleny. V opačném případě, pokud je křestní jméno „Anne Marie“ a příjmení „Müller“, bude makro považovat „Anne“ za křestní jméno a „Marie Müller“ za příjmení. V takových případech je třeba použít vhodnější oddělovač, který pak může být nalezen makrem. V případě jmen by to mohlo být „Příjmení, Jméno“.
Situace se ještě více zkomplikuje, pokud obě pole pocházejí z různých tabulek:
SELECT "Table1"."Field1"||' > '||"Table2"."Field2"
FROM "Table1", "Table2"
WHERE "Table1"."ID" = "Table2"."ForeignID"
ORDER BY "Table1"."Field1"||' > '||"Table2"."Field2" ASC
Zde je třeba pole od sebe oddělit, určit tabulku, do které každé pole patří, a určit odpovídající cizí klíče.
stQuery = oFieldList.ListSource
aFields() = Split(stQuery, """")
stContent = ""
For i=LBound(aFields)+1 To UBound(aFields)
Obsah dotazu je zbaven zbytečného balastu. Jednotlivé části jsou znovu sestaveny do pole s neobvyklou kombinací znaků jako oddělovačem. FROM odděluje zobrazení viditelných polí od názvů tabulek. WHERE odděluje podmínku od názvů tabulek. Spojení nejsou podporována.
If Trim(UCASE(aFields(i))) = "ORDER BY" Then
Exit For
ElseIf Trim(UCASE(aFields(i))) = "FROM" Then
stContent = stcontent+" §§ "
ElseIf Trim(UCASE(aFields(i))) = "WHERE" Then
stContent = stcontent+" §§ "
Else
stContent = stContent+Trim(aFields(i))
End If
Next i
aContent() = Split(stContent, " §§ ")
V některých případech pochází obsah viditelného zobrazení polí z různých polí:
aFirst() = Split(aContent(0),"||")
If UBound(aFirst) > 0 Then
If UBound(aContent) > 1 Then
První část obsahuje nejméně dvě pole. Pole začínají názvem tabulky. Druhá část obsahuje dva názvy tabulek, které lze určit z první části. Třetí část obsahuje vztah s cizím klíčem, oddělený znakem =:
aTest() = Split(aFirst(0),".")
NameTable1 = aTest(0)
NameTableField1 = aTest(1)
Erase aTest
stFieldSeperator = Join(Split(aFirst(1),"'"),"")
aTest() = Split(aFirst(2),".")
NameTable2 = aTest(0)
NameTableField2 = aTest(1)
Erase aTest
aTest() = Split(aContent(2),"=")
aTest1() = Split(aTest(0),".")
If aTest1(1) <> "ID" Then
NameTab12ID = aTest1(1)
IF aTest1(0) = NameTable1 Then
Position = 2
Else
Position = 1
End If
Else
Erase aTest1
aTest1() = Split(aTest(1),".")
NameTab12ID = aTest1(1)
If aTest1(0) = NameTable1 Then
Position = 2
Else
Position = 1
End If
End If
Else
První část obsahuje dva názvy polí bez názvů tabulek, případně s oddělovači. Druhá část obsahuje názvy tabulek. Třetí část neexistuje:
If UBound(aFirst) > 1 Then
NameTableField1 = aFirst(0)
stFieldSeperator = Join(Split(aFirst(1),"'"),"")
NameTableField2 = aFirst(2)
Else
NameTableField1 = aFirst(0)
NameTableField2 = aFirst(1)
End If
NameTable1 = aContent(1)
End If
Else
Z jedné tabulky je pouze jedno pole:
NameTableField1 = aFirst(0)
NameTable1 = aContent(1)
End If
Maximální délka znaku, kterou může záznam mít, je dána funkcí ColumnSize. Pole se seznamem nelze použít k omezení velikosti, protože může být nutné, aby obsahovalo dvě pole současně.
LengthField1 = ColumnSize(NameTable1,NameTableField1)
If NameTableField2 <> "" Then
If NameTable2 <> "" Then
LengthField2 = ColumnSize(NameTable2,NameTableField2)
Else
LengthField2 = ColumnSize(NameTable1,NameTableField2)
End If
Else
LengthField2 = 0
End If
Obsah pole se seznamem se načte:
stContent = oFieldList.getCurrentValue()
V případě potřeby se odstraní počáteční a koncové mezery a netisknutelné znaky.
stContent = Trim(stContent)
If stContent <> "" Then
If NameTableField2 <> "" Then
Pokud existuje druhé pole tabulky, musí být obsah pole se seznamem rozdělen. Pro určení místa, kde má dojít k rozdělení, použijeme oddělovač polí, který je funkci zadán jako argument.
a_stParts = Split(stContent, FieldSeparator, 2)
Poslední parametr znamená, že maximální počet částí je 2.
Podle toho, který údaj odpovídá poli 1 a který poli 2, se nyní obsah pole se seznamem přiřadí jednotlivým proměnným. "Position = 2" zde slouží jako označení, že druhá část obsahu znamená pole 2.
If Position = 2 Then
stContent = Trim(a_stParts(0))
If UBound(a_stParts()) > 0 Then
stContentField2 = Trim(a_stParts(1))
Else
stContentField2 = ""
End If
stContentField2 = Trim(a_stParts(1))
Else
stContentField2 = Trim(a_stParts(0))
If UBound(a_stParts()) > 0 Then
stContent = Trim(a_stParts(1))
Else
stContent = ""
End If
stContent = Trim(a_stParts(1))
End If
End If
Může se stát, že při dvou oddělitelných obsazích se instalovaná velikost pole se seznamem (délka textu) nevejde do polí tabulky, která se mají uložit. U polí se seznamem, která představují jediné pole, se to obvykle řeší vhodnou konfigurací ovládacího prvku formuláře. Zde naopak potřebujeme nějaký způsob, jak takové chyby zachytit. Kontroluje se maximální přípustná délka příslušného pole.
If (LengthField1 > 0 And Len(stContent) > LengthField1) Or (LengthField2 > 0 And Len(stContentField2) > LengthField2) Then
Pokud je délka pole první nebo druhé části příliš velká, uloží se do jedné z proměnných výchozí řetězec. Znak Chr(13) se používá pro zalomení řádku.
stmsgbox1 = "The field " + NameTableField1 + " must not exceed " + Field1Length + "characters in length." + Chr(13)
stmsgbox2 = "The field " + NameTableField2 + " must not exceed " + Field2Length + "characters in length." + Chr(13)
Pokud jsou oba obsahy polí příliš dlouhé, zobrazí se oba texty.
If (LengthField1 > 0 And Len(stContent) > LengthField1) And (LengthField2 > 0 And Len(stContentField2) > LengthField2) Then
MsgBox("The entered text is too long." + Chr(13) + stmsgbox1 + stmsgbox2 + "Please shorten it.",64,"Invalid entry")
Zobrazení používá funkci MsgBox(). Jako první argument se očekává textový řetězec, dále volitelně číslo (které určuje typ zobrazeného okna zprávy) a nakonec volitelný textový řetězec jako název okna. V okně se proto zobrazí nadpis "Invalid entry" (Neplatné zadání, pozn. překl.) a číslo "64" poskytuje pole obsahující symbol Informace.
Následující kód se vztahuje na všechny další případy, kdy se může vyskytnout příliš dlouhý text.
ElseIf (Field1Length > 0 And Len(stContent) > Field1Length) Then
MsgBox("The entered text is too long." + Chr(13) + stmsgbox1 + "Please shorten it.",64,"Invalid entry")
Else
MsgBox("The entered text is too long." + Chr(13) + stmsgbox2 + "Please shorten it.",64,"Invalid entry")
End If
Else
Pokud není text příliš dlouhý, může funkce pokračovat. V opačném případě se zde ukončí.
Nyní jsou položky maskovány tak, aby případné uvozovky nevyvolaly chybu.
stContent = String_to_SQL(stContent)
If stContentField2 <> "" Then
stContentField2 = String_to_SQL(stContentField2)
End If
Nejprve jsou předalokovány proměnné, které lze následně dotazem měnit. Proměnné inID1 a inID2 uchovávají obsah polí primárních klíčů obou tabulek. Pokud dotaz neposkytne žádné výsledky, přiřadí Basic této celočíselné proměnné hodnotu 0. Tato hodnota by však také mohla znamenat úspěšný dotaz vracející hodnotu primárního klíče 0; proto je proměnná přednastavena na –1. HSQLDB nemůže tuto hodnotu nastavit pro pole automatické hodnoty.
Dále se nastaví připojení k databázi, pokud ještě neexistuje.
inID1 = -1
inID2 = -1
oDatasource = ThisComponent.Parent.CurrentController
If Not (oDatasource.isConnected()) Then
oDatasource.connect()
End If
oConnection = oDatasource.ActiveConnection()
oSQL_Command = oConnection.createStatement()
If NameTableField2 <> "" And Not IsEmpty(stContentField2) And NameTable2 <> "" Then
Pokud existuje druhé pole tabulky, musí být nejprve deklarována druhá závislost.
stSql = "SELECT ""ID"" FROM """ + NameTable2 + """ WHERE """ + NameTableField2 + """='" + stContentField2 + "'"
oResult = oSQL_Command.executeQuery(stSql)
While oResult.next
inID2 = oResult.getInt(1)
Wend
If inID2 = -1 Then
stSql = "INSERT INTO """ + NameTable2 + """ (""" + NameTableField2 + """) VALUES ('" + stContentField2 + "') "
oSQL_Command.executeUpdate(stSql)
stSql = "CALL IDENTITY()"
Pokud se obsah v poli se seznamem nenachází v příslušné tabulce, vloží se tam. Výsledná hodnota primárního klíče se pak přečte. Pokud je přítomen, načte se existující primární klíč stejným způsobem. Funkce používá automaticky generovaná pole primárního klíče (IDENTITY).
oResult = oSQL_Command.executeQuery(stSql)
While oResult.next
inID2 = oResult.getInt(1)
Wend
End If
Primární klíč pro druhou hodnotu je dočasně uložen v proměnné inID2 a poté zapsán jako cizí klíč do tabulky odpovídající první hodnotě. Podle toho, zda byl záznam z první tabulky již k dispozici, se obsah čerstvě uloží (INSERT) nebo změní (UPDATE):
If inID1 = -1 Then
stSql = "INSERT INTO """ + NameTable1 + """ (""" + NameTableField1 + """,""" + NameTab12ID + """) VALUES ('" + stContent + "','" + inID2 + "') "
oSQL_Command.executeUpdate(stSql)
A odpovídající ID se přímo načte:
stSql =