Tekst van runtime knop onbereikbaar (button Text property)

In bepaalde omstandigheden kwam ik op een foutmelding bij het gebruiken van de tekst die ingesteld staat bij een knop. De foutmelding:

Unknown symbol ‘Text’ in class ‘Control’

Unknown Symbol Text In Class Control

De klasse van het object waarvan ik de tekst eigenschap wil gebruiken is niet “Control”, maar wel “Button”, maar dat ziet Gambas niet. Toch niet ‘at runtime’, maar… :

Unknown Symbol Text In Class Control Debugged

Bij het stilleggen van het programma, en het selecteren van de betreffende code, toont hij de juiste tekst in de tooltip.

Daarom gebruik ik nu deze kleine omweg:

In plaats van de children van hboxItems aan te spreken met een index, en daarvan ineens de tekst op te vragen, wijs ik nu eerst het i-de item van de children toe aan een voorgedefinieerde button, en gebruik ik daarvan de tekst eigenschap:

Unknown Symbol Text In Class Control Solved

ps: Dit is een stukje code uit een complexer stuk programma, en om de fout te isoleren heb ik me hier beperkt tot het weergeven met DEBUG van de Text eigenschap; in werkelijkheid gebeurt daar iets anders mee, meer bepaald een drag’n’drop bewerking.

De buttons werden niet gemaakt in de Form designer, maar vanuit het programma, met als parent de hboxItems container. Daarom kan ik ze enkel onrechtstreeks aanspreken.

English summaray:
To use the Text attribute of a button (in this case), you have to make a button object first, then allocate the child object (with index i) to this button object. Then you are able to use the button text property.
The buttons in the hBoxItems were made under program control (at runtime), that’s why I have to call them in this inderect way, as children of the parent container.

openSUSE Leap 42.1 en Gambas2, Gambas3

Update 03/2016:
Ondertussen draait Gambas2 IDE (2.24) perfect op LEap 42.1!

* Een update van openSUSE 13.1 naar openSUSE Leap:
– Gambas2 programma’s compileren en draaien via runtime ok.
– Gambas IDE’s opstarten: werkt niet (meer), te checken.

Opgelet; Trek geen andere conclusie; dit is dus geen “verse installatie” van Leap; kan een verschil maken!
(inderdaad, na nieuwe installatie of updates was het in orde, zie boven)

Klik en sleep van TableView naar GridView

Klik en sleep
De eenvoudige voorbeelden van klik en sleep met de muis, zoals die waarbij een tekst van een TextBox naar een TextLabel worden gesleept, schieten te kort als je een TableView of een GridView gebruikt (beiden even roosters genoemd). Immers: je kan een heel rooster slepen naar een ander rooster en daar allerlei leuke dingen mee doen, maar meestal is dat niet de bedoeling.

Cel in plaats van rooster
Je wil een bepaald vakje, één cel, of eerder nog de inhoud daarvan, naar een andere plaats slepen. De bestemming is dan niet een element als TextBox of GridView, maar ook weer een bepaalde cel van een TableView of GridView rooster.

Drag..
De basis blijft hetzelfde:
Voor de vertrekplaats moet een _MouseDrag() gemaakt worden:

PUBLIC SUB TableView1_MouseDrag()
  IF Mouse.Left
    Drag.Icon = PictureBox1.Picture
    TableView1.Drag(TableView1[TableView1.Row, TableView1.Column].Text)
  ENDIF
END

Ik heb in de IDE op voorhand een PictureBox1 op FMain gezet, er in de IDE een beeldje voor gekozen uit de verzameling (stock), en die PictureBox1.Visible op FALSE gezet.

.. en Drop
De bestemming moet als eigenschap Drop = TRUE hebben:

GridView1.Drop = TRUE

en er moet drop code gemaakt worden:

PUBLIC SUB GridView1_Drop()
  GridView1[GridView1.RowAt(Drag.y), GridView1.ColumnAt(Drag.X)].Text = Drag.Data
END

Om de data in de Text te krijgen van de gewenste cel op rij, kolom

GridView1[row, column].Text = Drag.Data

