Klik en sleep van object van een groep

Concept van klikken en slepen toegepast op objecten in een groep
(vervolg op eenvoudig klik en sleep voorbeeld)

Als je een aantal voorwerpen maakt tijdens de uitvoering van je programma (at runtime), bv knoppen, kan je die daarbij toewijzen aan een “group”, zodat je daarna de leden van die groep, als een soort child-objecten kan aanspreken (zie Group van een control definiëren).

Die “group” kan je ook gebruiken voor het klik en sleep gedrag.
De Gambas-omgeving helpt door een “laatst gebruikte” object/control waarde bij te houden: LAST
Via die weg kan je een “sleutel” doorgeven door die (op voorhand) op te nemen in het extra “Tag” veld van een object.

bv:

PUBLIC grpEtiketten_MouseDrag()
  ...
  IF Mouse.Left
    DEBUG LAST.Tag
  ENDIF
  ...
END

en

PUBLIC grpEtiketten_Drop()
  ...
  ... = Drag.Data
  DEBUG "dropped on" & LAST.Tag
  ...
END

Group van een control definiëren vanuit code

In de IDE kan je de group invullen bij de eigenschappen van een control, rechts in de lijst van eigenschappen.
Bovenaan heb je telkens

(Class)
(Name)
(Group)

Die group kan je gebruiken om een aktie op te vangen, bv een klik of een drop event.

Als je een object of control vanuit code gemaakt hebt, kan je niet eevoudigweg die eigenschap invullen zoals de andere eigenschappen.

FOR i = iEerste TO iLaatste
  arrayControls[i] = NEW ToggleButton(frameKnoppen)
  WITH arrayControls[i]
    .Text = Str$(i)
'    .Group="groupKnoppen"
    .Drop = TRUE
  END WITH
NEXT

Geen enkel van die “tussen haakjes” eigenschappen kan je vanuit code wijzigen; ze worden bepaald bij declaratie/initiatie.

De manier om die group toe te kennen is de declaratie/initiatie uit te breiden met de groupnaam als string in AS “groupname”

FOR i = iEerste TO iLaatste
  arrayControls[i] = NEW ToggleButton(frameKnoppen) AS "groupKnoppen"
  WITH arrayControls[i]
    .Text = Str$(i)
'    .Group="groupKnoppen"
    .Drop = TRUE
  END WITH
NEXT

Dan kan de group verder gebruikt worden om events op te vangen:

PUBLIC SUB grpKnoppen_Drop()
  LAST.Text = Drag.Data
  LAST.Value = TRUE
END

Gambas 2 en 3 op openSUSE 12.1

En dit is een derde installatie van Gambas op openSUSE 12.1, die vlekkeloos vlot verloopt.
(todo: na deze en deze)

Gestart van een installatie van openSUSE vanaf CD-rom met een image van 12.1 32-bit, download afkomstig van de openSUSE website. Na volledige installatie en alle updates op zoek naar Gambas; we weten van vroeger dat gambas meestal in de community repositories beschikbaar is bij de “Education” packages:

  • Software Repositories: Community “Education”
    URL: http://download.opensuse.org/repositories/Education/openSUSE_12.1/
  • Daarna in Software Management: Zoek “gambas”:
    Zowel versie 2 als versie 3 zijn beschikbaar.
    Zowel de individuele paketten als het geheel ().
    Als je bv gambas3-IDE selecteert, worden alle gambas3 onderdelen mee-geselecteerd; nadien ook nog heel wat afhankelijkheden, zeker als je nog geen programmeertools of omgeving geïnstalleerd had staan. Versie: Gambas 3.3.2
    Voor Gambas2 worden heel wat (oude) KDE3 onderdelen geïnstalleerd. Versie: 2.24

Commandolijn, SHELL: Distributie en versie opvragen

Een commandolijnprogramma kan je vanuit Gambas uitvoeren met SHELL of EXEC.

bv:

EXEC [ "ls", "-lF"]

Vanaf er “wildcards” in komen, als een ‘*’ om een reeks niet op voorhand gedefinieerde files aan te duiden, moet je SHELL gebruiken.

