LibreOfficeLogo

Příručka aplikace Base 7.3

Kapitola 9
Makra

 

Autorská práva

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.

Přispěvatelé

Pro toto vydání

flywire

Jean-Pierre Ledure

Jean Hollis Weber

Steve Fanning

Olivier Hallot

 

Pro předchozí vydání

Robert Großkopf

Pulkit Krishna

Jost Lange

Jean-Pierre Ledure

Andrew Pitonyak

Alain Romedenne

Hazel Russman

Jochen Schiffers

Jean Hollis Weber

Zpětná vazba

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.

Datum vydání a verze programu

Vydáno Srpen 2022. Založeno na LibreOffice 7.3 Community.
Jiné verze LibreOffice se mohou lišit vzhledem a funkčností.

Používání LibreOffice na systému macOS

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

 

Obecné poznámky k makrům

Databázi v systému Base lze v zásadě spravovat bez maker. Někdy však mohou být nezbytná pro:

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.

graphics1

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:

Některé základní zásady pro použití kódu Basic v LibreOffice:

   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/.

Makra v Base

Používání maker

„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í:

„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).

Přiřazení maker

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.

Události, které nastanou ve formuláři při otevření nebo zavření okna.

Akce, které se provádějí při otevření nebo zavření formuláře, se zaznamenávají následujícím způsobem:

Grafik2

Obrázek 2: Dialogové okno Přizpůsobení, karta Události

  1. Při návrhu formuláře otevřeme kartu Události v Nástroje > Přizpůsobit.

  2. 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.

  3. Pomocí tlačítka Makro vyhledáme požadované makro a potvrdíme výběr.

  4. V části Uložit do zadáme název formuláře.

  5. Potvrdíme pomocí OK.

Události ve formuláři v otevřeném okně

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.

Bild11

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.

Události ve formuláři

Všechna ostatní makra se registrují pomocí vlastností podformulářů a ovládacích prvků na kartě Události.

  1. Otevřeme okno vlastností ovládacího prvku (pokud jsme tak ještě neučinili).

  2. Na kartě Události vybereme vhodnou událost.

  3. K úpravě zdroje dat použijeme události, které odkazují na položku Záznam, Aktualizovat nebo Obnovit.

  1. Kliknutím na tlačítko ... vpravo otevřeme dialogové okno Přiřadit akci.

  2. Kliknutím na tlačítko Makro vybereme makro definované pro danou akci.

  3. Kliknutím na OK potvrdíme přiřazení.

Grafik3

Obrázek 4: Dialogové okno Přiřadit akci

Součásti maker

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.

„Framework“ makra

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.

Definování proměnných

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.

Definování polí

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.

Přístup k formulářům

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.

Přístup k prvkům formuláře

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 do databáze

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.

Připojení k databázi

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).

Příkazy SQL

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.

Předpřipravené příkazy SQL s parametry

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):

Čtení a používání záznamů

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.

Používání formulářů

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:

Ú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.

Výsledek dotazu

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

Použití ovládacího prvku

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.

Navigace v datové sadě

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.

Editace záznamů – přidávání, úprava, mazání

Aby bylo možné záznamy upravovat, musí spolupracovat několik věcí:

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í.

Změna obsahu ovládacího prvku

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.

Změna řádků v datové sadě

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.

Vytváření, úprava a odstraňování řádků

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:

  1. Vybereme aktuální záznam.

  2. Změníme hodnoty podle popisu v předchozí části.

  3. Změnu potvrdíme následujícím příkazem:
    oForm.updateRow()

  4. 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:

  1. Připravíme se na nový záznam:
    oForm.moveToInsertRow()

  2. Zadáme všechny potřebné/požadované hodnoty. To se provádí pomocí metod updateXxx, jak je uvedeno v předchozí části.

  3. Nová data potvrdíme následujícím příkazem:
    oForm.insertRow()

  4. 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:

  1. Zvolíme požadovaný záznam a provedeme jeho aktualizaci, stejně jako v případě změny.

  2. 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

Testování a změna ovládacích prvků

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

Anglické názvy v makrech

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:

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.

Vlastnosti formulářů a ovládacích prvků

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.