moet je die coördinaten eerst detecteren:

GridView1.RowAt(Drag.y)
GridView1.ColumnAt(Drag.X)

Dit is de kleine “truuk” om het klikken en slepen tussen TableViews en GridViews mogelijk te maken.
Er zit nog wel een addertje onder het gras: als je een beetje buiten de bestaande cellen sleept en daar in het gridview gebied onder de laatste rij cellen bv loslaat, zijn de coördinaten niet gedefineerd. Crash!

Dus:
TRY GridView1[GridView1.RowAt(Drag.y), GridView1.ColumnAt(Drag.X)].Text = Drag.Data

Verder moet je de code aanvullen met alles wat moet gebeuren, zoals opslaan in een databank, berekeningen enz.

Rechter muisklik

Als je wil reageren op de rechtermuisklik kan dat in volgende twee stappen:

PUBLIC SUB SchermObject_MouseDown() 
  '
  IF Mouse.Right
    ' Doe iets
  ENDIF 
  '
END

Veelgebruikt is extra informatie of een extra optie geven voor het met de muis aangewezen object.

Om de gebruiker in te lichten vul je de “tooltip” in van het aangewezen object, zodat de extra mogelijkheid uitgelegd wordt alvorens geklikt is.

Voorbeeld: een rooster met gegevens van werknemers (Tableview met Employee data):

Twee andere procedures moeten bestaan;

  • newDataAvailable() AS BOOLEAN ‘ checkt of er nieuwe data is
  • doReloadData() ‘ haalt nieuwe data af en vult ze in de tabel
PUBLIC SUB tbvwEmpl_MouseDown() 'tbvwEmpl_DblClick()
  '
  IF Mouse.Right
    IF newDataAvailable()
      tbvwEmpl.Clear()
      doLoadData()
    ELSE 
      Message.Info("Up to date already")
    ENDIF  
  ENDIF 
  '
END

Data module met universele procedure om record toe te voegen

Gambas Modules of minstens stukken ervan kan je zo universeel maken dat je ze gemakkelijk kan hergebruiken.
Bij gebruik van een databank (bv MySQL/MariaDB) moet je altijd code schrijven om een record aan te maken. Het gemeenschappelijke daarin is minstens het toevoegen van een record met een sleutel (record id).

Je kan de aanmaak van een nieuw record (dus met nieuwe gegevens) opsplitsen in twee delen:

  • Aanmaken van een leeg record met een nieuw bekomen record nummer.
  • Het aanvullen van dat nieuwe record met alle andere gegevens, een update dus.

De update procedure moet je waarschijnlijk toch ook maken om gegevens te kunnen wijzigen aan een record waarvan je de id kent.

Het aanroepend programma kan gewoon een “ModData.saveRecord(id, data)” gebruiken, de module splitst het op in twee delen.
Als de id gegevens is, wordt de update procedure aangeroepen.
Als de id = 0 moet er een nieuw record gemaakt worden, daarna de update procudure met de ondertussen verkregen id.

Een datamodule ModData bevat:

PRIVATE sLastError AS String
' ...
PUBLIC SUB addRecord(sTablename AS String, sKeyname AS String) AS Long
' adds a record to a given database, get the record id of the empty record 
  DIM sSql AS String  
  DIM myResult AS Result
 ' 
  sSql = "INSERT INTO " & db.Quote(sTablename) & " (" & sKeyname & ") VALUES(0)" 
  DEBUG sSql
  '
  TRY $hConData.Exec(sSql)
  IF ERROR 
    sLastError &= "insert; " & Error.Text
    RETURN 0
  ELSE 
    sSql = "SELECT LAST_INSERT_ID() AS myId "
    'myId" ' FROM " & db.Quote(sTablename)
    TRY myResult = $hConData.Exec(sSql)
    IF ERROR 
      sLastError &= "last id ?" & Error.Text
      RETURN 0
    ELSE 
      RETURN myResult!myId 
    ENDIF 
  ENDIF 
  DEBUG sLastError
END

