Error management – foutbeheer

Bij gebruik van een databank lijkt de eenvoudigste manier om de fouten op te slaan in de databank; tenzij de fouten juist gaan over de databankverbinding.

Een alternatief is ze op te slaan naar een tekstbestand “error.log”, zoals de meeste programma’s. Het is bedrijfszekerder en de fouten zijn gemakkelijk te raadplegen zonder dat de applicatie draait, of zonder zelfs de databank draait.

Wat moet er in de foutlijn in de logfile staan? Minstens:
Foutmelding, datum, tijd, systeeminformatie als user@host

Een paar voorbeelden uit /var/log:

Zypper:mail
2010-07-27 11:32:25 <1> mybox(17593) [zypp] RpmDb.cc(~RpmDb):310 ~RpmDb()
2010-07-27 11:32:25 <1> mybox(17593) [zypp] RpmDb.cc(closeDatabase):805 closeDatabase: RpmDb[NO_INIT]
2010-07-27 11:32:25 <1> mybox(17593) [zypp] TargetImpl.cc(~TargetImpl):302 Targets closed

X.org:
(II) intel(0): Output VGA is connected to pipe A
(II) intel(0): [drm] dma control initialized, using IRQ 16
(II) Mouse[1]: ps2EnableDataReporting: succeeded
(II) AIGLX: Suspending AIGLX clients for VT switch
(II) intel(0): xf86UnbindGARTMemory: unbind key 0

mail.err
Aug 25 10:24:01 linux postfix/postfix-script[3310]: fatal: the Postfix mail system is not running

Moeten er alleen fouten in staan, of ook meldingen van bv een toestand? Dan wordt het meer een soort “message log”. Cups lijkt letters te gebruiken als I = info, E = Error, W = warning:

/var/log/cups/error_log

I [25/Aug/2010:15:15:49 +0200] Started “/usr/lib/cups/cgi-bin/admin.cgi” (pid=1119)
E [25/Aug/2010:15:15:49 +0200] CUPS-Add-Modify-Printer: Unauthorized
W [10/Sep/2010:15:19:40 +0200] [Job 1886] Unknown choice “Auto” for option “InputSlot”!

Of moet je het scheiden zoals bij “mail“, in verschillende bestanden:

mail
mail.err
mail.info
mail.warn

Kan bv de “debug” omgeleid worden naar een bestand? Dan heb je de debug meldingen bij het programmeren+draaien van de code, en vergelijkbare data in de log.

Log snoeien: hoe lang mag log worden? FIFO die oudste data verliest, of telkens bij nieuwe start de vorige log leegmaken?

Gambas IDE verknoeid / Screwed my Gambas IDE

Door het installeren en compileren van een programma is mijn hele Gambas IDE in de problemen gekomen.
Het programma had als voorwaarden Gambas met een versienummer hoger dan de gebruikte versie 2.8 op OpenSUSE 11.0 (maar dat wist ik toen nog niet).
Het geïnstalleerde pakket was DBReport (Report-Designer and Printer); en ik heb het stap voor stap gecompileerd zoals beschreven in de handleiding. Daarbij kreeg ik foutmeldingen die me uiteindelijk tot het inzicht van de hogere versie-vereisten brachten.

Nadien kon in Gambas niet meer gebruiken; foutmeldingen zoals hieronder:

Screwed my Gambas IDE

Due to installing and compiling the application DBReport (Report-Designer and Printer), I screwed up my Gambas IDE version 2.8 that runs on an (old-ok) openSuse 11.0

This is the log of what happened when I tried to use the IDE afterwards:

Continue reading

Rekenen met tijd in Gambas (uren, dagen)

Om tijd vast te leggen op het moment zelf: Now() geeft de huidige datum+tijd. Bekijk:

DEBUG Now()

Toekennen aan een variabele:

PRIVATE dStartuptime AS Date
dStartuptime = Now()
DEBUG Format$(dStartuptime, “hh:nn:ss”)

De debug regelt toont de variabele weergegeven in opgegeven patroon, waarbij “n” staat voor minuten (omdat de m al staat voor maand in het dagpatroon: yy-mm-dd).