Písmo

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

Vzorec

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ů

Tyto vlastnosti platí pro všechny ovládací prvky

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í:
0 = vlevo, 1 = na střed, 2 = vpravo

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í

Ty se vztahují na mnoho typů ovládacích prvků

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.

Textové pole – další vlastnosti (TextField)

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.

Číselné pole (NumericField)

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
(Nepoužívejte pro hodnoty ze souboru dat).

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í.

Pole pro datum (DateField)

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í getDateupdateDate, 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
(Nepoužívejte pro hodnoty ze souboru dat).

DateFormat

integer

 

R+W

Formát data specifický pro operační systém:
0 = krátké datum  (jednoduché)
1 = krátké Datum
dd.mm.yy (rok zobrazen pomocí dvou číslic)
2 = krátké Datum
dd.mm.yyyy (čtyřmístný rok)
3 = dlouhé Datum (obsahuje název dne v týdnu a měsíce)
Další možnosti nalezneme v definici formuláře nebo v 
Popisu API.

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

Pole pro čas (TimeField)

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
(Nepoužívejte pro hodnoty ze souboru dat).

TimeFormat

integer

 

R+W

Formát času:
0 = krátký, formát
hh:mm (hodiny, minuty, 24hodinové hodiny)
1 = dlouhý, formát
h:mm:ss (totéž s vteřinami, 24hodinové hodiny)
2 = krátký, formát
h:mm (12hodinové hodiny s AM/PM)
3 = dlouhý, formát
h:mm:ss (12hodinové hodiny s AM/PM)
4 = krátké zadání na dobu trvání
5 = dlouhý záznam pro časové období

DefaultTime

long

com.sun.star.util.Time

R+W

Výchozí hodnota.

Měnové pole (CurrencyField)

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é pole (FormattedControl)

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.

Pole se seznamem (ListBox)

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:
0 = Seznam hodnot
1 = Tabulka
2 = Dotaz
3 = Sada výsledků z SQL příkazu
4 = Výsledek databázového příkazu
5 = Názvy polí z tabulky databáze

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

Pole se seznamem (ComboBox)

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).

Zaškrtávací políčka (CheckBox) a přepínače (RadioButton)

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
0 = není vybráno
1 = vybráno
2 = nedefinováno

MultiLine

boolean

R+W

Zalomení řádků pro dlouhý text.

Pole vzoru (PatternField)

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í.

Ovládání prvek tabulky (GridControl)

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.

FixedText – také se nazývá Label

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.

Skupinové rámečky (GroupBox)

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í.

Tlačítka

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.

Lišta navigace (NavigationBar)

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.

ShowPosition

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.

ShowFilterSort

boolean

R+W

Umožňuje třídění podle filtru.

Metody pro formuláře a ovládací prvky

Datový typ parametru je označen zkratkou:

Navigace v datové sadě

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.

Úprava řádků dat

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.

Úprava jednotlivých hodnot

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.

Parametry pro připravené příkazy SQL

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.

Zlepšení použitelnosti

U této první kategorie použití maker si ukážeme různé možnosti, jak zlepšit použitelnost formulářů aplikace Base.

Automatická aktualizace formulářů

Č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ží.

Filtrování záznamů

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 = LBound(aList()) To UBound(aList())

      If = 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říprava dat z textových polí tak, aby odpovídala konvencím SQL

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.

Výpočet hodnot ve formuláři předem

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.

Poskytnutí aktuální verze LibreOffice

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.

Vrácení hodnoty polí seznamu

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.

Omezení seznamů zadáním počátečních písmen

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.

Převod dat z formuláře do proměnné data

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.

Vyhledávání datových záznamů

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.Nr. je primární klíč, což znamená všechny záznamy.

Zvýraznění vyhledávacích výrazů ve formulářích a výsledcích

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.

Bild2

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.

Bild6

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ě.

Kontrola pravopisu při zadávání dat

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.

Bild7

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.

Pole se seznamem jako seznamy s možností zadání

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.

Zobrazení textu v polích se seznamem

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.

Přenos hodnoty cizího klíče z pole se seznamem do číselného pole

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 =