bv:

SHELL "ls /etc/*release"

Je kan in de Gambas IDE in het console venster onderaan de resultaten zien.

Je kan de uitvoer naar een variabele binnen Gambas sturen door de lijn te eindigen met

TO sVariabele

Klein voorbeeldje:

Maak een nieuw project “Command line application”

plak in MMain:

' Gambas module file

PUBLIC sParameter AS String
PUBLIC sCommand AS String
PUBLIC sAnswer AS String

PUBLIC sLine1 AS String
PUBLIC sLine2 AS String


PUBLIC SUB Main()

  sCommand = "ls /etc/*release"
  
  SHELL sCommand TO sAnswer
  
  DEBUG "Answer was: >" & Trim$(sAnswer) & "<"
  
  sAnswer = Trim$(sAnswer)
  
  sCommand = "cat " & sAnswer
  
  SHELL sCommand TO sAnswer
  
  DEBUG "Answer was: >" & Trim$(sAnswer) & "<"
  
  sLine1 = Left$(sAnswer, String.InStr(sAnswer, gb.NewLine))
  
  DEBUG "sLine1 is: " & sLine1
  
END

Hier kan je code uittesten die je elders in een grotere applicatie inbouwt; sParameter en sLine2 dienden daarvoor.

Valse echo eet letter op bij invoer en weergave

Ik had een vervelende fenomeen van een soort “echo” op mijn scherm in een textbox, die ik wilde vullen met de invoer van een andere textbox.

De invoer gebeurde in txbxEditField.

Het was de bedoeling dat als de tekst daar klaar was, en de gebruiker enter of return drukt, de tekst ingevuld wordt in een cel in een tabel “tbvwDoel”. Het invullen in die tabel gebeurde met de functie valToTable() die in essentie niet meer doet dan:

tbvwDoel[iRowSelected, iColNewValue].Text = txbxEditField.Text

Ik ving bij het invoeren de Enter en de Return knop op om de invoer te aanvaarden:


PUBLIC SUB txbxEditField_KeyPress()
IF Key.Enter
valToTable()
btEditOk_Click()
ENDIF
IF Key.Return
valToTable()
btEditOk_Click()
ENDIF
END

Maar het vervelende effect was dat in de tabel de tekst die ingetikt wordt zichbaar is maar telkens met 1 letter vertraging, met 1 letter minder dan wat ingegeven is. Dat is bijzonder irrittant voor de gebruiker, die eigenlijk kijkt naar de plaats in de tabel in plaats van naar het invulveld.

Het is een kleine “logische” fout:


PUBLIC SUB txbxEditField_KeyPress()
IF Key.Code = Key.Enter
valToTable()
btEditOk_Click()
ENDIF
IF Key.Code = Key.Return
valToTable()
btEditOk_Click()
ENDIF
END

Nu gebeurt wat de bedoeling is. Het andere, verkeerde effect is leuk om te onthouden …

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?

Mail sturen vanuit Gambas

MailFromGambas Kies component “gb.net.smtp” in Project/Properties/Components.
Je krijgt dan beschikking over een smtp opject met volgende eigenschappen en methodes:

gb.net.smtp
 SmtpClient
   Add
   Alternative
   Bcc
   Cc
   From
   Host
   Port
   Send
   Subject
   To

De meeste eigenschappen kan je gewoon een tekstwaarde toewijzen, bv .Host = "..."
De lijst van de bestemmelingen wordt gegeven door de string .To.
Om een bestemmeling toe te voegen moet je To.Add("..") gebruiken, bv in een loop per adres dat je wil toevoegen.
Voor de inhoud van de mail .Add("..")
Attachments zijn halvelings voorzien maar lijken in 2.x versies (<2.21) niet altijd te werken (alleen te werken voor pure tekst).
Attachments hebben een type: IANN
Zie ook de documentatie van de gb.net.smtp module.

Een voorbeeld van code (die bij het schermvoorbeeld hoort):
Continue reading

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!