Rekenen met tijd of opgeslagen tijd gaat niet zo:
DEBUG Now() – dStartuptime
Dat geeft immers ofwel direct 0, ofwel na acht seconden 9.055575355887E-5 en waarschijnlijk wil je een leesbaar getal, als een aantal minuten.

Hiervoor gebruik je de functie DateDiff met parameters oude tijd, nieuwe tijd, gecombineerd met uitvoerpatroon:

DEBUG DateDiff(dStartuptime, Now(), gb.Minute)
DEBUG DateDiff(dStartuptime, Now(), gb.Minute)
DEBUG DateDiff(dStartuptime, Now(), gb.Minute)

Bij start is het resultaat:

0
0
0

Na 8 seconden is het resultaat:

8
0
0

En na 121 seconden is het:

121
2
0

Dus je hoeft niet zelf (het aantal minuten x 60 ) plus de seconden te doen; de seconden tellen door en kunnen gebruikt worden, of als je slechts de nauwkeurigheid van minuten nodig hebt kan je rechtstreeks met minuten werken.
Na meer dan een hele dag wordt het, uitgedrukt in gb.Minute, gb.Hour, gb.Day:

1547
25
2

De eerste twee, minuten in uren:
Van minuten naar uren: 1547/60 is 25.7833.. dus de uren worden “afgekapt”
Maar de laatste in “dagen” telt een begonnen dag als een dag: hoewel het maar goed 25 uren zijn wordt 2 dagen aangegeven!

Hoe data in een cel steken van een TableView

Zet op een Form bv Form1 een tabel met de eigenschap TableView, bv tbvwFill.
Het gemakkelijkst is waarschijnlijk om de tabel te initialiseren door code die je oproept bij het openen van de Form waar ze in staat:

PUBLIC SUB Form_Open()

  initTableView()

END

Je moet dan een procedure daarvoor maken:

PUBLIC SUB initTableView()

Daarin moet je zeker bepalen wat de grootte van de tabel is, m.a.w. hoeveel cellen horizontaal en hoeveel vertikaal. Daarvoor “zet” je de eigenschap van de kolom en rij-teller door er een waarde of de waarde van een bestaande variabele aan toe te kennen:

  tbvwFill.Columns.Count = 3
  tbvwFill.Rows.Count = iDefinedRows

Je kan het aantal natuurlijk laten bepalen door een globale variabele die je elders reeds gevuld had:

  tbvwFill.Rows.Count = FMain.$hMonth.GrdTotRows()
  • FMain: het hoofdscherm van waaruit het huidig scherm (Form1) wordt opgeroepen
  • $hMonth is een object dat een maand voorstelt, daar een aantal eigenschappen over heeft, en gedefinieerd werd in FMain.
  • GrTotRows is een eigenschap van object $hMonth, de waarde is al toegekend in FMain; of hier is het eigenlijk een functie van het object $hMonth die deze waarde berekent op basis van andere eigenschappen en teruggeeft als waarde.

Op deze manier kan het aantal rijen van tabellen in verschillende forms gestuurd worden uit 1 variabele.

Een waarde toekennen aan de twee cellen of velden van de bovenste rij in de tabel:

  tbvwFill[0, 0].Text = "ID"
  tbvwFill[0, 1].Text = "Naam"
  iRowStartEmployees = 1

Procedure natuurlijk altijd afsluiten met

END

Het vullen van de tabel kan o.a. met een FOR EACH loop, bv met waarden uit een resultset – hier $hResEmployees – die op voorhand gevuld werd met waarden uit een databank.

  FOR EACH $hResEmployees
    tbvwFill[$hResEmployees.Index + iRowStartEmployees, 0].Text = $hResEmployees!emp_id
    tbvwFill[$hResEmployees.Index + iRowStartEmployees, 1].Text = $hResEmployees!emp_name
  NEXT 

De eerste twee kolommen (kolom 0 en kolom 1) worden gevuld met een de velden id en name uit de database.
De eerste rij wordt hier niet gebruikt (rij 0) omdat daar de titel in staat.

Dan moet ervoor gezorgd worden dat als je op de tabel klikt, je de waarde van de cel kan wijzigen:

PUBLIC SUB tbvwFill_Click()

  DEBUG TableView1.Column
  DEBUG TableView1.Row

  tbvwFill.Edit()
  
END

De DEBUG lijnen tonen de rij en de kolom-waard; de cel linksboven is (0,0); de headers reageert niet op deze klik om coördinaten.

En tenslotte moet je ervoor zorgen dat die ingevulde waarde ook behouden blijft in de cel:
Daarvoor moet je de methode _Save van de tabel zelf aanvullen met code:

PUBLIC SUB tbvwFill_Save(x AS Integer, y AS Integer, sText AS String)
  
  tbvwFill[x, y].Text = sText
  
END

Je kan hier natuurlijk binnen deze code controles op uitvoeren enz.

– NB: – – Continue reading

Overal programmeren (met live-dvd)

Een triple boot DVD (bij LXF139) bevat drie versies van Ubuntu: Ubuntu, Xubuntu en Kubuntu. Ubuntu 2010 bevat Gambas 2.21, zelfs in de live dvd versie (systeem draaien van dvd zonder te installeren op de harde schijf). Dat betekent dat je met deze dvd zowat overal kan programmeren; ofwel moet je project op usb-stick/harddisk staan, ofwel online, naargelang je mogelijkheden en omstandigheden.

Start eender welke computer met de DVD, download je broncode, werk er verder aan, upload het resultaat. Al is het maar om wat vertalingswerk te doen, want een databank installeren op een live distro is natuurlijk al wat omslachtiger.

Dank u, Ubuntu!

Standaard leeg project

Project Type: Graphical application.
Options:

  • Internationalisation
  • Database access
  • Settings files management

Name: EmptyProject
Title: Empty Project

FMain: Menu met

  • File: Quit
  • Help: About, Changes, License

Form_Open: zet programma titel en versie.
doClose(): aangeroepen bij Menu/Quit (of scherm “Exit” button); kan afsluitende code aanroepen (wegschrijven toestand)

FAbout: About logo en tekst: naam plus versie.

FLicense: Toont License.txt
FChanges: Toont Changes.txt

Misschien nog een “test” menu-item dat alleen verschijnt als de conf file de verwijzing bevat:

[Mode]
Developer=”TRUE”

Op basis van die verwijzing zet je bij het starten van het programma het menu op visible.
Daaronder kunnen dat stukjes code getest worden die nog niet zijn vrijgegeven voor gebruik.
Opgelet: de gebruiker kan door het (buiten het programma om) wijzigen van zijn settings file dit menu dus aanzetten!

Logs en foutmeldingen op scherm

– Een eenvoudige weergave van log-meldingen en foutmeldingen kan in het (hoofd-)venster van het programma FMain in een ListBoxLog en ListBoxError. Door ListBoxLog.Add(“Opmerking”, 0) kan je de meldingen bovenaan toevoegen, de oude rollen weg naar beneden.

Fouten met Error Class

Een foutklasse CError kan vanuit het programma geinitieerd worden en de foutafhandeling waarnemen; bv kunnen de fouten naar een bestand gelogd worden, waarin elke regel voorafgegaan wordt door datum en tijd, en de foutmeldingslijn aangevuld wordt met de gebruiker System.User.Name

(laatste aanpassing: 08-2014)

TabStrip: hoe tab-bladen bijmaken en aanspreken?

Een tabstrip zit in de Toolbox onder de tab “Container”.
Eens op het werkvlak getekend heeft hij slechts 1 tab: Tab0.
Als je terug naar de Toolbox gaat zoeken om tab-bladen bij te maken vind je dat daar niet.
Als je op het TabStrip rechtsklikt om tab-bladen bij te maken vind je alleen “Move Tab”, niet “Create”

Tabstrip met tab-bladen

Om tabs bij te maken moet je de “teller” van de tabstrip verhogen:
“Count” staat op 1.

Zet op het gewenste aantal.

Dit kan natuurlijk ook vanuit je programma, bv:

TabStrip1.Count = 3

Daarna kan je de tabbladen aanspreken met

TabStrip1.Index = 2 ' aktief maken van tabblad 2; dwz het derde want er wordt geteld tab0 tab1 tab2.