De procedure geeft het aangemaakte recordnummer terug. Daarna kunnen de gegevens ingevuld worden, wat minder universeel is. Veel kans dat dit stuk code enkel intern vanuit de module aangeroepen wordt, je zou ze dus ook PRIVATE kunnen maken.
Fouten vraagt het aanroepend programma/aanroepende procedure op met getLastError(), wat geimplementeerd is als

PUBLIC SUB getLastError() AS String
  '
  RETURN sLastError
  '
END

Alle procedures in de datamodule die een record moeten toevoegen in een database, kunnen deze zelfde functie gebruiken, mits aangeroepen met de juiste parameters voor de betreffende tabel.

Voorbeeld:

# Name Type Null Default Extra
1 emp_id bigint(20) No None AUTO_INCREMENT
2 emp_data1 int(11) No 0  
3 emp_data2 int(11) No 0  
4 emp_data3 char(1) Yes NULL  
5 emp_data4 varchar(11) Yes NULL  
6 emp_data5 datetime Yes NULL  
7 emp_data6 datetime Yes NULL  
8 emp_cre timestamp Yes CURRENT_TIMESTAMP  
9 emp_creby char(24) Yes NULL  
10 emp_upd datetime Yes NULL  
11 emp_updby char(24) Yes NULL  

Dit werkt op voorwaarde dat

  • de key record_id een getal is, bv van het type bigint(20)
  • de waarde van het veld record_id altijd automatisch wordt toegekend door de database (Auto Increment)
  • er standaardwaarden voorzien zijn in de struktuur van de tabel (0, NULL, ..).

Als geen standaardwaarden voorzien zijn krijg je een foutmelding; de database krijgt enkel een opdracht om de key in te vullen en weet niet wat er met de andere velden moet gebeuren.

Andere dingen die je kan standaardiseren:

  • Een foutmelding bijhouden (zie ook hierboven sLastError) en op laten vragen.
  • Een record verwijderen dat een bepaalde keywaarde heeft.
  • Opbouwen, openen en sluiten van de databaseverbinding
  • Een keuze tussen verschillende datasets voorzien (bv laptop/netwerk, ontwikkeling/productie)
  • enz.

Metadata
Dikwijls is het nuttig om te weten wanneer een record ontstaan is (creation date-time), en wie het gemaakt heeft (user). Als je daarvoor standaard velden opneemt in de database kan je die laten invullen vanuit deze record toevoegen-procedure. Het eenvoudigste voor het “createdon” veld is in de database als standaardwaarde “CURRENT_TIMESTAMP” in te stellen. Dan blijft nog het “createdby” veld, waar we de gebruikerslogin naam kunnen invullen (gb.user.name). Ofwel laat je een waarde opslaan die als parameter van de oproepende procedure komt, en kan het een andere vorm van gebruikers-id zijn, bv die waarmee in de applicatie ingelogd wordt.

  • Database: employee
  • Velden: id, naam, address, …, createdon, createdby
  • Database: department
  • Velden: id, building, floor, …, createdon, createdby

Dit is universeel; je kan employee.createdby of department.createdby enz. gebruiken; bij de AddRecord is het steeds dezelfde naam. Je moet dat dan voor alle tabellen zo doen!

Een andere mogelijkheid is de createdby optioneel te maken, zodat je ook nog minimale tabellen met enkel id kan houden.
En: als je niet de standaardnaam gebruikt, maar velden met een prefix voor de tabel gebruikt, moet je de veldnaam ergens vandaan halen.

  • Database: employee
  • Velden: emp_id, emp_naam, emp_address, …, emp_createdon, emp_createdby
  • Database: department
  • Velden: dep_id, dep_building, dep_floor, …, dep_createdon, dep_createdby

Gecombineerd:

PUBLIC SUB addRecord(sTablename AS String, sKeyname AS String, OPTIONAL sCreatedByField AS String) AS Long 
' adds a record to a given database, get the record id of the empty record 
  DIM sSql AS String  
  DIM myResult AS Result
 '
  sSql = "INSERT INTO " & db.Quote(sTablename) & " (" & sKeyname 
  IF sCreatedByField
    sSql &= "," & sCreatedByField & ") VALUES(0,&1)" ' & db.Quote(User.Name) & ")"
  ELSE 
    sSql &= ") VALUE(0)" 
  ENDIF 
  '
  DEBUG sSql
  '
  TRY $hconData.Exec(sSql, User.Name)
  IF ERROR 
    sLastError &= "insert; " & Error.Text
    RETURN 0
  ELSE 
    sSql = "SELECT LAST_INSERT_ID() AS myId "
    '
    TRY myResult = $hConData.Exec(sSql)
    IF ERROR 
      sLastError &= "last id ?" & Error.Text
      RETURN 0
    ELSE 
      RETURN myResult!myId 
    ENDIF 
  ENDIF 
  DEBUG sLastError
END 

De procedure AddRecord krijgt een optionele parameter “sCreatedByField”.

Als die ingevuld is, wordt dat veld gebruikt om de gebruikersnaam in te bewaren; ‘User.Name’ kan je in Gambas altijd gebruiken en geeft de loginnaam van de gebruiker die het programma draait. Hier wordt die ingevuld vanuit AddRecord, zodat er van het oproepend programma niet aan gedacht moet worden, of ook de waarde niet vergeten of verkeerd ingevuld kan worden; zelfs als de update nadien niet werkt heb je al meta-informatie.

Als geen veldnaam wordt doorgegeven om de createdby informatie in op te slaan, wordt enkel de record_id ingevuld.

Upd: Ps: misschien gebruik ik ook beter geen tabelnaam-PREFIX in de veldnamen … (http://gambas.copyleft.be/blog/archives/1453)

Gambas script als shell script

Ben je zodanig aan Gambas verslingerd dat je een shell script liefst in Gambas schrijft?

Eenvoudig script

Het eenvoudigste voorbeeld is altijd de “Hello World”; maak een tekstbestand helloGambas.sh in ~/bin met als inhoud:

#!/usr/bin/gbs2
Public Sub Main()
   Print "Hello Gambas World v. " & System.Version
End

De eerste lijn geeft aan waarmee dit script moet uitgevoerd worden. Daarvoor kijk je waar gambas staat, bv met “which gbs2”; het antwoord op OpenSuse: /usr/bin/gbs2, elders bv /usr/local/bin/gbs2, enz.

Als je met Gambas versie 3 werkt is het :

#!/usr/bin/gbs3
Public Sub Main()
   Print "Hello Gambas World v. " & System.Version
End

Pas ook hier de eerste lijn aan aan je eigen systeem.

Maak het script uitvoerbaar
chmod +x helloGambas.sh
En start het van de commandolijn met de naam: ./helloGambas.sh

De uitvoer moet natuurlijk

Hello Gambas World v. 2

of

Hello Gambas World v. 3

zijn.

Nu heb je een script dat je kan starten vanop de commandolijn, net zoals je andere shell scripts.

Programma in plaats van script

Als je een veel groter/uitgebreider programma wil laten draaien, kan dat door een nieuw project te openen, kies bij Project Type voor “Command Line Application”.

Dan krijg je geen FMain, dus geen venster dat geopend wordt bij het starten van het programma.
Je krijgt wel een MMain als startende module, en je kan klassen bijmaken enz.

Andere opties mag je wel aankruisen, zoals “settings file managament” en “database access”.

Het uiteindelijke programma compileer je tot mijnProgramma.gambas, en je maakt het uitvoerbaar als het dat nog niet zou zijn.

Je kan dat programma dan aanroepen vanin een shell script, bv:
/home/username/bin/runTest.sh
met als inhoud:
/home/username/uitvoerbaar/mijnProgramma.gambas

In het script kan je ervoor of erna een touch doen naar een bestand om te checken of het script gelopen heeft:


touch /home/username/startedScript.txt
/home/username/uitvoerbaar/mijnProgramma.gambas

Als je vanuit dit shell script je gambas programma kan starten, kan je runTest.sh opnemen in de cron jobs: uitvoeren vanuit de cron jobs,.

Verdere interessante mogelijkheden zijn: een script laten uitvoeren als CGI script in een webserver, …

Ontbrekende pdf-component in Gambas2 project

Bij het overbrengen van een project in de vorm van een source-code archief, kreeg ik na het uitpakken en compileren vanuit de IDE een foutmelding over een ontbrekende pdf-component (het te installeren programma maakt prints).

In mijn installatie op de doel-pc (uit OpenSUSE Education, Gambas 2.24.0-2.16 ) komt die pdf niet voor, maar ik heb een identiek systeem, waarop ik ontwikkel, en ze duidelijk wel aanwezig zijn. Mogelijk is er een iets andere versie van Gambas, of nog waarschijnlijker, een andere repository gebruikt bij installatie van Gambas.

In mijn geval heb ik de betreffende bestanden manueel naar het andere systeem gekopieerd:

gb.pdf.component
gb.pdf.la
gb.pdf.so (link)
gb.pdf.so.0
gb.pdf.so.0.0.0

Ze zijn terug te vinden in /usr/lib64/gambas2

Geen “mooie” oplossing, maar daarna werkte het programma wel normaal.

Gambas2 Runtime op OpenSUSE 11.4

Upd dec. 2015: op dit moment krijg ik op een nieuwe installatie van opensuse 11.4 + evergreen geen gambas2 meer geinstalleerd. Misschien lukt het nog met bestanden kopieren van een ander werkende 11.4 systeem…

Appliance: enkel runtime
Situatie: Oude hardware (Aspire One ZG5) kan toegewezen worden aan één bepaalde toepassing (combinatie van toepassingen voor eenzelfde doel), en moet niet algemeen als desktop pc onderhouden worden (geen browser updates nodig enz).
Daarvoor doen we een “nieuwe” OpenSUSE 11.4 installatie met alleen de Gambas runtime, en dus niet de hele programmeeromgeving (IDE); zie voor installatie volledige Gambas2 IDE hier).

