Gordijn: Een HSplit om twee GridViews te schalen zoals in een spreadsheet

Doel:
Het scherm is in twee verdeeld: links en rechts een rooster met gegevens, ongeveer er uitziend als een rekenblad/spreadsheet.

De gegevens aan de linkse kant wil je altijd zien omdat ze vaste titels en gegevens van de rij bevatten, bv de naam van een persoon (naam, voornaam, geb.datum, in dienst datum), waarvan in de volgende kolommen gegevens te zien zijn, bv aanwezigheden in een maand.

Van het linkse rooster is de eerste kolom meestal genoeg, de andere gegevens zijn “verborgen” achter de data van het rechtse rooster. Maar af en toe wil je toch de andere gegevens raadplegen, bv even naar de geboortedatum kijken, en wil je het rooster wat breder maken. Het lijkt alsof je een gordijn opzijschuift.

Er zijn meer kolommen met gegevens dan het scherm breed is, dus het rechtse rooster kan horizontaal scrollen. Er zijn ook meer rijen dan het scherm kan weergeven, dus beide roosters scrollen ook vertikaal.

Je hebt dus twee gridviews nodig: GridView1 links en GridView2 rechts.
Met de HSplit kan je horizontaal een “schuiver” krijgen om twee elementen met een middengrip groter/kleiner te maken, horizontaal in dit geval. Maar om dat te kunnen is er een “hoger” element nodig, dat de twee gridviews omvat, en van waaruit de Split kan werken, hier een HBox.

Gebruik van HSplit met GridViews

In de IDE rechts bij eigenschappen (properties), tabblad “hierarchy” krijg je dan deze structuur (zie afbeelding).

Het vervelende is dat de twee grids hun eigen scrolbars hebben, en niet alleen horizontaal maar ook vertikaal afzonderlijk scrollen. Dan klopt de horizontale lijn van de gegevens niet meer.

Daar kan je wel manueel en mouw aan passen; bv het weergeven van log gegevens, linkse grid de titel of naam van een logitem, rechtse grid de gegevens of data die gelogd en weergegeven worden.

Als je in het linkse “names” grid naar beneden scrolt moet het rechtse data-grid meescrollen:

PUBLIC SUB grvwLogNames_Scroll()

  grvwLogData.ScrollY = grvwLogNames.ScrollY

END

En omgekeeerd ook natuurlijk; als je in de data scrolt moeten de namen meescrollen:

PUBLIC SUB grvwLogData_Scroll()

  grvwLogDataNames.ScrollY = grvwLogData.ScrollY

END

Bovendien is het handig dat een klik op het rechtse grid ook “werkt”, dwz eigenlijk hetzelfde doet als een klik op het linkse grid.

PUBLIC SUB grvwLogData_Click()

  grvwLogNames.Row = grvwLogData.Row
  grvwLogNames_Click

END

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

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

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)

Foxpro timestamp data leesbaar maken

Een uit Foxpro ingevoerde tabel bevat een kolom met “timestamps”; het is een getal dat in Foxpro gebruikt wordt om te kijken in welke volgorde de records gemaakt (of gemanipuleerd) werden; een vergelijking tussen de getallen levert een aantal seconden verschil op. Hoe dit getal bruikbaar maken, bv door het naar een leesbare datum om te zetten?

Bv: het getal : 487768695 zou op het moment van bewaren het het aantal seconden voorstellen dat verstreken is sinds Foxpro’s referentietijd, een soort seconde nul in het begin van 1980.

Seconden naar minuten -> uren -> dagen: getal / (60 x 60 x 24)

Hier komen de Visual Basic Compatibility functies goed van pas. Je moet dan eerst bij Project, Properties, tab Components gb.vb aankruisen!

De component gb.vb bevat maar een paar functies, niet toevallig met datumfuncties, en meer bepaald om tijd bij te tellen of af te trekken van een datum:

DateAdd DateDiff Left Mid Right Round Str Val

DateAdd vereist de aard van wat erbij geteld wordt (dag), bij te tellen getal, begindatum:

vb.DateAdd("d", Round(db.fldTimestamp / (3600 * 24), 0), Date(1980, 1,1)

Ik probeerde het eerst met seconden maar daar moet ik iets gemist hebben, want dat gaf niet het juiste resultaat:

txlbUpdated.Text=Str$(vb.DateAdd("s", db.fldTimestamp, Date(1980, 1,1))

om weer te geven op het scherm in een programma.