Een tabblad kan ook verborgen worden:

TabStrip1.Current.Visible = FALSE ' verbergen van een tabblad, hier dus dat derde.
TabStrip1[0].Visible = FALSE ' of bepaal het tabblad met de index

TabStrip1.Hide ' verbergen van heel de tabstrip

Bij de eigenschappen rechts in het ontwerpscherm zie je nog meer mogelijkheden, als een pictogram opnemen enz.

Columnview: kolomtitel invullen, item invullen

Gridview, ColumnviewNieuw formulier FMain, daarop een columnview “cvTwoCols”.

Eerst moeten de dimensies opgegeven worden met Columns.Count.
Dan kunnen de titels ingevuld worden.
Dan kunnen lijnen bijgemaakt worden met een zelfgekozen sleutel waarmee een opvraging kan gebeuren.
Tenslotte kan
– genavigeerd worden met MoveTo,
– een waarde gewijzigd,
– of de waarde in een bij de lijn horende kolom ingevuld worden.

PUBLIC SUB btFillColView_Click()
'
cvTwoCols.Columns.Count = 2
'
cvTwoCols.Columns[0].Text = "code"
cvTwoCols.Columns[0].Width = 50
cvTwoCols.Columns[1].Text = "description"
cvTwoCols.Columns[1].Width = 100
'
cvTwoCols.Add("0", "test1")
cvTwoCols.Add("1", "test2")
'
' and now? How to add something to the second column?
cvTwoCols.MoveTo("0")
cvTwoCols.Current.Text = "Test1"
cvTwoCols.Item[1] = "TestItem"
'
END

update griddemo download/demo/GridDemo/

html rapport weergeven of printen

Uitvoer kan je eenvoudig doen in html-bestanden, die je lokaal schrijft en opent met een browser.

Daarvoor moeten we een bestand openen (een nieuw bestand maken) om in te schrijven, tekst naar het bestand schrijven, en het bestand sluiten.

Maak een module met alle printonderdelen, en met bovenaan

PUBLIC bToPrint AS Boolean

PRIVATE hFile AS File

schrijf een bestand

OPEN sFilename FOR WRITE CREATE AS #hFile
pushHeader(bToPrint)

dat je begint met een kop die zo gemaakt wordt:
( de < en > tekens moeten natuurlijk aansluiten zonder spaties in je code)


PUBLIC SUB pushHeader(bToPrinter AS Boolean)
'
PRINT #hFile, " < html > "
PRINT #hFile, " < head > < title > " & Application.Name & " - by " & User.Name & " < /title > < /head > "
PRINT #hFile, " < body topmargin='0' leftmargin='0' fontsize='1'" ' IF (bToPrinter) THEN DEBUG "To printer ..." PRINT #hFile, " onload='window.print()'" ' only works when java is on ENDIF ' PRINT #hFile, " > "
'
END

Daarna stuur je alle gegevenslijnen, eventueel in de vorm van een tabel, en sluit je het af met een “footer”

PUBLIC SUB pushFooter()
'
PRINT #hFile, " < br > < font size='1' > " & "FACS " & Application.Version
PRINT #hFile, " < i > via " & MCommon.sReportDir & " "
PRINT #hFile, "by " & User.Name & "." & System.Host & " at " & CStr(Date(Now())) & " - " & Left$(CStr(Time(Now())), 5)
PRINT #hFile, " < /i > "
PRINT #hFile, " < /font > "
PRINT #hFile, " < /body > "
PRINT #hFile, " < /html > "
'
END

Bestand afsluiten met CLOSE na het vullen:


pushTableHeadwSub(sTitle, arrColNames, sSql, arrColTotals)
pushTableLines(resCostcode, arrColTotals)
pushTableFooter()
pushFooter()

CLOSE #hFile

Als de volledige bestandsnaam met het volledige pad in de variabele sFilename zit, bv:

sFilename = “/home/mijnnaam/Documents/ToPrint/test.html”

dan kan je de pagina openen in een browser:


EXEC ["konqueror", sFilename]
EXEC ["firefox", sFilename]

(dit is in de KDE omgeving uitgevoerd – Gnome heeft bv geen konqueror standaard geïnstalleerd)