Softwarebron
http://software.opensuse.org/package/gambas2, dan onder “unsupported distributions” openen, en dan
KDE:KDE3 – 2.24.0 32 Bit
En bevestigen; er begint een download die redelijk wat extra paketten ook afhaalt.
Nadien is de gambas runtime geïnstalleerd:

gambas2 – Runtime Environment for Gambas

/usr/bin/gambas2
/usr/bin/gambas2-database-manager.gambas
/usr/bin/gambas2.gambas

3 files total

“gambas runtime”
Volgende vraag: hoe gebruiken? Ik heb de runtime geïnstalleerd en ik heb een programma dat in de gambas IDE (op een andere computer) gecompileerd werd tot een .gambas bestand.
Bij pogingen het programma te draaien krijg ik altijd foutmeldingen, bv

/usr/bin/env: gbr2: No such file or directory

In /usr/bin staan uitvoerbare programma’s; gbr en gbx bestaan niet hier. gbr is een link naar gbx (zag ik op een systeem met de hele Gambas2 IDE). Maar zelfs als ze even geleend worden van het andere systeem werkt het hier niet mee; er komen weer andere fouten als gb.gui not found, maar die vind ik op het andere systeem ook niet als file of in de repo.

Ik doe nog eens het ommetje langs de opensuse website en kies nog eens de install van de 32bit versie uit de KDE3 repository:
http://software.opensuse.org/package/gambas2
En na wachtwoord vraag begint packagekit weer iets te installeren. Een hele lijst zelfs, waarin ik zie voorbijkomen:
waarin ook gambas2, en verder: samba, gimp-help, libreoffice converter en extentions, enz… om te eindigen in “File was installed successfully”.
Maar ik zie verder niet veel verschil, behalve dat mijn harddisk nu voor 4.4 Gb vol is ipv 3.9.

KDE3 bron
Ik voeg nog de KDE3 repository toe, manueel als URL, want de community optie werkt niet in mijn huidige 11.4:
http://download.opensuse.org/repositories/KDE:/KDE3/openSUSE_11.4/

Daarna is er veel meer Gambas2 in de lijst van Yast/Software management (zoek: gambas).
Ik zie alle afzonderlijke componenten, en kies de gambas2-gb-gui alleen uit. Die vereist dan nog een paar extra componenten, zoals de “runtime”- die zal daarmee vervangen worden veronderstel ik.

Nadien: ruimtegebruik: 4.5 Gb

Ik mis nu gb.form, die er in het package management uitziet als:

gambas2-gb-form – The control component for both GTK+ and qt

(Naam moet je weten als je zypper wil gebruiken). Installeer.
zypper install gambas2-gb-form

Zelfde voor:
gb.db: zypper install gambas2-gb-db
gb.db.form: zypper install gambas2-gb-db-form
gb.settings: zypper install gambas2-gb-settings
gb.qt:zypper install gambas2-gb-qt

Dit zijn er een paar meer:

Loading repository data…
Warning: Repository ‘openSUSE-11.4-Update’ appears to outdated. Consider using a different mirror or server.
Reading installed packages…
Resolving package dependencies…

The following NEW packages are going to be installed:
gambas2-gb-qt kdelibs3-default-style qt3

The following recommended package was automatically selected:
kdelibs3-default-style

3 new packages to install.
Overall download size: 3.1 MiB. After the operation, additional 10.2 MiB will be used.
Continue? [y/n/?] (y):
Retrieving package qt3-3.3.8c-219.1.i586 (1/3), 2.8 MiB (9.1 MiB unpacked)
Retrieving: qt3-3.3.8c-219.1.i586.rpm [done (377.9 KiB/s)]
Retrieving package kdelibs3-default-style-3.5.10-232.1.i586 (2/3), 128.0 KiB (381.0 KiB unpacked)
Retrieving: kdelibs3-default-style-3.5.10-232.1.i586.rpm [done (0 B/s)]
Retrieving package gambas2-gb-qt-2.24.0-22.1.i586 (3/3), 190.0 KiB (696.0 KiB unpacked)
Retrieving: gambas2-gb-qt-2.24.0-22.1.i586.rpm [done]
Installing: qt3-3.3.8c-219.1 [done]
Installing: kdelibs3-default-style-3.5.10-232.1 [done]
Installing: gambas2-gb-qt-2.24.0-22.1 [done]

Run
Maar daarna draait de applicatie perfect! En zonder de Gambas2-IDE.
Het .gambas bestand is uitvoerbaar gemaakt (chmod +x).
Voor alle .gambas programma’s een Gb2Run directory gemaakt in mijn home map, en daar gestart:
~/Gb2Run> ./mijnprogramma.gambas
Eens de meestgebruikte componenten geïnstalleerd, zijn toekomstige programma’s minder omslachtig te installeren, tenzij ze weer een nieuwe component nodig hebben.
Dit soort afhankelijkheden wordt waarschijnlijk opgevangen als je vanuit Gambas installatie-packages maakt.

Gambas2 op OpenSUSE 13.1: meer dan de runtime?!

Het lijkt erop dat Gambas2 stilaan en onvermijdelijk Einde Loopbaan is. In de huidige installatie van OpenSUSE 13.1 komt bv alleen nog de runtime voor van Gambas2, tenminste als je de community repositories/Educational geïnstalleerd hebt. (bronnen van de gemeenschap)
Gambas 2.24.0 is installeerbaar van de One Click install
Ik ging specifiek op zoek naar de gambas2 IDE en vond die ook:
http://software.opensuse.org/package/gambas2-ide:

Als u doorgaat zullen de volgende wijzigingen worden aangebracht aan uw systeem:
Toe te voegen installatiebronnen:
http://download.opensuse.org/distribution/13.1/repo/non-oss/ (openSUSE:13.1:NonFree)
http://download.opensuse.org/distribution/13.1/repo/oss/ (openSUSE:13.1)
http://download.opensuse.org/repositories/Education/openSUSE_13.1/ (Education)
http://download.opensuse.org/repositories/devel:/languages:/perl/openSUSE_13.1/ (devel:languages:perl)
http://download.opensuse.org/repositories/devel:/languages:/python/openSUSE_13.1/ (devel:languages:python)

Te installeren software:
gambas2-ide

Gambas2 programmeeromgeving duikt op in het klassiek KDE menu recent geïnstalleerd.